From cde724399cb52fa436728c80265affa6567944d5 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 11 Apr 2017 14:53:44 +0200 Subject: [PATCH 01/53] Pin the pads --- www/common/cryptpad-common.js | 112 +++++++++++++++++++++------------- www/common/fileObject.js | 27 ++++++-- www/common/fsStore.js | 3 + 3 files changed, 95 insertions(+), 47 deletions(-) diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 48231245d..b787978ca 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -389,6 +389,19 @@ load pinpad dynamically only after you know that it will be needed */ * title * ??? // what else can we put in here? */ + var checkObjectData = function (pad) { + if (!pad.ctime) { pad.ctime = pad.atime; } + if (/^https*:\/\//.test(pad.href)) { + pad.href = common.getRelativeHref(pad.href); + } + var parsed = common.parsePadUrl(pad.href); + if (!parsed || !parsed.hash) { return; } + if (!pad.title) { + pad.title = common.getDefaultname(parsed); + } + return parsed.hash; + }; + // Migrate from legacy store (localStorage) var migrateRecentPads = common.migrateRecentPads = function (pads) { return pads.map(function (pad) { var hash; @@ -405,16 +418,7 @@ load pinpad dynamically only after you know that it will be needed */ ctime: pad[1], }; } else if (pad && typeof(pad) === 'object') { - if (!pad.ctime) { pad.ctime = pad.atime; } - if (!pad.title) { - pad.href.replace(/#(.*)$/, function (x, hash) { - pad.title = hash.slice(0,8); - }); - } - if (/^https*:\/\//.test(pad.href)) { - pad.href = common.getRelativeHref(pad.href); - } - hash = pad.href.slice(pad.href.indexOf('#')+1); + hash = checkObjectData(pad); if (!hash || !common.parseHash(hash)) { return; } return pad; } else { @@ -424,6 +428,18 @@ load pinpad dynamically only after you know that it will be needed */ } }).filter(function (x) { return x; }); }; + // Remove everything from RecentPads that is not an object and check the objects + var checkRecentPads = common.checkRecentPads = function (pads) { + pads.forEach(function (pad, i) { + if (pad && typeof(pad) === 'object') { + var hash = checkObjectData(pad); + if (!hash || !common.parseHash(hash)) { return; } + return pad; + } + console.error("[Cryptpad.migrateRecentPads] pad had unexpected value"); + getStore().removeData(i); + }); + }; // Get the pads from localStorage to migrate them to the object store var getLegacyPads = common.getLegacyPads = function (cb) { @@ -486,14 +502,14 @@ load pinpad dynamically only after you know that it will be needed */ }; // Create untitled documents when no name is given - var getDefaultName = common.getDefaultName = function (parsed, recentPads) { + var getDefaultName = common.getDefaultName = function (parsed) { var type = parsed.type; var untitledIndex = 1; var name = (Messages.type)[type] + ' - ' + new Date().toString().split(' ').slice(0,4).join(' '); return name; }; var isDefaultName = common.isDefaultName = function (parsed, title) { - var name = getDefaultName(parsed, []); + var name = getDefaultName(parsed); return title === name; }; @@ -594,29 +610,18 @@ load pinpad dynamically only after you know that it will be needed */ }; // STORAGE - /* fetch and migrate your pad history from localStorage */ + /* fetch and migrate your pad history from the store */ var getRecentPads = common.getRecentPads = function (cb) { getStore().getDrive(storageKey, function (err, recentPads) { if (isArray(recentPads)) { - cb(void 0, migrateRecentPads(recentPads)); + checkRecentPads(recentPads); + cb(void 0, recentPads); return; } cb(void 0, []); }); }; - // STORAGE - /* commit a list of pads to localStorage */ - // TODO integrate pinning if enabled - var setRecentPads = common.setRecentPads = function (pads, cb) { - getStore().setDrive(storageKey, pads, function (err, data) { - if (PINNING_ENABLED && isLoggedIn()) { - console.log("TODO check pin hash"); - } - cb(err, data); - }); - }; - // STORAGE: Display Name var getLastName = common.getLastName = function (cb) { common.getAttribute('username', function (err, userName) { @@ -636,7 +641,6 @@ load pinpad dynamically only after you know that it will be needed */ }; // STORAGE - // TODO integrate pinning if enabled var forgetPad = common.forgetPad = function (href, cb) { var parsed = parsePadUrl(href); @@ -724,6 +728,8 @@ load pinpad dynamically only after you know that it will be needed */ var href = window.location.href; var parsed = parsePadUrl(href); href = getRelativeHref(href); + // getRecentPads return the array from the drive, not a copy + // We don't have to call "set..." at the end, everything is stored with listmap getRecentPads(function (err, recent) { if (err) { cb(err); @@ -779,20 +785,15 @@ load pinpad dynamically only after you know that it will be needed */ if (!contains) { var data = makePad(href, name); - renamed.push(data); - if (typeof(getStore().addPad) === "function") { - getStore().addPad(href, common.initialPath, common.initialName || name); - } + getStore().pushData(data); + getStore().addPad(href, common.initialPath, common.initialName || name); } - - setRecentPads(renamed, function (err, data) { - if (updateWeaker.length > 0) { - updateWeaker.forEach(function (obj) { - getStore().replaceHref(obj.o, obj.n); - }); - } - cb(err, data); - }); + if (updateWeaker.length > 0) { + updateWeaker.forEach(function (obj) { + getStore().replaceHref(obj.o, obj.n); + }); + } + cb(err, recent); }); }; @@ -920,6 +921,13 @@ load pinpad dynamically only after you know that it will be needed */ // TODO check if pin list is up to date // if not, reset + common.arePinsSynced(function (err, yes) { + if (!yes) { + common.resetPins(function (err, hash) { + console.log('RESET DONE'); + }); + } + }); cb(); }); } else if (PINNING_ENABLED) { @@ -1098,6 +1106,9 @@ load pinpad dynamically only after you know that it will be needed */ }; var pinsReady = common.pinsReady = function () { + if (!isLoggedIn()) { + return false; + } if (!PINNING_ENABLED) { console.error('[PINNING_DISABLED]'); return false; @@ -1121,8 +1132,7 @@ load pinpad dynamically only after you know that it will be needed */ }; var resetPins = common.resetPins = function (cb) { - if (!PINNING_ENABLED) { return void console.error('[PINNING_DISABLED]'); } - if (!rpc) { return void console.error('[RPC_NOT_READY]'); } + if (!pinsReady()) { return void cb ('[RPC_NOT_READY]'); } var list = getCanonicalChannelList(); rpc.reset(list, function (e, hash) { @@ -1131,6 +1141,24 @@ load pinpad dynamically only after you know that it will be needed */ }); }; + var pinPads = common.pinPads = function (pads, cb) { + if (!pinsReady()) { return void cb ('[RPC_NOT_READY]'); } + + rpc.pin(pads, function (e, hash) { + if (e) { return void cb(e); } + cb(void 0, hash); + }); + }; + + var unpinPads = common.unpinPads = function (pads, cb) { + if (!pinsReady()) { return void cb ('[RPC_NOT_READY]'); } + + rpc.unpin(pads, function (e, hash) { + if (e) { return void cb(e); } + cb(void 0, hash); + }); + }; + var createButton = common.createButton = function (type, rightside, data, callback) { var button; var size = "17px"; diff --git a/www/common/fileObject.js b/www/common/fileObject.js index 537ada142..a397cf928 100644 --- a/www/common/fileObject.js +++ b/www/common/fileObject.js @@ -45,6 +45,23 @@ define([ return a; }; + var pushFileData = exp.pushData = function (data) { + Cryptpad.pinPads([Cryptpad.hrefToHexChannelId(data.href)], function (e, hash) { + console.log(hash); + }); + files[FILES_DATA].push(data); + }; + var spliceFileData = exp.removeData = function (idx) { + var data = files[FILES_DATA][idx]; + if (typeof data === "object") { + Cryptpad.unpinPads([Cryptpad.hrefToHexChannelId(data.href)], function (e, hash) { + console.log(hash); + }); + } + files[FILES_DATA].splice(idx, 1); + }; + + var comparePath = exp.comparePath = function (a, b) { if (!a || !b || !$.isArray(a) || !$.isArray(b)) { return false; } if (a.length !== b.length) { return false; } @@ -459,7 +476,7 @@ define([ var idx = files[FILES_DATA].indexOf(f); if (idx !== -1) { debug("Removing", f, "from filesData"); - files[FILES_DATA].splice(idx, 1); + spliceFileData(idx); removePadAttribute(f.href); } }); @@ -745,7 +762,7 @@ define([ }; var pushNewFileData = function (href, title) { - files[FILES_DATA].push({ + pushFileData({ href: href, title: title, atime: +new Date(), @@ -865,7 +882,7 @@ define([ var idx = files[FILES_DATA].indexOf(f); if (idx !== -1) { debug("Removing", f, "from filesData"); - files[FILES_DATA].splice(idx, 1); + spliceFileData(idx); // Remove the "padAttributes" stored in the realtime object for that pad removePadAttribute(f.href); } @@ -1009,7 +1026,7 @@ define([ return o.href === href; }); if (!test) { - files[FILES_DATA].push(fileData); + pushFileData(fileData); } if (files[TEMPLATE].indexOf(href) === -1) { files[TEMPLATE].push(href); @@ -1141,7 +1158,7 @@ define([ toClean.forEach(function (el) { var idx = fd.indexOf(el); if (idx !== -1) { - fd.splice(idx, 1); + spliceFileData(idx); } }); }; diff --git a/www/common/fsStore.js b/www/common/fsStore.js index 794a39ecd..1974aa27d 100644 --- a/www/common/fsStore.js +++ b/www/common/fsStore.js @@ -86,6 +86,9 @@ define([ cb(void 0, Object.keys(storeObj)); }; + ret.removeData = filesOp.removeData; + ret.pushData = filesOp.pushData; + ret.addPad = function (href, path, name) { filesOp.addPad(href, path, name); }; From 4e61b79f9ac506d29a53fb5db2a0050e6e4c40e1 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 11 Apr 2017 15:11:33 +0200 Subject: [PATCH 02/53] Clean fileObject --- www/common/fileObject.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/www/common/fileObject.js b/www/common/fileObject.js index a397cf928..202a67f4c 100644 --- a/www/common/fileObject.js +++ b/www/common/fileObject.js @@ -89,12 +89,15 @@ define([ var isPathInTrash = exp.isPathInTrash = function (path) { return path[0] && path[0] === TRASH; }; + var isInTrashRoot = exp.isInTrashRoot = function (path) { + return path[0] === TRASH && path.length === 4; + }; var isPathInFilesData = exp.isPathInFilesData = function (path) { return path[0] && path[0] === FILES_DATA; }; - var isFile = exp.isFile = function (element) { + var isFile = exp.isFile = function (element) { return typeof(element) === "string"; }; @@ -439,10 +442,6 @@ define([ return paths; }; - var isInTrashRoot = exp.isInTrashRoot = function (path) { - return path[0] === TRASH && path.length === 4; - }; - var removePadAttribute = function (f) { Object.keys(files).forEach(function (key) { var hash = f.indexOf('#') !== -1 ? f.slice(f.indexOf('#') + 1) : null; @@ -486,9 +485,9 @@ define([ var parentPath = path.slice(); var key = parentPath.pop(); var parentEl = exp.findElement(files, parentPath); - if (path.length === 4 && path[0] === TRASH) { + if (isInTrashRoot(path)) { files[TRASH][path[1]].splice(path[2], 1); - } else if (path[0] === UNSORTED || path[0] === TEMPLATE) { + } else if (isPathInHrefArray(path)) { parentEl.splice(key, 1); } else { parentEl[key] = undefined; From 9aa0548b1fe1617350d79fada861a8875114894e Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 12 Apr 2017 15:59:30 +0200 Subject: [PATCH 03/53] remove dead cursor code --- www/common/cursor.js | 209 ----------------------------------------- www/common/treesome.js | 92 ------------------ 2 files changed, 301 deletions(-) diff --git a/www/common/cursor.js b/www/common/cursor.js index 07e705244..6da99f1bd 100644 --- a/www/common/cursor.js +++ b/www/common/cursor.js @@ -2,10 +2,6 @@ define([ '/common/treesome.js', '/bower_components/rangy/rangy-core.min.js' ], function (Tree, Rangy, saveRestore) { - //window.Rangy = Rangy; - //window.Tree = Tree; - // do some function for the start and end of the cursor - var log = function (x) { console.log(x); }; var error = function (x) { console.log(x); }; var verbose = function (x) { if (window.verboseMode) { console.log(x); } }; @@ -27,108 +23,6 @@ define([ } }; - // TODO deprecate - // assumes a negative index - var seekLeft /* = cursor.seekLeft*/ = function (el, delta, current) { - var textLength; - var previous; - - // normalize - - if (-delta >= current) { - delta += current; - current = 0; - } else { - current += delta; - delta = 0; - } - - while (delta) { - previous = el; - el = Tree.previousNode(el, inner); - if (el) { - textLength = el.textContent.length; - if (-delta > textLength) { - delta -= textLength; - } else { - current = textLength + delta; - delta = 0; - } - } else { - return { - el: previous, - offset: 0, - error: "out of bounds" - }; - } - } - return { - el: el, - offset: current - }; - }; - - // TODO deprecate - // seekRight assumes a positive delta - var seekRight = /* cursor.seekRight = */ function (el, delta, current) { - var textLength; - var previous; - - // normalize - delta += current; - current = 0; - - while (delta) { - if (el) { - textLength = el.textContent.length; - if (delta >= textLength) { - delta -= textLength; - previous = el; - el = Tree.nextNode(el, inner); - } else { - current = delta; - delta = 0; - } - } else { - // don't ever return a negative index - if (previous.textContent.length) { - textLength = previous.textContent.length - 1; - } else { - textLength = 0; - } - return { - el: previous, - offset: textLength, - error: "out of bounds" - }; - } - } - return { - el: el, - offset: current - }; - }; - - // TODO deprecate - var seekToDelta = /* cursor.seekToDelta = */ function (el, delta, current) { - var result = null; - if (el) { - if (delta < 0) { - return seekLeft(el, delta, current); - } else if (delta > 0) { - return seekRight(el, delta, current); - } else { - result = { - el: el, - offset: current - }; - } - } else { - error("[cursor.seekToDelta] el is undefined"); - } - return result; - }; - /* cursor.update takes notes about wherever the cursor was last seen in the event of a cursor loss, the information produced by side effects of this function should be used to recover the cursor @@ -262,109 +156,6 @@ define([ }; }; - /* getLength assumes that both nodes exist inside of the active editor. */ - // unused currently - var getLength = cursor.getLength = function () { - if (Range.start.el === Range.end.el) { - if (Range.start.offset === Range.end.offset) { return 0; } - if (Range.start.offset < Range.end.offset) { - return Range.end.offset - Range.start.offset; - } else { - return Range.start.offset - Range.end.offset; - } - } else { - var order = Tree.orderOfNodes(Range.start.el, Range.end.el, inner); - var L; - var cur; - - /* we know that the cursor elements are different, and that we - must traverse to find the total length. We also know the - order of the nodes (probably 1 or -1) */ - if (order === 1) { - L = (Range.start.el.textContent.length - Range.start.offset); - cur = Tree.nextNode(Range.start.el, inner); - while (cur && cur !== Range.end.el) { - L += cur.textContent.length; - cur = Tree.nextNode(cur, inner); - } - L += Range.end.offset; - return L; - } else if (order === -1) { - L = (Range.end.el.textContent - Range.end.offset); - cur = Tree.nextNode(Range.end.el, inner); - while (cur && cur !== Range.start.el) { - L += cur.textContent.length; - cur = Tree.nextNode(cur, inner); - } - L += Range.start.offset; - return -L; - } else { - console.error("unexpected ordering of nodes..."); - return null; - } - } - }; - - // previously used for testing - // TODO deprecate - var delta = /* cursor.delta = */ function (delta1, delta2) { - var sel = Rangy.getSelection(inner); - delta2 = (typeof delta2 !== 'undefined') ? delta2 : delta1; - - // update returns errors if there are problems - // and updates the persistent Range object - var err = cursor.update(sel, inner); - if (err) { return err; } - - // create a range to modify - var range = Rangy.createRange(); - - /* - The assumption below is that Range.(start|end).el - actually exists. This might not be the case. - TODO check if start and end elements are defined - */ - - // using infromation about wherever you were last... - // move both parts by some delta - var start = seekToDelta(Range.start.el, delta1, Range.start.offset); - var end = seekToDelta(Range.end.el, delta2, Range.end.offset); - - /* if range is backwards, cursor.delta fails - so check if they're in the expected order - before setting the new range */ - - var order = Tree.orderOfNodes(start.el, end.el, inner); - var backward; - - // this could all be one line but nobody would be able to read it - if (order === -1) { - // definitely backward - backward = true; - } else if (order === 0) { - // might be backward, check offsets to know for sure - backward = (start.offset > end.offset); - } else { - // definitely not backward - backward = false; - } - - if (backward) { - range.setStart(end.el, end.offset); - range.setEnd(start.el, start.offset); - } else { - range.setStart(start.el, start.offset); - range.setEnd(end.el, end.offset); - } - - // actually set the cursor to the new range - sel.setSingleRange(range); - return { - startError: start.error, - endError: end.error - }; - }; - cursor.brFix = function () { cursor.update(); var start = Range.start; diff --git a/www/common/treesome.js b/www/common/treesome.js index 65b0b2c58..cf9dcff97 100644 --- a/www/common/treesome.js +++ b/www/common/treesome.js @@ -1,91 +1,6 @@ define([], function () { var tree = {}; - // FIXME this isn't being used - var someElement = tree.some = function (root, predicate) { - // take the index of the last element in the current root - var last = root.childElementCount - 1; - - // it might be a leaf node - if (last < 0) { return false; } - - // otherwise it has children - while (last >= 0) { - // check from back to front - - // check the node's children (depth first) - // if the predicate tests true, return true - if (tree.some(root.children[last], predicate)) { - return true; - } // otherwise none of the nodes inside it matched. - - // check the node itself - if (predicate(root.children[last], last)) { - return true; - } - last--; - } - return false; - }; - - // FIXME this isn't being used - var someText = tree.someIncludingText = function (root, predicate) { - // take the index of the last element in the current root - var last = root.childNodes.length - 1; - - // it might be a leaf node - if (last < 0) { return false; } - - // otherwise it has children - while (last >= 0) { - // check from back to front - - // check the node's children (depth first) - // if the predicate tests true, return true - if (tree.someIncludingText(root.childNodes[last], predicate)) { - return true; - } // otherwise none of the nodes inside it matched. - - // check the node itself - if (predicate(root.childNodes[last], last)) { - return true; - } - last--; - } - return false; - }; - - // FIXME not being used - tree.findSameHierarchy = function (list, ancestor) { - var i = 0; - var success = true; - var last = list.length - 1; - var el; - - tree.someIncludingText(ancestor, function (e) { - // don't out of bounds - if (i > last) { - // unsuccessful - success = false; - return true; - } - - if (list[i] === (e.tagName||e.nodeName)) { - - if (i === last) { - el = e; - return true; - } - i++; - } else { - // hierarchy has changed, what should we do? - success = false; - return true; // terminate - } - }); - return success? el: false; - }; - var indexOfNode = tree.indexOfNode = function (el) { if (!(el && el.parentNode)) { console.log("No parentNode found!"); @@ -107,13 +22,6 @@ define([], function () { return el.childNodes.length; }; - var parentsOf = tree.parentsOf = function (el, root) { - var P = []; - var p = el; - while (p !== root) { P.push((p = p.parentNode)); } - return P; - }; - /* rightmost and leftmost return the deepest right and left leaf nodes of a tree */ From 7a59183bb111efad732cad790ad9468e8423682a Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 12 Apr 2017 16:02:42 +0200 Subject: [PATCH 04/53] pinpad.create should always be async --- www/common/pinpad.js | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/www/common/pinpad.js b/www/common/pinpad.js index 78ae607db..aa2cc532f 100644 --- a/www/common/pinpad.js +++ b/www/common/pinpad.js @@ -5,13 +5,28 @@ define([ var Nacl = window.nacl; var create = function (network, proxy, cb) { - if (!network) { return void cb('INVALID_NETWORK'); } - if (!proxy) { return void cb('INVALID_PROXY'); } + if (!network) { + window.setTimeout(function () { + cb('INVALID_NETWORK'); + }); + return; + } + if (!proxy) { + window.setTimeout(function () { + cb('INVALID_PROXY'); + }); + return; + } var edPrivate = proxy.edPrivate; var edPublic = proxy.edPublic; - if (!(edPrivate && edPublic)) { return void cb('INVALID_KEYS'); } + if (!(edPrivate && edPublic)) { + window.setTimeout(function () { + cb('INVALID_KEYS'); + }); + return; + } Rpc.create(network, edPrivate, edPublic, function (e, rpc) { if (e) { return void cb(e); } From 9a46b58c8561bbcf0088b500ccac2f8fc6122ef6 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 12 Apr 2017 16:03:34 +0200 Subject: [PATCH 05/53] deprecate this 90 days after f-release --- www/poll/main.js | 1 + 1 file changed, 1 insertion(+) diff --git a/www/poll/main.js b/www/poll/main.js index 7225bee7f..b3265531e 100644 --- a/www/poll/main.js +++ b/www/poll/main.js @@ -25,6 +25,7 @@ define([ var secret = Cryptpad.getSecrets(); var readOnly = secret.keys && !secret.keys.editKeyStr; + // DEPRECATE_F if (!secret.keys) { secret.keys = secret.key; } From 401936a91ed5bbcee302cd0efc49a802ed8382c9 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 12 Apr 2017 16:09:05 +0200 Subject: [PATCH 06/53] move singly-used css file out of /common/ --- www/examples/render/index.html | 2 +- www/{common => examples/render}/render-sd.css | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename www/{common => examples/render}/render-sd.css (100%) diff --git a/www/examples/render/index.html b/www/examples/render/index.html index 24e7e41b5..56112aab3 100644 --- a/www/examples/render/index.html +++ b/www/examples/render/index.html @@ -3,7 +3,7 @@ - + diff --git a/www/poll/poll.css b/www/poll/poll.css new file mode 100644 index 000000000..321121b59 --- /dev/null +++ b/www/poll/poll.css @@ -0,0 +1,357 @@ +html, +body { + width: 100%; + height: 100%; + margin: 0px; + padding: 0px; + border: 0px; +} +.cryptpad-toolbar h2 { + font: normal normal normal 12px Arial, Helvetica, Tahoma, Verdana, Sans-Serif; + color: #000; + line-height: auto; +} +.cryptpad-toolbar { + display: inline-block; +} +.realtime { + display: block; + max-height: 100%; + max-width: 100%; +} +.realtime input[type="text"] { + height: 1em; + margin: 0px; +} +.text-cell input[type="text"] { + width: 400px; +} +input[type="text"][disabled], +textarea[disabled] { + background-color: transparent; + font: white; + border: 0px; +} +table#table { + margin: 0px; +} +#tableContainer { + position: relative; + padding: 29px; + padding-right: 79px; +} +#tableContainer button { + height: 2rem; + display: none; +} +#publish { + display: none; +} +#publish, +#admin { + margin-top: 15px; + margin-bottom: 15px; +} +#create-user { + position: absolute; + display: inline-block; + /*left: 0px;*/ + top: 55px; + width: 50px; + overflow: hidden; +} +#create-option { + width: 50px; +} +#tableScroll { + overflow-y: hidden; + overflow-x: auto; + margin-left: calc(30% - 50px + 29px); + max-width: 70%; + width: auto; + display: inline-block; +} +#description { + padding: 15px; + margin: auto; + min-width: 80%; + width: 80%; + min-height: 5em; + font-size: 20px; + font-weight: bold; +} +#description[disabled] { + resize: none; + color: #000; + border: 1px solid #444; +} +#commit { + width: 100%; +} +#howItWorks { + width: 80%; + margin: auto; +} +div.upper { + width: 80%; + margin: auto; +} +table { + border-collapse: collapse; + border-spacing: 0; + margin: 20px; +} +tbody { + border: 1px solid #555; +} +tbody tr { + text-align: center; +} +tbody tr:first-of-type th { + font-size: 20px; + border-top: 0px; + font-weight: bold; + padding: 10px; + text-decoration: underline; +} +tbody tr:first-of-type th.table-refresh { + color: #46E981; + text-decoration: none; + cursor: pointer; +} +tbody tr:nth-child(odd) { + background-color: #ffffff; +} +tbody tr th:first-of-type { + border-left: 0px; +} +tbody tr th { + box-sizing: border-box; + border: 1px solid #555; +} +tbody tr th, +tbody tr td { + color: #555; +} +tbody tr th.remove, +tbody tr td.remove { + cursor: pointer; +} +tbody tr th:last-child { + border-right: 0px; +} +tbody td { + border-right: 1px solid #555; + padding: 12px; + padding-top: 0px; + padding-bottom: 0px; +} +tbody td:last-child { + border-right: none; +} +form.realtime, +div.realtime { + padding: 0px; + margin: 0px; +} +form.realtime > textarea, +div.realtime > textarea { + width: 50%; + height: 15vh; +} +form.realtime table, +div.realtime table { + border-collapse: collapse; + width: calc(100% - 1px); +} +form.realtime table tr td:first-child, +div.realtime table tr td:first-child { + position: absolute; + left: 29px; + top: auto; + width: calc(30% - 50px); +} +form.realtime table tr td, +div.realtime table tr td { + padding: 0px; + margin: 0px; +} +form.realtime table tr td div.text-cell, +div.realtime table tr td div.text-cell { + padding: 0px; + margin: 0px; + height: 100%; +} +form.realtime table tr td div.text-cell input, +div.realtime table tr td div.text-cell input { + width: 80%; + width: 90%; + height: 100%; + border: 0px; +} +form.realtime table tr td div.text-cell input[disabled], +div.realtime table tr td div.text-cell input[disabled] { + background-color: transparent; + color: #000; + font-weight: bold; +} +form.realtime table tr td.checkbox-cell, +div.realtime table tr td.checkbox-cell { + margin: 0px; + padding: 0px; + height: 100%; + min-width: 150px; +} +form.realtime table tr td.checkbox-cell div.checkbox-contain, +div.realtime table tr td.checkbox-cell div.checkbox-contain { + display: inline-block; + height: 100%; + width: 100%; + position: relative; +} +form.realtime table tr td.checkbox-cell div.checkbox-contain label, +div.realtime table tr td.checkbox-cell div.checkbox-contain label { + background-color: transparent; + display: block; + position: absolute; + top: 0px; + left: 0px; + height: 100%; + width: 100%; +} +form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable), +div.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) { + display: none; +} +form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover, +div.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover { + font-weight: bold; + background-color: #FA5858; + color: #000; + display: block; +} +form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover:after, +div.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover:after { + height: 100%; +} +form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover:after, +div.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover:after { + content: "✖"; +} +form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover.yes, +div.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover.yes { + background-color: #46E981; +} +form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover.yes:after, +div.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover.yes:after { + content: "✔"; +} +form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover.uncommitted, +div.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover.uncommitted { + background: #ddd; +} +form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover.mine, +div.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover.mine { + display: none; +} +form.realtime table input[type="text"], +div.realtime table input[type="text"] { + height: auto; + border: 1px solid #fff; + width: 80%; +} +form.realtime table thead td, +div.realtime table thead td { + padding: 0px 5px; + background: #aaa; + border-radius: 20px 20px 0 0; + text-align: center; +} +form.realtime table thead td input[type="text"], +div.realtime table thead td input[type="text"] { + width: 100%; + box-sizing: border-box; +} +form.realtime table thead td input[type="text"][disabled], +div.realtime table thead td input[type="text"][disabled] { + color: #000; + padding: 1px 5px; + border: none; +} +form.realtime table tbody .text-cell, +div.realtime table tbody .text-cell { + background: #aaa; +} +form.realtime table tbody .text-cell input[type="text"], +div.realtime table tbody .text-cell input[type="text"] { + width: calc(100% - 50px); +} +form.realtime table tbody .text-cell .edit, +div.realtime table tbody .text-cell .edit { + float: right; + margin: 0 10px 0 0; +} +form.realtime table tbody .text-cell .remove, +div.realtime table tbody .text-cell .remove { + float: left; + margin: 0 0 0 10px; +} +form.realtime table tbody td label, +div.realtime table tbody td label { + border: 0.5px solid #555; +} +form.realtime table .edit, +div.realtime table .edit { + color: #000; + cursor: pointer; + float: left; + margin-left: 10px; +} +form.realtime table .remove, +div.realtime table .remove { + float: right; + margin-right: 10px; +} +form.realtime table thead tr th input[type="text"][disabled], +div.realtime table thead tr th input[type="text"][disabled] { + background-color: transparent; + color: #555; + font-weight: bold; +} +form.realtime table thead tr th .remove, +div.realtime table thead tr th .remove { + cursor: pointer; + font-size: 20px; +} +form.realtime table tfoot tr, +div.realtime table tfoot tr { + border: none; +} +form.realtime table tfoot tr td, +div.realtime table tfoot tr td { + border: none; + text-align: center; +} +form.realtime table tfoot tr td .save, +div.realtime table tfoot tr td .save { + padding: 15px; + border-top-left-radius: 5px; + border-top-right-radius: 5px; +} +form.realtime #adduser, +div.realtime #adduser, +form.realtime #addoption, +div.realtime #addoption { + color: #46E981; + border: 1px solid #46E981; + padding: 15px; + cursor: pointer; +} +form.realtime #adduser, +div.realtime #adduser { + border-top-left-radius: 5px; +} +form.realtime #addoption, +div.realtime #addoption { + border-bottom-left-radius: 5px; +} diff --git a/www/poll/poll.less b/www/poll/poll.less new file mode 100644 index 000000000..7292b0e15 --- /dev/null +++ b/www/poll/poll.less @@ -0,0 +1,387 @@ +@import "../../customize.dist/src/less/variables.less"; +@import "../../customize.dist/src/less/mixins.less"; + +@poll-th-bg: #aaa; +@poll-td-bg: #aaa; +@poll-border-color: #555; +@poll-cover-color: #000; +@poll-fg: #000; + +html, body { + width: 100%; + height: 100%; + margin: 0px; + padding: 0px; + border: 0px; +} + +.cryptpad-toolbar h2 { + font: normal normal normal 12px Arial, Helvetica, Tahoma, Verdana, Sans-Serif; + color: #000; + line-height: auto; +} +.cryptpad-toolbar { + display: inline-block; +} +.realtime { + display: block; + max-height: 100%; + max-width: 100%; +} + +.realtime input[type="text"] { + height: 1em; + margin: 0px; +} +.text-cell input[type="text"] { + width: 400px; +} + +input[type="text"][disabled], textarea[disabled] { + background-color: transparent; + font: white; + border: 0px; +} +table#table { + margin: 0px; +} +#tableContainer { + position: relative; + padding: 29px; + padding-right: 79px; +} +#tableContainer button { + height: 2rem; + display: none; +} +#publish { + display: none; +} +#publish, #admin { + margin-top: 15px; + margin-bottom: 15px; +} +#create-user { + position: absolute; + display: inline-block; + /*left: 0px;*/ + top: 55px; + width: 50px; + overflow: hidden; +} +#create-option { + width: 50px; +} +#tableScroll { + overflow-y: hidden; + overflow-x: auto; + margin-left: calc(~"30% - 50px + 29px"); + max-width: 70%; + width: auto; + display: inline-block; +} +#description { + padding: 15px; + margin: auto; + + min-width: 80%; + width: 80%; + min-height: 5em; + font-size: 20px; + font-weight: bold; + +} +#description[disabled] { + resize: none; + color: #000; + border: 1px solid #444; +} + +#commit { + width: 100%; +} +#howItWorks { + width: 80%; + margin: auto; +} +div.upper { + width: 80%; + margin: auto; +} + +// from cryptpad.less + +table { + border-collapse: collapse; + border-spacing: 0; + margin: 20px; +} +tbody { + border: 1px solid @poll-border-color; + tr { + text-align: center; + &:first-of-type th{ + font-size: 20px; + border-top: 0px; + font-weight: bold; + padding: 10px; + text-decoration: underline; + &.table-refresh { + color: @cp-green; + text-decoration: none; + cursor: pointer; + } + + } + &:nth-child(odd) { + background-color: @light-base; + } + th:first-of-type { + border-left: 0px; + } + th { + box-sizing: border-box; + border: 1px solid @poll-border-color; + } + th, td { + color: @fore; + + &.remove { + cursor: pointer; + } + } + th:last-child { + border-right: 0px; + } + } + + td { + border-right: 1px solid @poll-border-color; + padding: 12px; + padding-top: 0px; + padding-bottom: 0px; + &:last-child { + border-right: none; + } + } +} + +form.realtime, div.realtime { + > input { + &[type="text"] { + + } + } + > textarea { + width: 50%; + height: 15vh; + } + + padding: 0px; + margin: 0px; + + table { + border-collapse: collapse; + width: ~"calc(100% - 1px)"; + tr { + td:first-child { + position:absolute; + left: 29px; + top: auto; + width: ~"calc(30% - 50px)"; + } + td { + padding: 0px; + margin: 0px; + + div.text-cell { + padding: 0px; + margin: 0px; + height: 100%; + + input { + width: 80%; + width: 90%; + height: 100%; + border: 0px; + &[disabled] { + background-color: transparent; + color: @poll-fg; + font-weight: bold; + } + } + } + + &.checkbox-cell { + margin: 0px; + padding: 0px; + height: 100%; + min-width: 150px; + + div.checkbox-contain { + display: inline-block; + height: 100%; + width: 100%; + position: relative; + + label { + background-color: transparent; + display: block; + position: absolute; + top: 0px; + left: 0px; + height: 100%; + width: 100%; + } + + input { + &[type="checkbox"] { + &:not(.editable) { + display: none; + + ~ .cover { + display: block; + font-weight: bold; + + background-color: @cp-red; + color: @poll-cover-color; + + &:after { + height: 100%; + } + + &:after { content: "✖"; } + + display: block; + &.yes { + background-color: @cp-green; + &:after { content: "✔"; } + } + + &.uncommitted { + background: #ddd; + } + + + &.mine { + display: none; + } + } + } + } + } + } + } + } + } + + input { + &[type="text"] { + height: auto; + border: 1px solid @base; + width: 80%; + } + } + thead { + td { + padding: 0px 5px; + background: @poll-th-bg; + border-radius: 20px 20px 0 0; + text-align: center; + input { + &[type="text"] { + width: 100%; + box-sizing: border-box; + &[disabled] { + color: @poll-fg; + padding: 1px 5px; + border: none; + } + } + } + } + } + + tbody { + .text-cell { + background: @poll-td-bg; + //border-radius: 20px 0 0 20px; + input[type="text"] { + width: ~"calc(100% - 50px)"; + } + .edit { + float:right; + margin: 0 10px 0 0; + } + .remove { + float: left; + margin: 0 0 0 10px; + } + } + td { + label { + border: .5px solid @poll-border-color; + } + } + } + .edit { + color: @poll-cover-color; + cursor: pointer; + float: left; + margin-left: 10px; + } + + .remove { + float: right; + margin-right: 10px; + } + + thead { + tr { + th { + input[type="text"][disabled] { + background-color: transparent; + color: @fore; + font-weight: bold; + } + .remove { + cursor: pointer; + font-size: 20px; + } + } + } + } + tbody { + tr { + td { + + } + } + } + tfoot { + tr { + border: none; + td { + border: none; + text-align: center; + .save { + padding: 15px; + border-top-left-radius: 5px; + border-top-right-radius: 5px; + } + } + } + } + } + + #adduser, + #addoption { + color: @cp-green; + border: 1px solid @cp-green; + padding: 15px; + cursor: pointer; + } + + #adduser { .top-left; } + #addoption { .bottom-left; } +} From 607d9652f55f3f42e4927646657f5d7536d0dfb9 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 13 Apr 2017 14:48:15 +0200 Subject: [PATCH 18/53] jshint compliance --- www/common/cryptpad-common.js | 37 ++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 9bf6a310e..2e78da45d 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -27,24 +27,6 @@ load pinpad dynamically only after you know that it will be needed */ Clipboard: Clipboard }; - var feedback = common.feedback = function (action) { - if (!action) { return; } - try { - if (!getStore().getProxy().proxy.allowUserFeedback) { return; } - } catch (e) { return void console.error(e); } - - var href = '/common/feedback.html?' + action + '=' + (+new Date()); - $.ajax({ - type: "HEAD", - url: href, - }); - }; - - var reportAppUsage = common.reportAppUsage = function () { - var pattern = window.location.pathname.split('/') - .filter(function (x) { return x; }).join('.'); - feedback(pattern); - }; // constants var userHashKey = common.userHashKey = 'User_hash'; @@ -105,6 +87,25 @@ load pinpad dynamically only after you know that it will be needed */ return; }; + var feedback = common.feedback = function (action) { + if (!action) { return; } + try { + if (!getStore().getProxy().proxy.allowUserFeedback) { return; } + } catch (e) { return void console.error(e); } + + var href = '/common/feedback.html?' + action + '=' + (+new Date()); + $.ajax({ + type: "HEAD", + url: href, + }); + }; + + var reportAppUsage = common.reportAppUsage = function () { + var pattern = window.location.pathname.split('/') + .filter(function (x) { return x; }).join('.'); + feedback(pattern); + }; + var getUid = common.getUid = function () { if (store) { if (store.getProxy() && store.getProxy().proxy) { From eb2a3c1bbfbed2efc22d3e6bc6c7bbc5bb601ee7 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 13 Apr 2017 15:04:17 +0200 Subject: [PATCH 19/53] Fix lint errors --- www/common/userObject.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/www/common/userObject.js b/www/common/userObject.js index d9669c408..c69be8de4 100644 --- a/www/common/userObject.js +++ b/www/common/userObject.js @@ -179,8 +179,6 @@ define([ // FIND - var compareFiles = function (fileA, fileB) { return fileA === fileB; }; - var findElement = function (root, pathInput) { if (!pathInput) { error("Invalid path:\n", pathInput, "\nin root\n", root); @@ -472,14 +470,14 @@ define([ // Move to Trash if (isPathIn(newParentPath, [TRASH])) { if (!elementPath || elementPath.length < 2 || elementPath[0] === TRASH) { - debug("Can't move an element from the trash to the trash: ", path); + debug("Can't move an element from the trash to the trash: ", elementPath); return; } var key = elementPath[elementPath.length - 1]; - var name = isPathIn(elementPath, ['hrefArray']) ? getTitle(element) : key; + var elName = isPathIn(elementPath, ['hrefArray']) ? getTitle(element) : key; var parentPath = elementPath.slice(); parentPath.pop(); - pushToTrash(name, element, parentPath); + pushToTrash(elName, element, parentPath); return true; } // Move to hrefArray @@ -646,7 +644,7 @@ define([ files[TRASH][obj.name].splice(idx, 1); }); }; - var deleteMultiplePermanently = function (paths) { + var deleteMultiplePermanently = function (paths, nocheck) { var hrefPaths = paths.filter(function(x) { return isPathIn(x, ['hrefArray']); }); var rootPaths = paths.filter(function(x) { return isPathIn(x, [ROOT]); }); var trashPaths = paths.filter(function(x) { return isPathIn(x, [TRASH]); }); @@ -689,10 +687,12 @@ define([ }); deleteMultipleTrashRoot(trashRoot); - checkDeletedFiles(); + // In some cases, we want to remove pads from a location without removing them from + // FILES_DATA (replaceHref) + if (!nocheck) { checkDeletedFiles(); } }; - var deletePath = exp.delete = function (paths, cb) { - deleteMultiplePermanently(paths); + var deletePath = exp.delete = function (paths, cb, nocheck) { + deleteMultiplePermanently(paths, nocheck); if (typeof cb === "function") { cb(); } }; var emptyTrash = exp.emptyTrash = function (cb) { @@ -754,7 +754,7 @@ define([ var allInTrash = true; paths.forEach(function (p) { if (p[0] === TRASH) { - removeFromTrash(p, null, true); // 3rd parameter means skip "checkDeletedFiles" + exp.delete(p, null, true); // 3rd parameter means skip "checkDeletedFiles" return; } else { allInTrash = false; From 7434dbcb0f97ba94619868ae4002c89b40d030ae Mon Sep 17 00:00:00 2001 From: Pierre Bondoerffer Date: Thu, 13 Apr 2017 15:27:37 +0200 Subject: [PATCH 20/53] what i have --- www/poll/main.js | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/www/poll/main.js b/www/poll/main.js index b3265531e..41295caa5 100644 --- a/www/poll/main.js +++ b/www/poll/main.js @@ -333,6 +333,11 @@ define([ } else if (isEdit) { unlockRow(id, function () { change(); + + setTimeout(function() { + var $newest = $('input[data-rt-id="' + id + '"]'); + $newest.focus(); + }); }); } } else if (type === 'col') { @@ -346,6 +351,11 @@ define([ } else if (isEdit) { unlockColumn(id, function () { change(); + + setTimeout(function() { + var $newest = $('[data-rt-id="' + id + '"]'); + $newest.focus(); + }); }); } } else if (type === 'cell') { @@ -547,14 +557,14 @@ define([ var $table = APP.$table = $(Render.asHTML(displayedObj, null, colsOrder, readOnly)); var $createRow = APP.$createRow = $('#create-option').click(function () { //console.error("BUTTON CLICKED! LOL"); - Render.createRow(proxy, function () { - change(); - var order = APP.proxy.table.rowsOrder; + Render.createRow(proxy, function (empty, id) { + unlockRow(id, function () { + change(); - var last = order[order.length - 1]; - var $newest = $('[data-rt-id="' + last + '"]'); - $newest.val(''); - window.setTimeout(change); + setTimeout(function() { + $('.edit[data-rt-id="' + id + '"]').click(); + }); + }); }); }); From ea5301be134d8891ee4d20c6995577ca64cd03c6 Mon Sep 17 00:00:00 2001 From: Pierre Bondoerffer Date: Thu, 13 Apr 2017 16:31:57 +0200 Subject: [PATCH 21/53] poll improved(tm) --- www/poll/main.js | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/www/poll/main.js b/www/poll/main.js index 41295caa5..ff90adcfd 100644 --- a/www/poll/main.js +++ b/www/poll/main.js @@ -211,7 +211,7 @@ define([ }; /* Any time the realtime object changes, call this function */ - var change = function (o, n, path, throttle) { + var change = function (o, n, path, throttle, cb) { if (path && !Cryptpad.isArray(path)) { return; } @@ -262,6 +262,11 @@ define([ Render.updateTable(table, displayedObj2, conf); updateDisplayedTable(); setFocus(f); + if (typeof(cb) === "function") + { + console.log("change cb"); + cb(); + } }; if (throttle) { @@ -273,7 +278,9 @@ define([ return; } - window.setTimeout(updateTable); + window.setTimeout(function() { + updateTable(); + }); }; var getRealtimeId = function (input) { @@ -332,11 +339,8 @@ define([ }); } else if (isEdit) { unlockRow(id, function () { - change(); - - setTimeout(function() { - var $newest = $('input[data-rt-id="' + id + '"]'); - $newest.focus(); + change(null, null, null, null, function() { + $('input[data-rt-id="' + id + '"]').focus(); }); }); } @@ -350,11 +354,8 @@ define([ }); } else if (isEdit) { unlockColumn(id, function () { - change(); - - setTimeout(function() { - var $newest = $('[data-rt-id="' + id + '"]'); - $newest.focus(); + change(null, null, null, null, function() { + $('input[data-rt-id="' + id + '"]').focus(); }); }); } @@ -365,8 +366,8 @@ define([ } }; - var hideInputs = function (e) { - if ($(e.target).is('[type="text"]')) { + var hideInputs = function (e, isKeyup) { + if (!isKeyup && $(e.target).is('[type="text"]')) { return; } $('.lock[data-rt-id!="' + APP.userid + '"]').html(lockHTML); @@ -400,6 +401,9 @@ define([ switch (nodeName) { case 'INPUT': handleInput(target); + if (isKeyup && (e.keyCode === 13 || e.keyCode === 27)) { + hideInputs(e, isKeyup); + } break; case 'SPAN': //case 'LABEL': @@ -558,19 +562,17 @@ define([ var $createRow = APP.$createRow = $('#create-option').click(function () { //console.error("BUTTON CLICKED! LOL"); Render.createRow(proxy, function (empty, id) { - unlockRow(id, function () { - change(); - - setTimeout(function() { - $('.edit[data-rt-id="' + id + '"]').click(); - }); + change(null, null, null, null, function() { + $('.edit[data-rt-id="' + id + '"]').click(); }); }); }); var $createCol = APP.$createCol = $('#create-user').click(function () { - Render.createColumn(proxy, function () { - change(); + Render.createColumn(proxy, function (empty, id) { + change(null, null, null, null, function() { + $('.edit[data-rt-id="' + id + '"]').click(); + }); }); }); From 2ad0a65b71e38fa588a3f678378b4b0dd2a921fa Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 13 Apr 2017 16:42:26 +0200 Subject: [PATCH 22/53] Remove shortcuts that override browser actions --- customize.dist/ckeditor-config.js | 20 ++++++++++++++++++++ www/code/main.js | 2 +- www/slide/main.js | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/customize.dist/ckeditor-config.js b/customize.dist/ckeditor-config.js index 38e1165e6..c1659300c 100644 --- a/customize.dist/ckeditor-config.js +++ b/customize.dist/ckeditor-config.js @@ -15,6 +15,26 @@ CKEDITOR.editorConfig = function( config ) { // jshint ignore:line config.fontSize_defaultLabel = '16px'; config.contentsCss = '/customize/ckeditor-contents.css'; + config.keystrokes = [ + [ CKEDITOR.ALT + 121 /*F10*/, 'toolbarFocus' ], + [ CKEDITOR.ALT + 122 /*F11*/, 'elementsPathFocus' ], + + [ CKEDITOR.SHIFT + 121 /*F10*/, 'contextMenu' ], + + [ CKEDITOR.CTRL + 90 /*Z*/, 'undo' ], + [ CKEDITOR.CTRL + 89 /*Y*/, 'redo' ], + [ CKEDITOR.CTRL + CKEDITOR.SHIFT + 90 /*Z*/, 'redo' ], + + [ CKEDITOR.CTRL + CKEDITOR.SHIFT + 76 /*L*/, 'link' ], + [ CKEDITOR.CTRL + 76 /*L*/, undefined ], + + [ CKEDITOR.CTRL + 66 /*B*/, 'bold' ], + [ CKEDITOR.CTRL + 73 /*I*/, 'italic' ], + [ CKEDITOR.CTRL + 85 /*U*/, 'underline' ], + + [ CKEDITOR.ALT + 109 /*-*/, 'toolbarCollapse' ] + ]; + //skin: 'moono-cryptpad,/pad/themes/moono-cryptpad/' //skin: 'flat,/pad/themes/flat/' //skin: 'moono-lisa,/pad/themes/moono-lisa/' diff --git a/www/code/main.js b/www/code/main.js index bdad4cdb6..fe999c6c0 100644 --- a/www/code/main.js +++ b/www/code/main.js @@ -63,7 +63,7 @@ define([ styleActiveLine : true, search: true, highlightSelectionMatches: {showToken: /\w+/}, - extraKeys: {"Ctrl-Q": function(cm){ cm.foldCode(cm.getCursor()); }}, + extraKeys: {"Shift-Ctrl-R": undefined}, foldGutter: true, gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], mode: "javascript", diff --git a/www/slide/main.js b/www/slide/main.js index 9acc6527e..995d8b767 100644 --- a/www/slide/main.js +++ b/www/slide/main.js @@ -83,7 +83,7 @@ define([ styleActiveLine : true, search: true, highlightSelectionMatches: {showToken: /\w+/}, - extraKeys: {"Ctrl-Q": function(cm){ cm.foldCode(cm.getCursor()); }}, + extraKeys: {"Shift-Ctrl-R": undefined}, foldGutter: true, gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], mode: "javascript", From 81d83897ecc59387dd37a36d6d1fe1f092478d12 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 13 Apr 2017 17:04:15 +0200 Subject: [PATCH 23/53] Rename hash.js --- www/common/{hash.js => common-hash.js} | 0 www/common/cryptpad-common.js | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename www/common/{hash.js => common-hash.js} (100%) diff --git a/www/common/hash.js b/www/common/common-hash.js similarity index 100% rename from www/common/hash.js rename to www/common/common-hash.js diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 2e78da45d..e1e02bf05 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -3,7 +3,7 @@ define([ '/customize/messages.js', '/common/fsStore.js', '/common/common-util.js', - '/common/hash.js', + '/common/common-hash.js', '/bower_components/alertifyjs/dist/js/alertify.js', '/common/clipboard.js', From d483e10e7703ba2410f681ea9a2ef9cff00ea75c Mon Sep 17 00:00:00 2001 From: Pierre Bondoerffer Date: Thu, 13 Apr 2017 17:07:09 +0200 Subject: [PATCH 24/53] poll fixes --- www/poll/main.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/www/poll/main.js b/www/poll/main.js index ff90adcfd..dca194717 100644 --- a/www/poll/main.js +++ b/www/poll/main.js @@ -264,7 +264,6 @@ define([ setFocus(f); if (typeof(cb) === "function") { - console.log("change cb"); cb(); } }; @@ -278,9 +277,7 @@ define([ return; } - window.setTimeout(function() { - updateTable(); - }); + window.setTimeout(updateTable); }; var getRealtimeId = function (input) { @@ -366,8 +363,8 @@ define([ } }; - var hideInputs = function (e, isKeyup) { - if (!isKeyup && $(e.target).is('[type="text"]')) { + var hideInputs = function (e) { + if ($(e.target).is('[type="text"]')) { return; } $('.lock[data-rt-id!="' + APP.userid + '"]').html(lockHTML); @@ -401,9 +398,9 @@ define([ switch (nodeName) { case 'INPUT': handleInput(target); - if (isKeyup && (e.keyCode === 13 || e.keyCode === 27)) { - hideInputs(e, isKeyup); - } + //if (isKeyup && (e.keyCode === 13 || e.keyCode === 27)) { + //hideInputs(e, isKeyup); + //} break; case 'SPAN': //case 'LABEL': From 6b57bb2bbb9aeead0317ae1d6831abd7447cfac5 Mon Sep 17 00:00:00 2001 From: Pierre Bondoerffer Date: Thu, 13 Apr 2017 17:09:31 +0200 Subject: [PATCH 25/53] poll: press enter to validate input --- www/poll/main.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/www/poll/main.js b/www/poll/main.js index dca194717..2573a4f05 100644 --- a/www/poll/main.js +++ b/www/poll/main.js @@ -285,7 +285,7 @@ define([ }; /* Called whenever an event is fired on an input element */ - var handleInput = function (input) { + var handleInput = function (input, isKeyup) { var type = input.type.toLowerCase(); var id = getRealtimeId(input); @@ -363,8 +363,8 @@ define([ } }; - var hideInputs = function (e) { - if ($(e.target).is('[type="text"]')) { + var hideInputs = function (e, isKeyup) { + if (!isKeyup && $(e.target).is('[type="text"]')) { return; } $('.lock[data-rt-id!="' + APP.userid + '"]').html(lockHTML); @@ -397,10 +397,11 @@ define([ switch (nodeName) { case 'INPUT': + if (isKeyup && (e.keyCode === 13 || e.keyCode === 27)) { + hideInputs(e, isKeyup); + return; + } handleInput(target); - //if (isKeyup && (e.keyCode === 13 || e.keyCode === 27)) { - //hideInputs(e, isKeyup); - //} break; case 'SPAN': //case 'LABEL': From 3e421c7289ebd8513a94cae9f4c88d1f39f6bad7 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 13 Apr 2017 17:09:35 +0200 Subject: [PATCH 26/53] Fix lint errors in ckeditor config --- customize.dist/ckeditor-config.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/customize.dist/ckeditor-config.js b/customize.dist/ckeditor-config.js index c1659300c..4c55f67fc 100644 --- a/customize.dist/ckeditor-config.js +++ b/customize.dist/ckeditor-config.js @@ -1,4 +1,5 @@ -CKEDITOR.editorConfig = function( config ) { // jshint ignore:line +/* global CKEDITOR */ +CKEDITOR.editorConfig = function( config ) { var fixThings = false; // https://dev.ckeditor.com/ticket/10907 config.needsBrFiller= fixThings; From 633d60ccd0fa73772c7051c31849cef83530b12d Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 13 Apr 2017 17:19:32 +0200 Subject: [PATCH 27/53] Remove a TODO --- www/common/cryptpad-common.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index e1e02bf05..8a64d66c4 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -1407,8 +1407,6 @@ load pinpad dynamically only after you know that it will be needed */ console.log('RPC handshake complete'); rpc = common.rpc = env.rpc = call; - // TODO check if pin list is up to date - // if not, reset common.arePinsSynced(function (err, yes) { if (!yes) { common.resetPins(function (err, hash) { From 40c06c4515341a45db212c5a993a24f8235c973f Mon Sep 17 00:00:00 2001 From: Pierre Bondoerffer Date: Thu, 13 Apr 2017 17:42:38 +0200 Subject: [PATCH 28/53] Spanish! --- customize.dist/translations/messages.es.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/customize.dist/translations/messages.es.js b/customize.dist/translations/messages.es.js index cfe682c48..e4167ad00 100644 --- a/customize.dist/translations/messages.es.js +++ b/customize.dist/translations/messages.es.js @@ -290,7 +290,7 @@ define(function () { out.fm_categoryError = "No se pudo abrir la categoría seleccionada, mostrando la raíz."; out.settings_userFeedbackHint1 = "CryptPad suministra informaciones muy básicas al servidor, para ayudarnos a mejorar vuestra experiencia."; out.settings_userFeedbackHint2 = "El contenido de tu pad nunca será compartido con el servidor."; - out.settings_userFeedback = "Activar feedback"; // "Disable user feedback" + out.settings_userFeedback = "Activar feedback"; out.settings_anonymous = "No has iniciado sesión. Tus ajustes se aplicarán solo a este navegador."; out.blog = "Blog"; out.initialState = "

