Use the FS store as default store

pull/1/head
yflory 8 years ago
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 = []; var changeHandlers = Store.changeHandlers = [];
Store.change = function (f) { Store.change = function (f) {

@ -7,10 +7,11 @@ define([
'/bower_components/spin.js/spin.min.js', '/bower_components/spin.js/spin.min.js',
'/common/clipboard.js', '/common/clipboard.js',
'/customize/fsStore.js',
'/customize/user.js', '/customize/user.js',
'/bower_components/jquery/dist/jquery.min.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 /* This file exposes functionality which is specific to Cryptpad, but not to
any particular pad type. This includes functions for committing metadata any particular pad type. This includes functions for committing metadata
about pads to your local storage for future use and improved usability. about pads to your local storage for future use and improved usability.
@ -23,6 +24,7 @@ define([
User: User, User: User,
}; };
var store; var store;
var fsStore;
var userProxy; var userProxy;
var userStore; var userStore;
@ -34,7 +36,8 @@ define([
var getStore = common.getStore = function (legacy) { var getStore = common.getStore = function (legacy) {
if (!legacy && userStore) { return userStore; } 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!"); throw new Error("Store is not ready!");
}; };
@ -94,7 +97,6 @@ define([
store = Store; store = Store;
}); });
var isArray = function (o) { return Object.prototype.toString.call(o) === '[object Array]'; }; var isArray = function (o) { return Object.prototype.toString.call(o) === '[object Array]'; };
var fixHTML = common.fixHTML = function (html) { var fixHTML = common.fixHTML = function (html) {
@ -163,13 +165,13 @@ define([
}; };
var getHashFromKeys = common.getHashFromKeys = getEditHashFromKeys; var getHashFromKeys = common.getHashFromKeys = getEditHashFromKeys;
var getSecrets = common.getSecrets = function () { var getSecrets = common.getSecrets = function (secretHash) {
var secret = {}; var secret = {};
if (!/#/.test(window.location.href)) { if (!secretHash && !/#/.test(window.location.href)) {
secret.keys = Crypto.createEditCryptor(); secret.keys = Crypto.createEditCryptor();
secret.key = Crypto.createEditCryptor().editKeyStr; secret.key = Crypto.createEditCryptor().editKeyStr;
} else { } else {
var hash = window.location.hash.slice(1); var hash = secretHash || window.location.hash.slice(1);
if (hash.length === 0) { if (hash.length === 0) {
secret.keys = Crypto.createEditCryptor(); secret.keys = Crypto.createEditCryptor();
secret.key = Crypto.createEditCryptor().editKeyStr; secret.key = Crypto.createEditCryptor().editKeyStr;
@ -380,40 +382,31 @@ define([
var forgetPad = common.forgetPad = function (href, cb, legacy) { var forgetPad = common.forgetPad = function (href, cb, legacy) {
var parsed = parsePadUrl(href); var parsed = parsePadUrl(href);
getRecentPads(function (err, recentPads) { var callback = function (err, data) {
setRecentPads(recentPads.filter(function (pad) { if (err) {
var p = parsePadUrl(pad.href); cb(err);
// find duplicates return;
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;
}
getStore(legacy).keys(function (err, keys) { getStore(legacy).keys(function (err, keys) {
if (err) { var toRemove = keys.filter(function (k) {
cb(err); return k.indexOf(parsed.hash) === 0;
return; });
}
var toRemove = keys.filter(function (k) {
return k.indexOf(parsed.hash) === 0;
});
if (!toRemove.length) { if (!toRemove.length) {
cb(); cb();
return; return;
} }
getStore(legacy).removeBatch(toRemove, function (err, data) { getStore(legacy).removeBatch(toRemove, function (err, data) {
cb(err, data); cb(err, data);
});
}); });
}, legacy); });
}, legacy); };
if (typeof(getStore(legacy).forgetPad) === "function") {
// TODO implement forgetPad in store.js
getStore(legacy).forgetPad(href, callback);
}
}; };
// STORAGE // STORAGE
@ -462,7 +455,12 @@ define([
}); });
if (!contains) { 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) { setRecentPads(renamed, function (err, data) {
@ -535,8 +533,8 @@ define([
f(void 0, env); f(void 0, env);
}; };
Store.ready(function (err, store) { FS.ready(function (err, store) {
common.store = env.store = store; fsStore = common.store = env.store = store;
$(function() { $(function() {
// Race condition : if document.body is undefined when alertify.js is loaded, Alertify // Race condition : if document.body is undefined when alertify.js is loaded, Alertify
@ -597,7 +595,7 @@ define([
cb(); cb();
}); */ }); */
}); }, common);
}; };
/* /*

@ -54,10 +54,12 @@ li {
border: 1px dotted #bbb; border: 1px dotted #bbb;
background: #666; background: #666;
color: #eee; color: #eee;
margin: -1px;
} }
/* TREE */ /* TREE */
#tree { #tree {
border: 2px solid blue; border: 2px solid blue;
box-sizing: border-box; box-sizing: border-box;
@ -194,6 +196,10 @@ li {
flex: 1; flex: 1;
} }
#content li * {
pointer-events: none;
}
#content li:hover:not(.header) .name { #content li:hover:not(.header) .name {
text-decoration: underline; text-decoration: underline;
} }

@ -12,6 +12,7 @@ define([
var NEW_FOLDER_NAME = Messages.fm_newFolder; var NEW_FOLDER_NAME = Messages.fm_newFolder;
var init = module.init = function (files, config) { var init = module.init = function (files, config) {
FILES_DATA = config.storageKey;
var DEBUG = config.DEBUG || false; var DEBUG = config.DEBUG || false;
var logging = console.log; var logging = console.log;
var log = config.log || logging; var log = config.log || logging;
@ -192,6 +193,16 @@ define([
return ret; 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) { var removeFileFromRoot = function (root, href) {
if (isFile(root)) { return; } if (isFile(root)) { return; }
for (var e in root) { for (var e in root) {
@ -536,18 +547,39 @@ define([
pushToTrash(key, href, [UNSORTED]); pushToTrash(key, href, [UNSORTED]);
}; };
var addPad = exp.addPad = function (href, data) { var addUnsortedPad = exp.addPad = function (href) {
if (!getFileData(href)) {
files[FILES_DATA].push(data);
}
var unsortedFiles = getUnsortedFiles().slice(); var unsortedFiles = getUnsortedFiles().slice();
var rootFiles = getRootFiles().slice(); var rootFiles = getRootFiles().slice();
//var trashFiles = getTrashFiles().slice(); var trashFiles = getTrashFiles().slice();
if (unsortedFiles.indexOf(href) === -1 && rootFiles.indexOf(href) === -1) { if (unsortedFiles.indexOf(href) === -1 && rootFiles.indexOf(href) === -1 && trashFiles.indexOf(href) === -1) {
files[UNSORTED].push(href); 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 () { var fixFiles = exp.fixFiles = function () {
// Explore the tree and check that everything is correct: // Explore the tree and check that everything is correct:
// * 'root', 'trash' and 'filesData' exist and are objects // * 'root', 'trash' and 'filesData' exist and are objects

@ -21,17 +21,13 @@ define([
//var hash = Cryptpad.getAttribute('FS_hash', cb); //var hash = Cryptpad.getAttribute('FS_hash', cb);
var hash = localStorage.FS_hash; var hash = localStorage.FS_hash;
if (hash) { var secret = Cryptpad.getSecrets(hash);
window.location.hash = hash;
}
var secret = Cryptpad.getSecrets();
var ROOT = "root"; var ROOT = "root";
var ROOT_NAME = Messages.fm_rootName; var ROOT_NAME = Messages.fm_rootName;
var UNSORTED = "unsorted"; var UNSORTED = "unsorted";
var UNSORTED_NAME = Messages.fm_unsortedName; var UNSORTED_NAME = Messages.fm_unsortedName;
var FILES_DATA = "filesData"; var FILES_DATA = Cryptpad.storageKey;
var FILES_DATA_NAME = Messages.fm_filesDataName; var FILES_DATA_NAME = Messages.fm_filesDataName;
var TRASH = "trash"; var TRASH = "trash";
var TRASH_NAME = Messages.fm_trashName; var TRASH_NAME = Messages.fm_trashName;
@ -44,6 +40,7 @@ define([
var NEW_FOLDER_NAME = Messages.fm_newFolder; var NEW_FOLDER_NAME = Messages.fm_newFolder;
var config = {}; var config = {};
config.storageKey = FILES_DATA;
var DEBUG = config.DEBUG = true; var DEBUG = config.DEBUG = true;
var debug = config.debug = DEBUG ? console.log : function() {return;}; var debug = config.debug = DEBUG ? console.log : function() {return;};
var logError = config.logError = console.error; var logError = config.logError = console.error;
@ -55,7 +52,7 @@ define([
} }
}; };
var filesObject = module.files = { var filesObject = {
root: { root: {
"Directory 1": { "Directory 1": {
"Dir A": { "Dir A": {
@ -213,7 +210,7 @@ define([
localStorage[LOCALSTORAGE_LAST] = JSON.stringify(path); localStorage[LOCALSTORAGE_LAST] = JSON.stringify(path);
}; };
var initLSOpened = function () { var initLocalStorage = function () {
try { try {
var store = JSON.parse(localStorage[LOCALSTORAGE_OPENED]); var store = JSON.parse(localStorage[LOCALSTORAGE_OPENED]);
if (!$.isArray(store)) { if (!$.isArray(store)) {
@ -562,14 +559,13 @@ define([
var addDragAndDropHandlers = function ($element, path, isFolder, droppable) { var addDragAndDropHandlers = function ($element, path, isFolder, droppable) {
// "dragenter" is fired for an element and all its children // "dragenter" is fired for an element and all its children
// "dragleave" may be fired when entering a child // "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 // --> We store the number of enter/leave and the element entered and we remove the
// highlighting only when we have left everything // highlighting only when we have left everything
var counter = 0; var counter = 0;
var dragenterList = [];
$element.on('dragstart', function (e) { $element.on('dragstart', function (e) {
e.stopPropagation(); e.stopPropagation();
counter = 0; counter = 0;
dragenterList = [];
onDrag(e.originalEvent, path); onDrag(e.originalEvent, path);
}); });
@ -585,18 +581,15 @@ define([
$element.on('dragenter', function (e) { $element.on('dragenter', function (e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
if (dragenterList.indexOf(e.target) !== -1) { return; }
dragenterList.push(e.target);
counter++; counter++;
$element.addClass('droppable'); $element.addClass('droppable');
}); });
$element.on('dragleave', function (e) { $element.on('dragleave', function (e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
var idx = dragenterList.indexOf(e.target);
dragenterList.splice(idx, 1);
counter--; counter--;
if (counter <= 0) { if (counter <= 0) {
counter = 0;
$element.removeClass('droppable'); $element.removeClass('droppable');
} }
}); });
@ -1283,7 +1276,6 @@ define([
var realtime = module.realtime = info.realtime; var realtime = module.realtime = info.realtime;
var editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys); var editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys);
window.location.hash = editHash;
//Cryptpad.setAttribute("FS_hash", editHash, cb, store); //Cryptpad.setAttribute("FS_hash", editHash, cb, store);
localStorage.FS_hash = editHash; localStorage.FS_hash = editHash;
@ -1303,16 +1295,17 @@ define([
}); });
});*/ });*/
}).on('ready', function () { }).on('ready', function () {
module.files = rt.proxy;
if (JSON.stringify(rt.proxy) === '{}') { if (JSON.stringify(rt.proxy) === '{}') {
var store = Cryptpad.getStore(); var store = Cryptpad.getStore(true);
store.get(Cryptpad.storageKey, function (err, s) { store.get(Cryptpad.storageKey, function (err, s) {
rt.proxy.filesData = s; rt.proxy[FILES_DATA] = s;
initLSOpened(); initLocalStorage();
init(rt.proxy); init(rt.proxy);
}); });
return; return;
} }
initLSOpened(); initLocalStorage();
init(rt.proxy); init(rt.proxy);
}) })
.on('disconnect', function () { .on('disconnect', function () {

Loading…
Cancel
Save