diff --git a/.gitignore b/.gitignore index abc6eb530..a75bb20e2 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ messages.log .DS_Store www/scratch data +npm-debug.log diff --git a/.travis.yml b/.travis.yml index 1331ef3cb..24288c6f2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ branches: - soon - staging node_js: - - "4.2.1" + - "6.6.0" before_script: - npm run-script lint - cp config.js.dist config.js diff --git a/bower.json b/bower.json index a6fc85b41..be5bdf00e 100644 --- a/bower.json +++ b/bower.json @@ -24,23 +24,19 @@ "ckeditor": "~4.5.6", "codemirror": "^5.19.0", "requirejs": "~2.1.15", - "reconnectingWebsocket": "", "marked": "~0.3.5", "rangy": "rangy-release#~1.3.0", "json.sortify": "~2.1.0", "fabric.js": "fabric#~1.6.0", "hyperjson": "~1.4.0", "textpatcher": "^1.3.0", - "proxy-polyfill": "^0.1.5", "chainpad": "^0.3.0", "chainpad-json-validator": "^0.2.0", "chainpad-crypto": "^0.1.3", "chainpad-listmap": "^0.3.0", - "lil-uri": "^0.2.1", "file-saver": "^1.3.1", "diff-dom": "^2.1.1", "alertifyjs": "^1.0.11", - "spin.js": "^2.3.2", "scrypt-async": "^1.2.0", "bootstrap": "#v4.0.0-alpha.6" } diff --git a/customize.dist/about.html b/customize.dist/about.html index 988efafc3..dfacd0634 100644 --- a/customize.dist/about.html +++ b/customize.dist/about.html @@ -115,6 +115,7 @@ +
-If you're reading this, you were probably curious why CryptPad is requesting web pages when you perform certain actions.
-We care about your privacy, and at the same time we want CryptPad to be very easy to use. +
If you're reading this, you were probably curious why CryptPad is requesting web pages when you perform certain actions.
+We care about your privacy, and at the same time we want CryptPad to be very easy to use. We use this file to figure out which UI features matter to our users, by requesting it along with a parameter specifying which action was taken.
-If you would like to opt out, visit your user settings page, where you'll find a checkbox to enable or disable user feedback
+If you would like to opt out, visit your user settings page, where you'll find a checkbox to enable or disable user feedback
diff --git a/www/common/fileObject.js b/www/common/fileObject.js index d8f10ced4..43ba5c3e5 100644 --- a/www/common/fileObject.js +++ b/www/common/fileObject.js @@ -6,10 +6,10 @@ define([ var Messages = {}; - var ROOT = "root"; - var UNSORTED = "unsorted"; - var TRASH = "trash"; - var TEMPLATE = "template"; + var ROOT = module.ROOT = "root"; + var UNSORTED = module.UNSORTED = "unsorted"; + var TRASH = module.TRASH = "trash"; + var TEMPLATE = module.TEMPLATE = "template"; var init = module.init = function (files, config) { var Cryptpad = config.Cryptpad; @@ -232,15 +232,95 @@ define([ return ret; }; - var getFilesDataFiles = function () { + var getFilesDataFiles = exp.getFilesDataFiles = function () { var ret = []; - for (var el in files[FILES_DATA]) { + files[FILES_DATA].forEach(function (el) { if (el.href && ret.indexOf(el.href) === -1) { ret.push(el.href); } + }); + return ret; + }; + + var _findFileInRoot = function (path, href) { + if (path[0] !== ROOT && path[0] !== TRASH) { return []; } + var paths = []; + var root = exp.findElement(files, path); + var addPaths = function (p) { + if (paths.indexOf(p) === -1) { + paths.push(p); + } + }; + + if (isFile(root)) { + if (compareFiles(href, root)) { + if (paths.indexOf(path) === -1) { + paths.push(path); + } + } + return paths; + } + for (var e in root) { + var nPath = path.slice(); + nPath.push(e); + _findFileInRoot(nPath, href).forEach(addPaths); + } + + return paths; + }; + var _findFileInHrefArray = function (rootName, href) { + var unsorted = files[rootName].slice(); + var ret = []; + var i = -1; + while ((i = unsorted.indexOf(href, i+1)) !== -1){ + ret.push([rootName, i]); } return ret; }; + var _findFileInTrash = function (path, href) { + var root = exp.findElement(files, path); + var paths = []; + var addPaths = function (p) { + if (paths.indexOf(p) === -1) { + paths.push(p); + } + }; + if (path.length === 1) { + Object.keys(root).forEach(function (key) { + var arr = root[key]; + if (!Array.isArray(arr)) { return; } + var nPath = path.slice(); + nPath.push(key); + _findFileInTrash(nPath, href).forEach(addPaths); + }); + } + if (path.length === 2) { + if (!Array.isArray(root)) { return []; } + root.forEach(function (el, i) { + var nPath = path.slice(); + nPath.push(i); + nPath.push('element'); + if (isFile(el.element)) { + if (compareFiles(href, el.element)) { + addPaths(nPath); + } + return; + } + _findFileInTrash(nPath, href).forEach(addPaths); + }); + } + if (path.length >= 4) { + _findFileInRoot(path, href).forEach(addPaths); + } + return paths; + }; + var findFile = exp.findFile = function (href) { + var rootpaths = _findFileInRoot([ROOT], href); + var unsortedpaths = _findFileInHrefArray(UNSORTED, href); + var templatepaths = _findFileInHrefArray(TEMPLATE, href); + var trashpaths = _findFileInTrash([TRASH], href); + return rootpaths.concat(unsortedpaths, templatepaths, trashpaths); + }; // Remove the selected 'href' from the tree located at 'path', and push its locations to the 'paths' array var removeFileFromRoot = function (path, href) { @@ -374,7 +454,6 @@ define([ var parentEl = exp.findElement(files, parentPath); // Trash root: we have array here, we can't just splice with the path otherwise we might break the path // of another element in the loop - console.log(path); if (path.length === 4) { trashRoot.push({ name: path[1], @@ -573,7 +652,6 @@ define([ // Import elements in the file manager var importElements = exp.importElements = function (elements, path, cb) { if (!elements || elements.length === 0) { return; } - console.log(elements); var newParent = findElement(files, path); if (!newParent) { debug("Trying to import elements into a non-existing folder"); return; } elements.forEach(function (e) { @@ -670,7 +748,7 @@ define([ }; // Delete permanently (remove from the trash root and from filesData) - var removeFromTrash = exp.removeFromTrash = function (path, cb) { + var removeFromTrash = exp.removeFromTrash = function (path, cb, nocheck) { if (!path || path.length < 4 || path[0] !== TRASH) { return; } // Remove the last element from the path to get the parent path and the element name var parentPath = path.slice(); @@ -691,7 +769,9 @@ define([ parentEl[name] = undefined; delete parentEl[name]; } - checkDeletedFiles(); + if (!nocheck) { + checkDeletedFiles(); + } if(cb) { cb(); } }; @@ -773,7 +853,7 @@ define([ pushToTrash(key, href, path); }; - var addUnsortedPad = exp.addPad = function (href, path, name) { + var addPad = exp.addPad = function (href, path, name) { if (workgroup) { return; } if (!href) { return; } var unsortedFiles = getUnsortedFiles(); @@ -798,10 +878,54 @@ define([ } } if (unsortedFiles.indexOf(href) === -1 && rootFiles.indexOf(href) === -1 && templateFiles.indexOf(href) === -1 && trashFiles.indexOf(href) === -1) { + console.log('push', href); files[UNSORTED].push(href); } }; + var replaceFile = function (path, o, n) { + var root = exp.findElement(files, path); + + if (isFile(root)) { return; } + for (var e in root) { + if (isFile(root[e])) { + if (compareFiles(o, root[e])) { + root[e] = n; + } + } else { + var nPath = path.slice(); + nPath.push(e); + replaceFile(nPath, o, n); + } + } + }; + + // Replace a href by a stronger one everywhere in the drive (except FILES_DATA) + var replaceHref = exp.replaceHref = function (o, n) { + if (!isFile(o) || !isFile(n)) { return; } + var paths = findFile(o); + + // Remove all the occurences in the trash + // Replace all the occurences not in the trash + // If all the occurences are in the trash or no occurence, add the pad to unsorted + var allInTrash = true; + paths.forEach(function (p) { + if (p[0] === TRASH) { + removeFromTrash(p, null, true); // 3rd parameter means skip "checkDeletedFiles" + return; + } else { + allInTrash = false; + var parentPath = p.slice(); + var key = parentPath.pop(); + var parentEl = findElement(files, parentPath); + parentEl[key] = n; + } + }); + if (allInTrash) { + addPad(n); + } + }; + // addTemplate is called when we want to add a new pad, never visited, to the templates list // first, we must add it to FILES_DATA, so the input has to be an fileDAta object var addTemplate = exp.addTemplate = function (fileData) { diff --git a/customize.dist/fsStore.js b/www/common/fsStore.js similarity index 97% rename from customize.dist/fsStore.js rename to www/common/fsStore.js index fbf7a5719..8f2405643 100644 --- a/customize.dist/fsStore.js +++ b/www/common/fsStore.js @@ -119,6 +119,10 @@ define([ return filesOp.getStructure(); }; + ret.replaceHref = function (o, n) { + return filesOp.replaceHref(o, n); + }; + var changeHandlers = ret.changeHandlers = []; ret.change = function (f) {}; @@ -127,9 +131,10 @@ define([ }; var onReady = function (f, proxy, Cryptpad, exp) { - var fo = FO.init(proxy.drive, { + var fo = exp.fo = FO.init(proxy.drive, { Cryptpad: Cryptpad }); + //storeObj = proxy; store = initStore(fo, proxy, exp); if (typeof(f) === 'function') { diff --git a/www/common/login.js b/www/common/login.js index 99678b1dd..7576ff4d4 100644 --- a/www/common/login.js +++ b/www/common/login.js @@ -94,17 +94,21 @@ define([ res.realtime = rt.realtime; res.network = rt.network; + // they're registering... + res.userHash = opt.userHash; + res.userName = uname; + // they tried to just log in but there's no such user if (!isRegister && isProxyEmpty(rt.proxy)) { rt.network.disconnect(); // clean up after yourself return void cb('NO_SUCH_USER', res); } - // they're registering... - - res.userHash = opt.userHash; - res.userName = uname; - //res.displayName // TODO + // they tried to register, but those exact credentials exist + if (isRegister && !isProxyEmpty(rt.proxy)) { + rt.network.disconnect(); + return void cb('ALREADY_REGISTERED', res); + } cb(void 0, res); }); diff --git a/www/common/mergeDrive.js b/www/common/mergeDrive.js new file mode 100644 index 000000000..f056fedee --- /dev/null +++ b/www/common/mergeDrive.js @@ -0,0 +1,198 @@ +require.config({ paths: { 'json.sortify': '/bower_components/json.sortify/dist/JSON.sortify' } }); +define([ + '/common/cryptpad-common.js', + '/common/cryptget.js', + '/common/fileObject.js', + 'json.sortify' +], function (Cryptpad, Crypt, FO, Sortify) { + var exp = {}; + + var getType = function (el) { + if (el === null) { return "null"; } + return Array.isArray(el) ? "array" : typeof(el); + }; + + var findAvailableKey = function (obj, key) { + if (typeof (obj[key]) === "undefined") { return key; } + var i = 1; + var nkey = key; + while (typeof (obj[nkey]) !== "undefined") { + nkey = key + '_' + i; + i++; + } + return nkey; + }; + + var copy = function (el) { + if (typeof (el) !== "object") { return el; } + return JSON.parse(JSON.stringify(el)); + }; + + var deduplicate = function (array) { + var a = array.slice(); + for(var i=0; i