Esto es CryptPad, el editor collaborativo en tiempo real zero knowledge.
Lo que escribes aquí es cifrado, con lo cual solo las personas con el enlace pueden accederlo.
Incluso el servido no puede ver lo que escribes.

Lo que ves aquí, lo que escuchas aquí, cuando sales, se queda aquí

 

"; @@ -356,5 +356,24 @@ define(function () { out.register_warning = "Zero Knowledge significa que no podemos recuperar tus datos si pierdes tu contraseña."; out.register_alreadyRegistered = "Este usuario ya existe, ¿iniciar sesión?"; + // 1.4.0 - Easter Bunny + + out.button_newwhiteboard = "Nueva Pizarra"; + out.wrongApp = "No se pudo mostrar el contenido de la sessión en tiempo real en tu navigador. Por favor, actualiza la página."; + out.synced = "Todo está guardado."; + out.saveTemplateButton = "Guardar como plantilla"; + out.saveTemplatePrompt = "Élige un título para la plantilla"; + out.templateSaved = "¡Plantilla guardada!" + out.selectTemplate = "Élige una plantilla o pulsa ESC"; + out.slideOptionsTitle = "Personaliza tus diapositivas"; + out.slideOptionsButton = "Guardar (enter)"; + out.canvas_clear = "Limpiar"; + out.canvas_delete = "Borrar selección"; + out.canvas_disable = "No permitir dibujos"; + out.canvas_enable = "Permitir dibujos"; + out.canvas_width = "Talla"; + out.canvas_opacity = "Opacidad"; + out.settings_publicSigningKey = "Clave de Firma Pública"; + return out; }); From 65e848fd4d729da6d733f88962bb35fd3dbd8c59 Mon Sep 17 00:00:00 2001 From: Pierre Bondoerffer Date: Thu, 13 Apr 2017 17:50:28 +0200 Subject: [PATCH 29/53] linter linted the lints --- customize.dist/translations/messages.es.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/customize.dist/translations/messages.es.js b/customize.dist/translations/messages.es.js index e4167ad00..aafa9bf70 100644 --- a/customize.dist/translations/messages.es.js +++ b/customize.dist/translations/messages.es.js @@ -363,7 +363,7 @@ define(function () { out.synced = "Todo está guardado."; out.saveTemplateButton = "Guardar como plantilla"; out.saveTemplatePrompt = "Élige un título para la plantilla"; - out.templateSaved = "¡Plantilla guardada!" + out.templateSaved = "¡Plantilla guardada!"; out.selectTemplate = "Élige una plantilla o pulsa ESC"; out.slideOptionsTitle = "Personaliza tus diapositivas"; out.slideOptionsButton = "Guardar (enter)"; From 248f88034bab19a46bef681f8fdf517067ee78ed Mon Sep 17 00:00:00 2001 From: Pierre Bondoerffer Date: Thu, 13 Apr 2017 17:56:28 +0200 Subject: [PATCH 30/53] important fixes --- www/poll/main.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/www/poll/main.js b/www/poll/main.js index 2573a4f05..2f182e7de 100644 --- a/www/poll/main.js +++ b/www/poll/main.js @@ -262,8 +262,7 @@ define([ Render.updateTable(table, displayedObj2, conf); updateDisplayedTable(); setFocus(f); - if (typeof(cb) === "function") - { + if (typeof(cb) === "function") { cb(); } }; From 96ff487271259b523802c2286dc6b1d6466a2af2 Mon Sep 17 00:00:00 2001 From: Pierre Bondoerffer Date: Thu, 13 Apr 2017 19:36:04 +0200 Subject: [PATCH 31/53] fix flash of content --- www/poll/main.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/www/poll/main.js b/www/poll/main.js index 2f182e7de..8170f7e9d 100644 --- a/www/poll/main.js +++ b/www/poll/main.js @@ -260,6 +260,9 @@ define([ var displayedObj2 = mergeUncommitted(APP.proxy, APP.uncommitted); var f = getFocus(); Render.updateTable(table, displayedObj2, conf); + APP.proxy.table.rowsOrder.forEach(function (rowId) { + $('input[data-rt-id="' + rowId +'"]').val(APP.proxy.table.rows[rowId] || ''); + }); updateDisplayedTable(); setFocus(f); if (typeof(cb) === "function") { From 50277cb0ae925e545d066b42d303d4c96b3ccf2f Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 13 Apr 2017 19:46:38 +0200 Subject: [PATCH 32/53] don't rely on 'info' in onRemote so we can call it anywhere --- www/code/main.js | 2 +- www/pad/main.js | 6 +++--- www/slide/main.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/www/code/main.js b/www/code/main.js index fe999c6c0..2b6553cf0 100644 --- a/www/code/main.js +++ b/www/code/main.js @@ -646,7 +646,7 @@ define([ return cursor; }; - var onRemote = config.onRemote = function (info) { + var onRemote = config.onRemote = function () { if (initializing) { return; } var scroll = editor.getScrollInfo(); diff --git a/www/pad/main.js b/www/pad/main.js index 4d9cd0244..443463b1d 100644 --- a/www/pad/main.js +++ b/www/pad/main.js @@ -475,12 +475,12 @@ define([ } }; - var onRemote = realtimeOptions.onRemote = function (info) { + var onRemote = realtimeOptions.onRemote = function () { if (initializing) { return; } var oldShjson = stringifyDOM(inner); - var shjson = info.realtime.getUserDoc(); + var shjson = module.realtime.getUserDoc(); // remember where the cursor is cursor.update(); @@ -679,7 +679,7 @@ define([ module.users = info.userList.users; module.realtime = info.realtime; - var shjson = info.realtime.getUserDoc(); + var shjson = module.realtime.getUserDoc(); var newPad = false; if (shjson === '') { newPad = true; } diff --git a/www/slide/main.js b/www/slide/main.js index 995d8b767..5654f43ab 100644 --- a/www/slide/main.js +++ b/www/slide/main.js @@ -840,7 +840,7 @@ define([ return cursor; }; - var onRemote = config.onRemote = function (info) { + var onRemote = config.onRemote = function () { if (initializing) { return; } var scroll = editor.getScrollInfo(); From 520ae822fc54f3c6888ef3d9387430a00be54439 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 13 Apr 2017 19:46:52 +0200 Subject: [PATCH 33/53] correct undefined reference --- www/common/cryptpad-common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index e1e02bf05..4ec0fabae 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -54,7 +54,7 @@ load pinpad dynamically only after you know that it will be needed */ var fixFileName = common.fixFileName = Util.fixFileName; // import hash utilities for export - var createRandomHash = Hash.createRandomHash; + var createRandomHash = common.createRandomHash = Hash.createRandomHash; var parsePadUrl = common.parsePadUrl = Hash.parsePadUrl; var isNotStrongestStored = common.isNotStrongestStored = Hash.isNotStrongestStored; var hrefToHexChannelId = common.hrefToHexChannelId = Hash.hrefToHexChannelId; From f42da4ecd83a674855057e12ae7a66ce31c7b0e8 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 14 Apr 2017 11:40:28 +0200 Subject: [PATCH 34/53] move hashChannelList into common-hash.js --- www/common/common-hash.js | 11 ++++++++- www/common/cryptpad-common.js | 2 +- www/common/pinpad.js | 42 ++++++++++++++++++++++++----------- 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/www/common/common-hash.js b/www/common/common-hash.js index 0c535ab18..034ee5bbb 100644 --- a/www/common/common-hash.js +++ b/www/common/common-hash.js @@ -1,13 +1,23 @@ define([ '/common/common-util.js', '/bower_components/chainpad-crypto/crypto.js', + '/bower_components/tweetnacl/nacl-fast.min.js' ], function (Util, Crypto) { + var Nacl = window.nacl; + var Hash = {}; var uint8ArrayToHex = Util.uint8ArrayToHex; var hexToBase64 = Util.hexToBase64; var base64ToHex = Util.base64ToHex; + // This implementation must match that on the server + // it's used for a checksum + Hash.hashChannelList = function (list) { + return Nacl.util.encodeBase64(Nacl.hash(Nacl.util + .decodeUTF8(JSON.stringify(list)))); + }; + var getEditHashFromKeys = Hash.getEditHashFromKeys = function (chanKey, keys) { if (typeof keys === 'string') { return chanKey + keys; @@ -231,6 +241,5 @@ define([ return hex; }; - return Hash; }); diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 67609e2dc..919177e33 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -726,7 +726,7 @@ load pinpad dynamically only after you know that it will be needed */ if (!pinsReady()) { return void cb ('[RPC_NOT_READY]'); } var list = getCanonicalChannelList(); - var local = rpc.hashChannelList(list); + var local = Hash.hashChannelList(list); rpc.getServerHash(function (e, hash) { if (e) { return void cb(e); } cb(void 0, hash === local); diff --git a/www/common/pinpad.js b/www/common/pinpad.js index aa2cc532f..275a68666 100644 --- a/www/common/pinpad.js +++ b/www/common/pinpad.js @@ -1,9 +1,6 @@ define([ '/common/rpc.js', - '/bower_components/tweetnacl/nacl-fast.min.js' ], function (Rpc) { - var Nacl = window.nacl; - var create = function (network, proxy, cb) { if (!network) { window.setTimeout(function () { @@ -41,21 +38,28 @@ define([ // you can ask the server to pin a particular channel for you exp.pin = function (channels, cb) { + // TODO use isArray if it's safe + if (!channels && channels.length) { + window.setTimeout(function () { + cb('[TypeError] pin expects an array'); + }); + return; + } rpc.send('PIN', channels, cb); }; // you can also ask to unpin a particular channel exp.unpin = function (channels, cb) { + // TODO use isArray if it's safe + if (!channels && channels.length) { + window.setTimeout(function () { + cb('[TypeError] pin expects an array'); + }); + return; + } rpc.send('UNPIN', channels, cb); }; - // This implementation must match that on the server - // it's used for a checksum - exp.hashChannelList = function (list) { - return Nacl.util.encodeBase64(Nacl.hash(Nacl.util - .decodeUTF8(JSON.stringify(list)))); - }; - // ask the server what it thinks your hash is exp.getServerHash = function (cb) { rpc.send('GET_HASH', edPublic, function (e, hash) { @@ -67,8 +71,15 @@ define([ }; // if local and remote hashes don't match, send a reset - exp.reset = function (list, cb) { - rpc.send('RESET', list, function (e, response) { + exp.reset = function (channels, cb) { + // TODO use isArray if it's safe + if (!channels && channels.length) { + window.setTimeout(function () { + cb('[TypeError] pin expects an array'); + }); + return; + } + rpc.send('RESET', channels, function (e, response) { cb(e, response[0]); }); }; @@ -81,7 +92,12 @@ define([ // get the combined size of all channels (in bytes) for all the // channels which the server has pinned for your publicKey exp.getFileListSize = function (cb) { - rpc.send('GET_TOTAL_SIZE', undefined, cb); + rpc.send('GET_TOTAL_SIZE', undefined, function (e, response) { + if (e) { return void cb(e); } + if (response && response.length) { + cb(void 0, response[0]); + } + }); }; cb(e, exp); From 8f4dbcf4c6e7398f6709902cec3c79ae8d005ddd Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 14 Apr 2017 11:41:18 +0200 Subject: [PATCH 35/53] remove getPadTitle --- www/common/cryptpad-common.js | 26 -------------------------- www/poll/main.js | 9 --------- 2 files changed, 35 deletions(-) diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 919177e33..dc903777c 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -562,32 +562,6 @@ load pinpad dynamically only after you know that it will be needed */ }); }; - // STORAGE - var getPadTitle = common.getPadTitle = function (cb) { - var href = window.location.href; - var parsed = parsePadUrl(window.location.href); - var hashSlice = window.location.hash.slice(1,9); // TODO remove - var title = ''; - - getRecentPads(function (err, pads) { - if (err) { - cb(err); - return; - } - pads.some(function (pad) { - var p = parsePadUrl(pad.href); - if (p.hash === parsed.hash && p.type === parsed.type) { - title = pad.title || hashSlice; - return true; - } - }); - - if (title === '') { title = getDefaultName(parsed, pads); } - - cb(void 0, title); - }); - }; - var errorHandlers = []; common.onError = function (h) { if (typeof h !== "function") { return; } diff --git a/www/poll/main.js b/www/poll/main.js index b474d41f2..acd4d0af2 100644 --- a/www/poll/main.js +++ b/www/poll/main.js @@ -781,15 +781,6 @@ define([ } Cryptpad.onDisplayNameChanged(setName); - - Cryptpad.getPadTitle(function (err, title) { - if (err) { - error(err); - debug("Couldn't get pad title"); - return; - } - updateTitle(title || defaultName); - }); }; // don't initialize until the store is ready. From 95789d3cbe5463f014fa4dee105d78626f201507 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 14 Apr 2017 11:41:51 +0200 Subject: [PATCH 36/53] expose rpc for pinned usage --- www/common/cryptpad-common.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index dc903777c..9218c0022 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -735,6 +735,11 @@ load pinpad dynamically only after you know that it will be needed */ }); }; + var getPinnedUsage = common.getPinnedUsage = function (cb) { + if (!pinsReady()) { return void cb('[RPC_NOT_READY]'); } + rpc.getFileListSize(cb); + }; + var createButton = common.createButton = function (type, rightside, data, callback) { var button; var size = "17px"; From e10901edb28d9e17e3804946b21c2b5706fa3ec7 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 14 Apr 2017 12:09:00 +0200 Subject: [PATCH 37/53] begin to move interface code out of cryptpad-common --- www/common/common-interface.js | 134 ++++++++++++++++++++++++++++++++ www/common/cryptpad-common.js | 137 ++++----------------------------- 2 files changed, 148 insertions(+), 123 deletions(-) create mode 100644 www/common/common-interface.js diff --git a/www/common/common-interface.js b/www/common/common-interface.js new file mode 100644 index 000000000..e23756cec --- /dev/null +++ b/www/common/common-interface.js @@ -0,0 +1,134 @@ +define([ + '/customize/messages.js', + '/common/common-util.js', + '/customize/application_config.js', + '/bower_components/alertifyjs/dist/js/alertify.js', + '/bower_components/jquery/dist/jquery.min.js', +], function (Messages, Util, AppConfig, Alertify) { + var $ = window.jQuery; + + var UI = {}; + + /* + * Alertifyjs + */ + UI.Alertify = Alertify; + + // set notification timeout + Alertify._$$alertify.delay = AppConfig.notificationTimeout || 5000; + + var findCancelButton = UI.findCancelButton = function () { + return $('button.cancel'); + }; + + var findOKButton = UI.findOKButton = function () { + return $('button.ok'); + }; + + var listenForKeys = UI.listenForKeys = function (yes, no) { + var handler = function (e) { + switch (e.which) { + case 27: // cancel + if (typeof(no) === 'function') { no(e); } + no(); + break; + case 13: // enter + if (typeof(yes) === 'function') { yes(e); } + break; + } + }; + + $(window).keyup(handler); + return handler; + }; + + var stopListening = UI.stopListening = function (handler) { + $(window).off('keyup', handler); + }; + + UI.alert = function (msg, cb, force) { + cb = cb || function () {}; + if (force !== true) { msg = Util.fixHTML(msg); } + var close = function (e) { + findOKButton().click(); + }; + var keyHandler = listenForKeys(close, close); + Alertify.alert(msg, function (ev) { + cb(ev); + stopListening(keyHandler); + }); + window.setTimeout(function () { + findOKButton().focus(); + }); + }; + + UI.prompt = function (msg, def, cb, opt, force) { + opt = opt || {}; + cb = cb || function () {}; + if (force !== true) { msg = Util.fixHTML(msg); } + + var keyHandler = listenForKeys(function (e) { // yes + findOKButton().click(); + }, function (e) { // no + findCancelButton().click(); + }); + + Alertify + .defaultValue(def || '') + .okBtn(opt.ok || Messages.okButton || 'OK') + .cancelBtn(opt.cancel || Messages.cancelButton || 'Cancel') + .prompt(msg, function (val, ev) { + cb(val, ev); + stopListening(keyHandler); + }, function (ev) { + cb(null, ev); + stopListening(keyHandler); + }); + }; + + UI.confirm = function (msg, cb, opt, force, styleCB) { + opt = opt || {}; + cb = cb || function () {}; + if (force !== true) { msg = Util.fixHTML(msg); } + + var keyHandler = listenForKeys(function (e) { + findOKButton().click(); + }, function (e) { + findCancelButton().click(); + }); + + Alertify + .okBtn(opt.ok || Messages.okButton || 'OK') + .cancelBtn(opt.cancel || Messages.cancelButton || 'Cancel') + .confirm(msg, function () { + cb(true); + stopListening(keyHandler); + }, function () { + cb(false); + stopListening(keyHandler); + }); + + window.setTimeout(function () { + var $ok = findOKButton(); + var $cancel = findCancelButton(); + if (opt.okClass) { $ok.addClass(opt.okClass); } + if (opt.cancelClass) { $cancel.addClass(opt.cancelClass); } + if (opt.reverseOrder) { + $ok.insertBefore($ok.prev()); + } + if (typeof(styleCB) === 'function') { + styleCB($ok.closest('.dialog')); + } + }, 0); + }; + + UI.log = function (msg) { + Alertify.success(Util.fixHTML(msg)); + }; + + UI.warn = function (msg) { + Alertify.error(Util.fixHTML(msg)); + }; + + return UI; +}); diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 9218c0022..75f7dad2d 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -4,15 +4,14 @@ define([ '/common/fsStore.js', '/common/common-util.js', '/common/common-hash.js', + '/common/common-interface.js', - '/bower_components/alertifyjs/dist/js/alertify.js', '/common/clipboard.js', - '/common/pinpad.js', /* TODO -load pinpad dynamically only after you know that it will be needed */ + '/common/pinpad.js', '/customize/application_config.js', '/bower_components/jquery/dist/jquery.min.js', -], function (Config, Messages, Store, Util, Hash, Alertify, Clipboard, Pinpad, AppConfig) { +], function (Config, Messages, Store, Util, Hash, UI, Clipboard, Pinpad, AppConfig) { /* 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,7 +22,6 @@ load pinpad dynamically only after you know that it will be needed */ var common = window.Cryptpad = { Messages: Messages, - Alertify: Alertify, Clipboard: Clipboard }; @@ -42,6 +40,16 @@ load pinpad dynamically only after you know that it will be needed */ var store; var rpc; + // import UI elements + var findCancelButton = common.findCancelButton = UI.findCancelButton; + var findOKButton = common.findOKButton = UI.findOKButton; + var listenForKeys = common.listenForKeys = UI.listenForKeys; + var stopListening = common.stopListening = UI.stopListening; + common.prompt = UI.prompt; + common.confirm = UI.confirm; + common.log = UI.log; + common.warn = UI.warn; + // import common utilities for export var find = common.find = Util.find; var fixHTML = common.fixHTML = Util.fixHTML; @@ -1180,121 +1188,6 @@ load pinpad dynamically only after you know that it will be needed */ return $userAdmin; }; - /* - * Alertifyjs - */ - var findCancelButton = common.findCancelButton = function () { - return $('button.cancel'); - }; - - var findOKButton = common.findOKButton = function () { - return $('button.ok'); - }; - - var listenForKeys = common.listenForKeys = function (yes, no) { - var handler = function (e) { - switch (e.which) { - case 27: // cancel - if (typeof(no) === 'function') { no(e); } - no(); - break; - case 13: // enter - if (typeof(yes) === 'function') { yes(e); } - break; - } - }; - - $(window).keyup(handler); - return handler; - }; - - var stopListening = common.stopListening = function (handler) { - $(window).off('keyup', handler); - }; - - common.alert = function (msg, cb, force) { - cb = cb || function () {}; - if (force !== true) { msg = fixHTML(msg); } - var close = function (e) { - findOKButton().click(); - }; - var keyHandler = listenForKeys(close, close); - Alertify.alert(msg, function (ev) { - cb(ev); - stopListening(keyHandler); - }); - window.setTimeout(function () { - findOKButton().focus(); - }); - }; - - common.prompt = function (msg, def, cb, opt, force) { - opt = opt || {}; - cb = cb || function () {}; - if (force !== true) { msg = fixHTML(msg); } - - var keyHandler = listenForKeys(function (e) { // yes - findOKButton().click(); - }, function (e) { // no - findCancelButton().click(); - }); - - Alertify - .defaultValue(def || '') - .okBtn(opt.ok || Messages.okButton || 'OK') - .cancelBtn(opt.cancel || Messages.cancelButton || 'Cancel') - .prompt(msg, function (val, ev) { - cb(val, ev); - stopListening(keyHandler); - }, function (ev) { - cb(null, ev); - stopListening(keyHandler); - }); - }; - - common.confirm = function (msg, cb, opt, force, styleCB) { - opt = opt || {}; - cb = cb || function () {}; - if (force !== true) { msg = fixHTML(msg); } - - var keyHandler = listenForKeys(function (e) { - findOKButton().click(); - }, function (e) { - findCancelButton().click(); - }); - - Alertify - .okBtn(opt.ok || Messages.okButton || 'OK') - .cancelBtn(opt.cancel || Messages.cancelButton || 'Cancel') - .confirm(msg, function () { - cb(true); - stopListening(keyHandler); - }, function () { - cb(false); - stopListening(keyHandler); - }); - - window.setTimeout(function () { - var $ok = findOKButton(); - var $cancel = findCancelButton(); - if (opt.okClass) { $ok.addClass(opt.okClass); } - if (opt.cancelClass) { $cancel.addClass(opt.cancelClass); } - if (opt.reverseOrder) { - $ok.insertBefore($ok.prev()); - } - if (typeof(styleCB) === 'function') { - styleCB($ok.closest('.dialog')); - } - }, 0); - }; - - common.log = function (msg) { - Alertify.success(fixHTML(msg)); - }; - - common.warn = function (msg) { - Alertify.error(fixHTML(msg)); - }; /* * spinner @@ -1351,7 +1244,7 @@ load pinpad dynamically only after you know that it will be needed */ $(function() { // Race condition : if document.body is undefined when alertify.js is loaded, Alertify // won't work. We have to reset it now to make sure it uses a correct "body" - Alertify.reset(); + UI.Alertify.reset(); // Load the new pad when the hash has changed var oldHash = document.location.hash.slice(1); @@ -1425,7 +1318,5 @@ load pinpad dynamically only after you know that it will be needed */ Messages._applyTranslation(); }); - Alertify._$$alertify.delay = AppConfig.notificationTimeout || 5000; - return common; }); From a4157b9908ec8a65cf9b9461742a2a782c1f82e6 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 14 Apr 2017 12:14:10 +0200 Subject: [PATCH 38/53] remove more unused functions --- www/common/cryptpad-common.js | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 75f7dad2d..68d5204fb 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -224,14 +224,6 @@ define([ var isArray = common.isArray = $.isArray; - var truncate = common.truncate = function (text, len) { - if (typeof(text) === 'string' && text.length > len) { - return text.slice(0, len) + '…'; - } - return text; - }; - - /* * localStorage formatting */ @@ -313,15 +305,6 @@ define([ }); }; - var isNameAvailable = function (title, parsed, pads) { - return !pads.some(function (pad) { - // another pad is already using that title - if (pad.title === title) { - return true; - } - }); - }; - // Create untitled documents when no name is given var getDefaultName = common.getDefaultName = function (parsed) { var type = parsed.type; From f694a81a5c37ebb11d39b9aadb7df3841717fbd2 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 14 Apr 2017 12:25:32 +0200 Subject: [PATCH 39/53] move more interface code out of cryptpad-common --- www/common/common-interface.js | 87 +++++++++++++++++++++++++++++++ www/common/cryptpad-common.js | 93 ++-------------------------------- 2 files changed, 92 insertions(+), 88 deletions(-) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index e23756cec..cc3f838f6 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -130,5 +130,92 @@ define([ Alertify.error(Util.fixHTML(msg)); }; + /* + * spinner + */ + UI.spinner = function (parent) { + var $target = $('', { + 'class': 'fa fa-spinner fa-pulse fa-4x fa-fw' + }).hide(); + + $(parent).append($target); + + return { + show: function () { + $target.show(); + return this; + }, + hide: function () { + $target.hide(); + return this; + }, + get: function () { + return $target; + }, + }; + }; + + var LOADING = 'loading'; + + var getRandomTip = function () { + if (!Messages.tips || !Object.keys(Messages.tips).length) { return ''; } + var keys = Object.keys(Messages.tips); + var rdm = Math.floor(Math.random() * keys.length); + return Messages.tips[keys[rdm]]; + }; + UI.addLoadingScreen = function (loadingText, hideTips) { + var $loading, $container; + if ($('#' + LOADING).length) { + $loading = $('#' + LOADING).show(); + if (loadingText) { + $('#' + LOADING).find('p').text(loadingText); + } + $container = $loading.find('.loadingContainer'); + } else { + $loading = $('
', {id: LOADING}); + $container = $('
', {'class': 'loadingContainer'}); + $container.append(''); + var $spinner = $('
', {'class': 'spinnerContainer'}); + UI.spinner($spinner).show(); + var $text = $('

').text(loadingText || Messages.loading); + $container.append($spinner).append($text); + $loading.append($container); + $('body').append($loading); + } + if (Messages.tips && !hideTips) { + var $loadingTip = $('

', {'id': 'loadingTip'}); + var $tip = $('', {'class': 'tips'}).text(getRandomTip()).appendTo($loadingTip); + $loadingTip.css({ + 'top': $('body').height()/2 + $container.height()/2 + 20 + 'px' + }); + $('body').append($loadingTip); + } + }; + UI.removeLoadingScreen = function (cb) { + $('#' + LOADING).fadeOut(750, cb); + $('#loadingTip').css('top', ''); + window.setTimeout(function () { + $('#loadingTip').fadeOut(750); + }, 3000); + }; + UI.errorLoadingScreen = function (error, transparent) { + if (!$('#' + LOADING).is(':visible')) { UI.addLoadingScreen(undefined, true); } + $('.spinnerContainer').hide(); + if (transparent) { $('#' + LOADING).css('opacity', 0.8); } + $('#' + LOADING).find('p').html(error || Messages.error); + }; + + var importContent = UI.importContent = function (type, f) { + return function () { + var $files = $('').click(); + $files.on('change', function (e) { + var file = e.target.files[0]; + var reader = new FileReader(); + reader.onload = function (e) { f(e.target.result, file); }; + reader.readAsText(file, type); + }); + }; + }; + return UI; }); diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 68d5204fb..620445bce 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -31,7 +31,6 @@ define([ var userNameKey = common.userNameKey = 'User_name'; var fileHashKey = common.fileHashKey = 'FS_hash'; var displayNameKey = common.displayNameKey = 'cryptpad.username'; - var LOADING = 'loading'; var newPadNameKey = common.newPadNameKey = "newPadName"; var newPadPathKey = common.newPadPathKey = "newPadPath"; var storageKey = common.storageKey = 'CryptPad_RECENTPADS'; @@ -49,6 +48,10 @@ define([ common.confirm = UI.confirm; common.log = UI.log; common.warn = UI.warn; + common.spinner = UI.spinner; + common.addLoadingScreen = UI.addLoadingScreen; + common.removeLoadingScreen = UI.removeLoadingScreen; + common.errorLoadingScreen = UI.errorLoadingScreen; // import common utilities for export var find = common.find = Util.find; @@ -155,7 +158,6 @@ define([ return url; }; - var login = common.login = function (hash, name, cb) { if (!hash) { throw new Error('expected a user hash'); } if (!name) { throw new Error('expected a user name'); } @@ -566,66 +568,6 @@ define([ }); }; - var getRandomTip = function () { - if (!Messages.tips || !Object.keys(Messages.tips).length) { return ''; } - var keys = Object.keys(Messages.tips); - var rdm = Math.floor(Math.random() * keys.length); - return Messages.tips[keys[rdm]]; - }; - common.addLoadingScreen = function (loadingText, hideTips) { - var $loading, $container; - if ($('#' + LOADING).length) { - $loading = $('#' + LOADING).show(); - if (loadingText) { - $('#' + LOADING).find('p').text(loadingText); - } - $container = $loading.find('.loadingContainer'); - } else { - $loading = $('
', {id: LOADING}); - $container = $('
', {'class': 'loadingContainer'}); - $container.append(''); - var $spinner = $('
', {'class': 'spinnerContainer'}); - common.spinner($spinner).show(); - var $text = $('

').text(loadingText || Messages.loading); - $container.append($spinner).append($text); - $loading.append($container); - $('body').append($loading); - } - if (Messages.tips && !hideTips) { - var $loadingTip = $('

', {'id': 'loadingTip'}); - var $tip = $('', {'class': 'tips'}).text(getRandomTip()).appendTo($loadingTip); - $loadingTip.css({ - 'top': $('body').height()/2 + $container.height()/2 + 20 + 'px' - }); - $('body').append($loadingTip); - } - }; - common.removeLoadingScreen = function (cb) { - $('#' + LOADING).fadeOut(750, cb); - $('#loadingTip').css('top', ''); - window.setTimeout(function () { - $('#loadingTip').fadeOut(750); - }, 3000); - }; - common.errorLoadingScreen = function (error, transparent) { - if (!$('#' + LOADING).is(':visible')) { common.addLoadingScreen(undefined, true); } - $('.spinnerContainer').hide(); - if (transparent) { $('#' + LOADING).css('opacity', 0.8); } - $('#' + LOADING).find('p').html(error || Messages.error); - }; - - var importContent = common.importContent = function (type, f) { - return function () { - var $files = $('').click(); - $files.on('change', function (e) { - var file = e.target.files[0]; - var reader = new FileReader(); - reader.onload = function (e) { f(e.target.result, file); }; - reader.readAsText(file, type); - }); - }; - }; - /* * Buttons */ @@ -748,7 +690,7 @@ define([ title: Messages.importButtonTitle, }).append($('', {'class':'fa fa-upload', style: 'font:'+size+' FontAwesome'})); if (callback) { - button.click(common.importContent('text/plain', function (content, file) { + button.click(UI.importContent('text/plain', function (content, file) { callback(content, file); })); } @@ -1172,31 +1114,6 @@ define([ }; - /* - * spinner - */ - common.spinner = function (parent) { - var $target = $('', { - 'class': 'fa fa-spinner fa-pulse fa-4x fa-fw' - }).hide(); - - $(parent).append($target); - - return { - show: function () { - $target.show(); - return this; - }, - hide: function () { - $target.hide(); - return this; - }, - get: function () { - return $target; - }, - }; - }; - // local name? common.ready = function (f) { var block = 0; From 525d35c9ece0e9ce43531fee90781a5b49544dee Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 14 Apr 2017 14:54:43 +0200 Subject: [PATCH 40/53] redefine alert --- www/common/cryptpad-common.js | 1 + 1 file changed, 1 insertion(+) diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 620445bce..ffabcd1f2 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -46,6 +46,7 @@ define([ var stopListening = common.stopListening = UI.stopListening; common.prompt = UI.prompt; common.confirm = UI.confirm; + common.alert = UI.alert; common.log = UI.log; common.warn = UI.warn; common.spinner = UI.spinner; From fbebbf0dcafd5ab5d48409da180464beab9ba5f5 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 14 Apr 2017 15:32:12 +0200 Subject: [PATCH 41/53] minor clean up --- www/common/cryptpad-common.js | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index ffabcd1f2..c63c43f62 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -119,18 +119,14 @@ define([ }; var getUid = common.getUid = function () { - if (store) { - if (store.getProxy() && store.getProxy().proxy) { - return store.getProxy().proxy.uid; - } + if (store && store.getProxy() && store.getProxy().proxy) { + return store.getProxy().proxy.uid; } }; var getRealtime = common.getRealtime = function () { - if (store) { - if (store.getProxy() && store.getProxy().info) { + if (store && store.getProxy() && store.getProxy().info) { return store.getProxy().info.realtime; - } } return; }; @@ -255,7 +251,7 @@ define([ var migrateRecentPads = common.migrateRecentPads = function (pads) { return pads.map(function (pad) { var hash; - if (isArray(pad)) { + if (Array.isArray(pad)) { var href = pad[0]; href.replace(/\#(.*)$/, function (a, h) { hash = h; @@ -298,7 +294,7 @@ define([ if (err) { cb(err, null); return; } legacy.get(storageKey, function (err2, recentPads) { if (err2) { cb(err2, null); return; } - if (isArray(recentPads)) { + if (Array.isArray(recentPads)) { cb(void 0, migrateRecentPads(recentPads)); return; } @@ -421,7 +417,7 @@ define([ /* fetch and migrate your pad history from the store */ var getRecentPads = common.getRecentPads = function (cb) { getStore().getDrive(storageKey, function (err, recentPads) { - if (isArray(recentPads)) { + if (Array.isArray(recentPads)) { checkRecentPads(recentPads); cb(void 0, recentPads); return; @@ -822,7 +818,7 @@ define([ // // allowed options tags: ['a', 'hr', 'p'] var createDropdown = common.createDropdown = function (config) { - if (typeof config !== "object" || !isArray(config.options)) { return; } + if (typeof config !== "object" || !Array.isArray(config.options)) { return; } var allowedTags = ['a', 'p', 'hr']; var isValidOption = function (o) { From c7eae9675bf07d70b9f269e230029af9c8fcee45 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 14 Apr 2017 15:34:05 +0200 Subject: [PATCH 42/53] keep exporting isArray for backwards compatibility but prevent internal use --- www/common/cryptpad-common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index c63c43f62..cc30c6803 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -221,7 +221,7 @@ define([ return typeof getUserHash() === "string"; }; - var isArray = common.isArray = $.isArray; + common.isArray = $.isArray; /* * localStorage formatting From 402ce2db93fb56b4f2e7874b7231e94fdbb24958 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 14 Apr 2017 15:34:22 +0200 Subject: [PATCH 43/53] better validation of inputs --- www/common/pinpad.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/www/common/pinpad.js b/www/common/pinpad.js index 275a68666..a9467cff9 100644 --- a/www/common/pinpad.js +++ b/www/common/pinpad.js @@ -38,8 +38,7 @@ define([ // you can ask the server to pin a particular channel for you exp.pin = function (channels, cb) { - // TODO use isArray if it's safe - if (!channels && channels.length) { + if (!Array.isArray(channels)) { window.setTimeout(function () { cb('[TypeError] pin expects an array'); }); @@ -50,8 +49,7 @@ define([ // you can also ask to unpin a particular channel exp.unpin = function (channels, cb) { - // TODO use isArray if it's safe - if (!channels && channels.length) { + if (!Array.isArray(channels)) { window.setTimeout(function () { cb('[TypeError] pin expects an array'); }); @@ -72,8 +70,7 @@ define([ // if local and remote hashes don't match, send a reset exp.reset = function (channels, cb) { - // TODO use isArray if it's safe - if (!channels && channels.length) { + if (!Array.isArray(channels)) { window.setTimeout(function () { cb('[TypeError] pin expects an array'); }); From a27cc76fc0c9ce5ab695f276a6628bfeb49c7642 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 14 Apr 2017 15:35:02 +0200 Subject: [PATCH 44/53] uppercase LOL --- www/common/themes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/themes.js b/www/common/themes.js index 76ae740f5..3df706c88 100644 --- a/www/common/themes.js +++ b/www/common/themes.js @@ -22,7 +22,7 @@ define(function () { "isotope isotope.css", "lesser-dark lesser-dark.css", "liquibyte liquibyte.css", - "lol lol.css", + "LOL lol.css", "material material.css", "mbo mbo.css", "mdn-like mdn-like.css", From 5a83759ee21d4b63e56ece984909d16ddf505371 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 14 Apr 2017 17:18:17 +0200 Subject: [PATCH 45/53] add usage button to settings page --- www/settings/main.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/www/settings/main.js b/www/settings/main.js index 64bf15f7b..cee0772b0 100644 --- a/www/settings/main.js +++ b/www/settings/main.js @@ -227,6 +227,40 @@ define([ return $div; }; + var bytesToMegabytes = function (bytes) { + return Math.floor((bytes / (1024 * 1024) * 100)) / 100; + }; + + var createUsageButton = function (obj) { + var proxy = obj.proxy; + + var $div = $('
', { 'class': 'pinned-usage' }) + .text(Messages.settings_usageTitle) + .append('
'); + + $('