Use the FS store as default store
parent
aa14ea7ac4
commit
118829617f
|
@ -0,0 +1,180 @@
|
|||
define([
|
||||
'/api/config?cb=' + Math.random().toString().slice(2),
|
||||
'/customize/messages.js?app=fs',
|
||||
'/bower_components/chainpad-listmap/chainpad-listmap.js',
|
||||
'/bower_components/chainpad-crypto/crypto.js',
|
||||
'/bower_components/textpatcher/TextPatcher.amd.js',
|
||||
'/file/fileObject.js'
|
||||
], function (Config, Messages, Listmap, Crypto, TextPatcher, FO) {
|
||||
/*
|
||||
This module uses localStorage, which is synchronous, but exposes an
|
||||
asyncronous API. This is so that we can substitute other storage
|
||||
methods.
|
||||
|
||||
To override these methods, create another file at:
|
||||
/customize/storage.js
|
||||
*/
|
||||
|
||||
var Store = {};
|
||||
var storeObj;
|
||||
var ready = false;
|
||||
var filesOp;
|
||||
|
||||
var safeSet = function (key, val) {
|
||||
storeObj[key] = val;
|
||||
};
|
||||
|
||||
// Store uses nodebacks...
|
||||
Store.set = function (key, val, cb) {
|
||||
safeSet(key, val);
|
||||
cb();
|
||||
};
|
||||
|
||||
// implement in alternative store
|
||||
Store.setBatch = function (map, cb) {
|
||||
Object.keys(map).forEach(function (key) {
|
||||
safeSet(key, val);
|
||||
});
|
||||
cb(void 0, map);
|
||||
};
|
||||
|
||||
var safeGet = window.safeGet = function (key) {
|
||||
return storeObj[key];
|
||||
};
|
||||
|
||||
Store.get = function (key, cb) {
|
||||
cb(void 0, safeGet(key));
|
||||
};
|
||||
|
||||
// implement in alternative store
|
||||
Store.getBatch = function (keys, cb) {
|
||||
var res = {};
|
||||
keys.forEach(function (key) {
|
||||
res[key] = safeGet(key);
|
||||
});
|
||||
cb(void 0, res);
|
||||
};
|
||||
|
||||
var safeRemove = function (key) {
|
||||
delete storeObj[key];
|
||||
};
|
||||
|
||||
Store.remove = function (key, cb) {
|
||||
safeRemove(key);
|
||||
cb();
|
||||
};
|
||||
|
||||
// implement in alternative store
|
||||
Store.removeBatch = function (keys, cb) {
|
||||
keys.forEach(function (key) {
|
||||
safeRemove(key);
|
||||
});
|
||||
cb();
|
||||
};
|
||||
|
||||
Store.keys = function (cb) {
|
||||
cb(void 0, Object.keys(storeObj));
|
||||
};
|
||||
|
||||
Store.addPad = function (href, data) {
|
||||
filesOp.addPad(href, data);
|
||||
};
|
||||
|
||||
Store.forgetPad = function (href, cb) {
|
||||
filesOp.forgetPad(href);
|
||||
cb();
|
||||
};
|
||||
|
||||
var changeHandlers = Store.changeHandlers = [];
|
||||
|
||||
Store.change = function (f) {
|
||||
if (typeof(f) !== 'function') {
|
||||
throw new Error('[Store.change] callback must be a function');
|
||||
}
|
||||
changeHandlers.push(f);
|
||||
|
||||
if (changeHandlers.length === 1) {
|
||||
// start listening for changes
|
||||
/* TODO: listen for changes in the proxy
|
||||
window.addEventListener('storage', function (e) {
|
||||
changeHandlers.forEach(function (f) {
|
||||
f({
|
||||
key: e.key,
|
||||
oldValue: e.oldValue,
|
||||
newValue: e.newValue,
|
||||
});
|
||||
});
|
||||
});
|
||||
*/
|
||||
}
|
||||
};
|
||||
|
||||
var onReady = function (f, proxy, storageKey) {
|
||||
filesOp = FO.init(proxy, {
|
||||
storageKey: storageKey
|
||||
});
|
||||
storeObj = proxy;
|
||||
ready = true;
|
||||
if (typeof(f) === 'function') {
|
||||
f(void 0, Store);
|
||||
}
|
||||
};
|
||||
|
||||
var init = function (f, Cryptpad) {
|
||||
if (!Cryptpad) { return; }
|
||||
var hash = localStorage.FS_hash;
|
||||
var secret = Cryptpad.getSecrets(hash);
|
||||
var listmapConfig = {
|
||||
data: {},
|
||||
websocketURL: Cryptpad.getWebsocketURL(),
|
||||
channel: secret.channel,
|
||||
readOnly: false,
|
||||
validateKey: secret.keys.validateKey || undefined,
|
||||
crypto: Crypto.createEncryptor(secret.keys),
|
||||
};
|
||||
|
||||
var rt = window.rt = Listmap.create(listmapConfig);
|
||||
rt.proxy.on('create', function (info) {
|
||||
var realtime = info.realtime;
|
||||
localStorage.FS_hash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys);
|
||||
window.patchText = TextPatcher.create({
|
||||
realtime: realtime,
|
||||
logging: true,
|
||||
});
|
||||
|
||||
}).on('ready', function () {
|
||||
if (JSON.stringify(rt.proxy) === '{}') {
|
||||
var oldStore = Cryptpad.getStore(true);
|
||||
oldStore.get(Cryptpad.storageKey, function (err, s) {
|
||||
rt.proxy.filesData = s;
|
||||
onReady(f, rt.proxy, Cryptpad.storageKey);
|
||||
});
|
||||
return;
|
||||
}
|
||||
onReady(f, rt.proxy, Cryptpad.storageKey);
|
||||
})
|
||||
.on('disconnect', function () {
|
||||
//setEditable(false);
|
||||
Cryptpad.alert(Messages.common_connectionLost);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
Store.ready = function (f, Cryptpad) {
|
||||
if (Cryptpad.parsePadUrl(window.location.href).type === "file") {
|
||||
if (typeof(f) === 'function') {
|
||||
f(void 0, Cryptpad.getStore(true));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (ready) {
|
||||
if (typeof(f) === 'function') {
|
||||
f(void 0, Store);
|
||||
}
|
||||
} else {
|
||||
init(f, Cryptpad);
|
||||
}
|
||||
};
|
||||
|
||||
return Store;
|
||||
});
|
|
@ -71,6 +71,12 @@ define(function () {
|
|||
}
|
||||
};
|
||||
|
||||
Store.addPad = function () {};
|
||||
|
||||
Store.forgetPad = function (href, cb) {
|
||||
|
||||
};
|
||||
|
||||
var changeHandlers = Store.changeHandlers = [];
|
||||
|
||||
Store.change = function (f) {
|
||||
|
|
|
@ -7,10 +7,11 @@ define([
|
|||
'/bower_components/spin.js/spin.min.js',
|
||||
'/common/clipboard.js',
|
||||
|
||||
'/customize/fsStore.js',
|
||||
'/customize/user.js',
|
||||
|
||||
'/bower_components/jquery/dist/jquery.min.js',
|
||||
], function (Config, Messages, Store, Crypto, Alertify, Spinner, Clipboard, User) {
|
||||
], function (Config, Messages, Store, Crypto, Alertify, Spinner, Clipboard, FS, User) {
|
||||
/* This file exposes functionality which is specific to Cryptpad, but not to
|
||||
any particular pad type. This includes functions for committing metadata
|
||||
about pads to your local storage for future use and improved usability.
|
||||
|
@ -23,6 +24,7 @@ define([
|
|||
User: User,
|
||||
};
|
||||
var store;
|
||||
var fsStore;
|
||||
var userProxy;
|
||||
var userStore;
|
||||
|
||||
|
@ -34,7 +36,8 @@ define([
|
|||
|
||||
var getStore = common.getStore = function (legacy) {
|
||||
if (!legacy && userStore) { return userStore; }
|
||||
if (store) { return store; }
|
||||
if (legacy) { return store; }
|
||||
if (!legacy && fsStore) { return fsStore; }
|
||||
throw new Error("Store is not ready!");
|
||||
};
|
||||
|
||||
|
@ -94,7 +97,6 @@ define([
|
|||
store = Store;
|
||||
});
|
||||
|
||||
|
||||
var isArray = function (o) { return Object.prototype.toString.call(o) === '[object Array]'; };
|
||||
|
||||
var fixHTML = common.fixHTML = function (html) {
|
||||
|
@ -163,13 +165,13 @@ define([
|
|||
};
|
||||
var getHashFromKeys = common.getHashFromKeys = getEditHashFromKeys;
|
||||
|
||||
var getSecrets = common.getSecrets = function () {
|
||||
var getSecrets = common.getSecrets = function (secretHash) {
|
||||
var secret = {};
|
||||
if (!/#/.test(window.location.href)) {
|
||||
if (!secretHash && !/#/.test(window.location.href)) {
|
||||
secret.keys = Crypto.createEditCryptor();
|
||||
secret.key = Crypto.createEditCryptor().editKeyStr;
|
||||
} else {
|
||||
var hash = window.location.hash.slice(1);
|
||||
var hash = secretHash || window.location.hash.slice(1);
|
||||
if (hash.length === 0) {
|
||||
secret.keys = Crypto.createEditCryptor();
|
||||
secret.key = Crypto.createEditCryptor().editKeyStr;
|
||||
|
@ -380,40 +382,31 @@ define([
|
|||
var forgetPad = common.forgetPad = function (href, cb, legacy) {
|
||||
var parsed = parsePadUrl(href);
|
||||
|
||||
getRecentPads(function (err, recentPads) {
|
||||
setRecentPads(recentPads.filter(function (pad) {
|
||||
var p = parsePadUrl(pad.href);
|
||||
// find duplicates
|
||||
if (parsed.hash === p.hash && parsed.type === p.type) {
|
||||
console.log("Found a duplicate");
|
||||
return;
|
||||
}
|
||||
return true;
|
||||
}), function (err, data) {
|
||||
if (err) {
|
||||
cb(err);
|
||||
return;
|
||||
}
|
||||
var callback = function (err, data) {
|
||||
if (err) {
|
||||
cb(err);
|
||||
return;
|
||||
}
|
||||
|
||||
getStore(legacy).keys(function (err, keys) {
|
||||
if (err) {
|
||||
cb(err);
|
||||
return;
|
||||
}
|
||||
var toRemove = keys.filter(function (k) {
|
||||
return k.indexOf(parsed.hash) === 0;
|
||||
});
|
||||
|
||||
if (!toRemove.length) {
|
||||
cb();
|
||||
return;
|
||||
}
|
||||
getStore(legacy).removeBatch(toRemove, function (err, data) {
|
||||
cb(err, data);
|
||||
});
|
||||
getStore(legacy).keys(function (err, keys) {
|
||||
var toRemove = keys.filter(function (k) {
|
||||
return k.indexOf(parsed.hash) === 0;
|
||||
});
|
||||
}, legacy);
|
||||
}, legacy);
|
||||
|
||||
if (!toRemove.length) {
|
||||
cb();
|
||||
return;
|
||||
}
|
||||
getStore(legacy).removeBatch(toRemove, function (err, data) {
|
||||
cb(err, data);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
if (typeof(getStore(legacy).forgetPad) === "function") {
|
||||
// TODO implement forgetPad in store.js
|
||||
getStore(legacy).forgetPad(href, callback);
|
||||
}
|
||||
};
|
||||
|
||||
// STORAGE
|
||||
|
@ -462,7 +455,12 @@ define([
|
|||
});
|
||||
|
||||
if (!contains) {
|
||||
renamed.push(makePad(href, name));
|
||||
var data = makePad(href, name);
|
||||
renamed.push(data);
|
||||
if (typeof(getStore(legacy).addPad) === "function") {
|
||||
//TODO implement addPad in store.js
|
||||
getStore().addPad(href);
|
||||
}
|
||||
}
|
||||
|
||||
setRecentPads(renamed, function (err, data) {
|
||||
|
@ -535,8 +533,8 @@ define([
|
|||
f(void 0, env);
|
||||
};
|
||||
|
||||
Store.ready(function (err, store) {
|
||||
common.store = env.store = store;
|
||||
FS.ready(function (err, store) {
|
||||
fsStore = common.store = env.store = store;
|
||||
|
||||
$(function() {
|
||||
// Race condition : if document.body is undefined when alertify.js is loaded, Alertify
|
||||
|
@ -597,7 +595,7 @@ define([
|
|||
cb();
|
||||
|
||||
}); */
|
||||
});
|
||||
}, common);
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -54,10 +54,12 @@ li {
|
|||
border: 1px dotted #bbb;
|
||||
background: #666;
|
||||
color: #eee;
|
||||
margin: -1px;
|
||||
}
|
||||
|
||||
/* TREE */
|
||||
|
||||
|
||||
#tree {
|
||||
border: 2px solid blue;
|
||||
box-sizing: border-box;
|
||||
|
@ -194,6 +196,10 @@ li {
|
|||
flex: 1;
|
||||
}
|
||||
|
||||
#content li * {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#content li:hover:not(.header) .name {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ define([
|
|||
var NEW_FOLDER_NAME = Messages.fm_newFolder;
|
||||
|
||||
var init = module.init = function (files, config) {
|
||||
FILES_DATA = config.storageKey;
|
||||
var DEBUG = config.DEBUG || false;
|
||||
var logging = console.log;
|
||||
var log = config.log || logging;
|
||||
|
@ -192,6 +193,16 @@ define([
|
|||
return ret;
|
||||
};
|
||||
|
||||
var getFilesDataFiles = function () {
|
||||
var ret = [];
|
||||
for (var el in files[FILES_DATA]) {
|
||||
if (el.href && ret.indexOf(el.href) === -1) {
|
||||
ret.push(el.href);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
var removeFileFromRoot = function (root, href) {
|
||||
if (isFile(root)) { return; }
|
||||
for (var e in root) {
|
||||
|
@ -536,18 +547,39 @@ define([
|
|||
pushToTrash(key, href, [UNSORTED]);
|
||||
};
|
||||
|
||||
var addPad = exp.addPad = function (href, data) {
|
||||
if (!getFileData(href)) {
|
||||
files[FILES_DATA].push(data);
|
||||
}
|
||||
var addUnsortedPad = exp.addPad = function (href) {
|
||||
var unsortedFiles = getUnsortedFiles().slice();
|
||||
var rootFiles = getRootFiles().slice();
|
||||
//var trashFiles = getTrashFiles().slice();
|
||||
if (unsortedFiles.indexOf(href) === -1 && rootFiles.indexOf(href) === -1) {
|
||||
var trashFiles = getTrashFiles().slice();
|
||||
if (unsortedFiles.indexOf(href) === -1 && rootFiles.indexOf(href) === -1 && trashFiles.indexOf(href) === -1) {
|
||||
files[UNSORTED].push(href);
|
||||
}
|
||||
};
|
||||
|
||||
var checkNewPads = exp.checkNewPads = function () {
|
||||
var fd = files[FILES_DATA];
|
||||
var rootFiles = getRootFiles().slice();
|
||||
var unsortedFiles = getUnsortedFiles().slice();
|
||||
var trashFiles = getTrashFiles().slice();
|
||||
fd.forEach(function (el, idx) {
|
||||
if (!el.href) { return; }
|
||||
if (rootFiles.indexOf(el.href) === -1
|
||||
&& unsortedFiles.indexOf(el.href) === -1
|
||||
&& trashFiles.indexOf(el.href) === -1) {
|
||||
debug("An element in filesData was not in ROOT, UNSORTED or TRASH.", el);
|
||||
files[UNSORTED].push(el.href);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var checkRemovedPads = exp.checkRemovedPads = function () {
|
||||
var fd = files[FILES_DATA];
|
||||
var rootFiles = getRootFiles().slice();
|
||||
var unsortedFiles = getUnsortedFiles().slice();
|
||||
var trashFiles = getTrashFiles().slice();
|
||||
|
||||
};
|
||||
|
||||
var fixFiles = exp.fixFiles = function () {
|
||||
// Explore the tree and check that everything is correct:
|
||||
// * 'root', 'trash' and 'filesData' exist and are objects
|
||||
|
|
|
@ -21,17 +21,13 @@ define([
|
|||
|
||||
//var hash = Cryptpad.getAttribute('FS_hash', cb);
|
||||
var hash = localStorage.FS_hash;
|
||||
if (hash) {
|
||||
window.location.hash = hash;
|
||||
}
|
||||
|
||||
var secret = Cryptpad.getSecrets();
|
||||
var secret = Cryptpad.getSecrets(hash);
|
||||
|
||||
var ROOT = "root";
|
||||
var ROOT_NAME = Messages.fm_rootName;
|
||||
var UNSORTED = "unsorted";
|
||||
var UNSORTED_NAME = Messages.fm_unsortedName;
|
||||
var FILES_DATA = "filesData";
|
||||
var FILES_DATA = Cryptpad.storageKey;
|
||||
var FILES_DATA_NAME = Messages.fm_filesDataName;
|
||||
var TRASH = "trash";
|
||||
var TRASH_NAME = Messages.fm_trashName;
|
||||
|
@ -44,6 +40,7 @@ define([
|
|||
var NEW_FOLDER_NAME = Messages.fm_newFolder;
|
||||
|
||||
var config = {};
|
||||
config.storageKey = FILES_DATA;
|
||||
var DEBUG = config.DEBUG = true;
|
||||
var debug = config.debug = DEBUG ? console.log : function() {return;};
|
||||
var logError = config.logError = console.error;
|
||||
|
@ -55,7 +52,7 @@ define([
|
|||
}
|
||||
};
|
||||
|
||||
var filesObject = module.files = {
|
||||
var filesObject = {
|
||||
root: {
|
||||
"Directory 1": {
|
||||
"Dir A": {
|
||||
|
@ -213,7 +210,7 @@ define([
|
|||
localStorage[LOCALSTORAGE_LAST] = JSON.stringify(path);
|
||||
};
|
||||
|
||||
var initLSOpened = function () {
|
||||
var initLocalStorage = function () {
|
||||
try {
|
||||
var store = JSON.parse(localStorage[LOCALSTORAGE_OPENED]);
|
||||
if (!$.isArray(store)) {
|
||||
|
@ -562,14 +559,13 @@ define([
|
|||
var addDragAndDropHandlers = function ($element, path, isFolder, droppable) {
|
||||
// "dragenter" is fired for an element and all its children
|
||||
// "dragleave" may be fired when entering a child
|
||||
// --> we use pointer-events: none in CSS, but we still need a counter to avoid some issues
|
||||
// --> We store the number of enter/leave and the element entered and we remove the
|
||||
// highlighting only when we have left everything
|
||||
var counter = 0;
|
||||
var dragenterList = [];
|
||||
$element.on('dragstart', function (e) {
|
||||
e.stopPropagation();
|
||||
counter = 0;
|
||||
dragenterList = [];
|
||||
onDrag(e.originalEvent, path);
|
||||
});
|
||||
|
||||
|
@ -585,18 +581,15 @@ define([
|
|||
$element.on('dragenter', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (dragenterList.indexOf(e.target) !== -1) { return; }
|
||||
dragenterList.push(e.target);
|
||||
counter++;
|
||||
$element.addClass('droppable');
|
||||
});
|
||||
$element.on('dragleave', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
var idx = dragenterList.indexOf(e.target);
|
||||
dragenterList.splice(idx, 1);
|
||||
counter--;
|
||||
if (counter <= 0) {
|
||||
counter = 0;
|
||||
$element.removeClass('droppable');
|
||||
}
|
||||
});
|
||||
|
@ -1283,7 +1276,6 @@ define([
|
|||
var realtime = module.realtime = info.realtime;
|
||||
|
||||
var editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys);
|
||||
window.location.hash = editHash;
|
||||
//Cryptpad.setAttribute("FS_hash", editHash, cb, store);
|
||||
localStorage.FS_hash = editHash;
|
||||
|
||||
|
@ -1303,16 +1295,17 @@ define([
|
|||
});
|
||||
});*/
|
||||
}).on('ready', function () {
|
||||
module.files = rt.proxy;
|
||||
if (JSON.stringify(rt.proxy) === '{}') {
|
||||
var store = Cryptpad.getStore();
|
||||
var store = Cryptpad.getStore(true);
|
||||
store.get(Cryptpad.storageKey, function (err, s) {
|
||||
rt.proxy.filesData = s;
|
||||
initLSOpened();
|
||||
rt.proxy[FILES_DATA] = s;
|
||||
initLocalStorage();
|
||||
init(rt.proxy);
|
||||
});
|
||||
return;
|
||||
}
|
||||
initLSOpened();
|
||||
initLocalStorage();
|
||||
init(rt.proxy);
|
||||
})
|
||||
.on('disconnect', function () {
|
||||
|
|
Loading…
Reference in New Issue