From 372f1dfeb433dd431b4c4ddc2f827059cd71632a Mon Sep 17 00:00:00 2001 From: Paul Libbrecht Date: Fri, 11 May 2018 09:06:22 +0200 Subject: [PATCH 01/86] First anchor test and restore of the CKEditor anchor function. --- customize.dist/ckeditor-config.js | 2 +- www/pad/inner.js | 57 +++++++++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/customize.dist/ckeditor-config.js b/customize.dist/ckeditor-config.js index 36cac87f0..882c5e0fc 100644 --- a/customize.dist/ckeditor-config.js +++ b/customize.dist/ckeditor-config.js @@ -5,7 +5,7 @@ CKEDITOR.editorConfig = function( config ) { config.needsBrFiller= fixThings; config.needsNbspFiller= fixThings; - config.removeButtons= 'Source,Maximize,Anchor'; + config.removeButtons= 'Source,Maximize'; // magicline plugin inserts html crap into the document which is not part of the // document itself and causes problems when it's sent across the wire and reflected back config.removePlugins= 'resize,elementspath'; diff --git a/www/pad/inner.js b/www/pad/inner.js index 88d9f5011..21919c1a2 100644 --- a/www/pad/inner.js +++ b/www/pad/inner.js @@ -32,6 +32,7 @@ define([ '/common/common-util.js', '/bower_components/chainpad/chainpad.dist.js', '/customize/application_config.js', + '/common/test.js', '/bower_components/diff-dom/diffDOM.js', @@ -52,7 +53,9 @@ define([ Hash, Util, ChainPad, - AppConfig) + AppConfig, + Test +) { var DiffDom = window.diffDOM; @@ -160,7 +163,12 @@ define([ ]; var getHTML = function (inner) { - return ('\n' + '\n' + inner.innerHTML); + return ('\n' + '\n' + + ' \n ' + + inner.innerHTML.replace(/]*class="cke_anchor"[^>]*data-cke-realelement="([^"]*)"[^>]*>/, + function(match,realElt){ return unescape(realElt); }) + + ' \n' + ); }; var CKEDITOR_CHECK_INTERVAL = 100; @@ -752,6 +760,51 @@ define([ }).nThen(waitFor()); }).nThen(function (/*waitFor*/) { + function launchAnchorTest(test) { + // -------- anchor test: make sure the exported anchor contains ------- + console.log('---- anchor test: make sure the exported anchor contains -----.'); + + // TODO: cleanup fixme, too much ---, and removed tests + // TODO: any other unwanted changes (sframe-app?)? + // TODO: upgrade to latest of master, create branch + // TODO: any way to make sure that content contains anchors? Seems to need selenium-driven clicks and inputs + function tryAndTestExport() { + // window.setContent("This goes before the anchor"); + var anchors = CKEDITOR.plugins["link"].getEditorAnchors(editor); + if(!anchors || anchors.length===0) { + test.fail("No anchors found. Please adjust document"); + } else { + console.log(anchors.length + " anchors found."); + var exported = getHTML(inner); + console.log("Obtained exported: " + exported); + var allFound = true; + for(var i=0; i=0; + console.log("Found " + expected + " " + found + "."); + allFound = allFound && found; + } + console.log("Finished anchor test."); + if(allFound) {test.pass();} + else + {test.fail("Not all expected a elements found.");} + } + } + var intervalHandle = window.setInterval(function() { + if(editor.status==="ready") { + window.clearInterval(intervalHandle); + tryAndTestExport(); + } else { + console.log("Waiting for editor to be ready."); + } + }, 100); + } + Test(function(test) { + + launchAnchorTest(test); + }); andThen2(editor, Ckeditor, framework); }); }; From 554b4a978d65027ca48b1c0fba3f863666b70e25 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 28 Jun 2018 14:15:30 +0200 Subject: [PATCH 02/86] Load shared folders in the store --- www/common/outer/async-store.js | 69 +++++++++++++++++++++++++++++++++ www/common/userObject.js | 1 + 2 files changed, 70 insertions(+) diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 52c0efb9c..01d2bd62b 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -1183,6 +1183,61 @@ define([ }])); }; + // SHARED FOLDERS + var loadSharedFolder = function (id, data) { + var parsed = Hash.parsePadUrl(data.href); + var secret = Hash.getSecrets('folder', parsed.hash, data.password); + var listmapConfig = { + data: {}, + websocketURL: NetConfig.getWebsocketURL(), + channel: secret.channel, + readOnly: false, + validateKey: secret.keys.validateKey || undefined, + crypto: Crypto.createEncryptor(secret.keys), + userName: 'sharedFolder', + logLevel: 1, + ChainPad: ChainPad, + classic: true, + }; + var rt = Listmap.create(listmapConfig); + store.sharedFolders[id] = rt; + return rt; + }; + Store.addSharedFolder = function (clientId, data, cb) { + var path = data.path; + var href = data.href; + var id; + nThen(function (waitFor) { + // TODO + var folderData = {}; + // 1. add the shared folder to our list of shared folders + store.userObject.pushSharedFolder(folderData, waitFor(function (err, folderId) { + if (err) { + waitFor.abort(); + return void cb(err); + } + id = folderId; + })); + nThen(function (waitFor) { + // 2a. add the shared folder to the path in our drive + store.userObject.add(id, path); + onSync(waitFor()); + + // 2b. load the proxy + var rt = loadSharedFolder(folderId, data); + rt.on('ready', waitFor(function () { + // TODO + // "fixFiles" + })); + }).nThen(function () { + sendDriveEvent('DRIVE_CHANGE', { + path: ['drive'].concat(path) + }, clientId); + cb(); + }); + }; + + // Drive Store.userObjectCommand = function (clientId, cmdData, cb) { if (!cmdData || !cmdData.cmd) { return; } @@ -1331,6 +1386,20 @@ define([ /////////////////////// Init ///////////////////////////////////// ////////////////////////////////////////////////////////////////// + var loadSharedFolders = function (waitFor) { + // TODO + store.sharedFolders = {}; + var shared = Util.find(store.proxy, ['drive', UserObject.SHARED_FOLDERS]) || {}; + Object.keys(shared).forEach(function (id) { + var sf = shared[id]; + var rt = loadSharedFolder(id, sf); + rt.on('ready', waitFor(function () { + // TODO + // "fixFiles" + })); + }); + }; + var onReady = function (clientId, returned, cb) { var proxy = store.proxy; var userObject = store.userObject = UserObject.init(proxy.drive, { diff --git a/www/common/userObject.js b/www/common/userObject.js index fb39eb484..0042d5d57 100644 --- a/www/common/userObject.js +++ b/www/common/userObject.js @@ -13,6 +13,7 @@ define([ var UNSORTED = module.UNSORTED = "unsorted"; var TRASH = module.TRASH = "trash"; var TEMPLATE = module.TEMPLATE = "template"; + var SHARED_FOLDERS = module.SHARED_FOLDERS = "sharedFolders"; module.init = function (files, config) { var exp = {}; From 470f404a24380058c51721be819840d899a6659c Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 28 Jun 2018 15:31:30 +0200 Subject: [PATCH 03/86] temp --- www/common/common-interface.js | 2 +- www/common/common-ui-elements.js | 16 ++++++++++++---- www/common/cryptpad-common.js | 10 ++++++++-- www/drive/inner.js | 29 ++++++++++++++++++----------- 4 files changed, 39 insertions(+), 18 deletions(-) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 7b05d22fe..974490796 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -761,7 +761,7 @@ define([ UI.getFileIcon = function (data) { var $icon = UI.getIcon(); if (!data) { return $icon; } - var href = data.href; + var href = data.href || data.roHref; var type = data.type; if (!href && !type) { return $icon; } diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index d54540efa..b35bebdfd 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -73,6 +73,8 @@ define([ data.password = val; })); }).nThen(function (waitFor) { + var base = common.getMetadataMgr().getPrivateData().origin; + /* XXX common.getPadAttribute('href', waitFor(function (err, val) { var base = common.getMetadataMgr().getPrivateData().origin; @@ -93,6 +95,12 @@ define([ if (!hrefsecret.keys) { return; } var viewHash = Hash.getViewHashFromKeys(hrefsecret); data.roHref = hBase + viewHash; + }));*/ + common.getPadAttribute('href', waitFor(function (err, val) { + data.href = base + val; + })); + common.getPadAttribute('roHref', waitFor(function (err, val) { + data.roHref = base + val; })); common.getPadAttribute('channel', waitFor(function (err, val) { data.channel = val; @@ -162,7 +170,7 @@ define([ $d.append(password); } - var parsed = Hash.parsePadUrl(data.href); + var parsed = Hash.parsePadUrl(data.href || data.roHref); if (owned && parsed.hashData.type === 'pad') { var sframeChan = common.getSframeChannel(); var changePwTitle = Messages.properties_changePassword; @@ -186,7 +194,7 @@ define([ UI.confirm(changePwConfirm, function (yes) { if (!yes) { return; } sframeChan.query("Q_PAD_PASSWORD_CHANGE", { - href: data.href, + href: data.href || data.roHref, password: $(newPassword).find('input').val() }, function (err, data) { if (err || data.error) { @@ -195,11 +203,11 @@ define([ UI.findOKButton().click(); if (data.warning) { return void UI.alert(Messages.properties_passwordWarning, function () { - common.gotoURL(hasPassword ? undefined : data.href); + common.gotoURL(hasPassword ? undefined : (data.href || data.roHref)); }, {force: true}); } return void UI.alert(Messages.properties_passwordSuccess, function () { - common.gotoURL(hasPassword ? undefined : data.href); + common.gotoURL(hasPassword ? undefined : (data.href || data.roHref)); }, {force: true}); }); }); diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 589ec0292..afd177577 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -613,7 +613,7 @@ define([ if (!parsed.hash) { return void cb({ error: 'EINVAL_HREF' }); } var warning = false; - var newHash; + var newHash, newRoHref; var oldChannel; if (parsed.hashData.password) { newHash = parsed.hash; @@ -678,6 +678,11 @@ define([ common.setPadAttribute('channel', secret.channel, waitFor(function (err) { if (err) { warning = true; } }), href); + var viewHash = Hash.getViewHashFromKeys(secret); + newRoHref = '/' + parsed.type + '/#' + viewHash; + common.setPadAttribute('roHref', newRoHref, waitFor(function (err) { + if (err) { warning = true; } + }), href); if (parsed.hashData.password) { return; } // same hash common.setPadAttribute('href', newHref, waitFor(function (err) { @@ -687,7 +692,8 @@ define([ cb({ warning: warning, hash: newHash, - href: newHref + href: newHref, + roHref: newRoHref }); }); }; diff --git a/www/drive/inner.js b/www/drive/inner.js index d072992d6..9e538b1f4 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -666,10 +666,10 @@ define([ var openFile = function (el, href) { if (!href) { var data = filesOp.getFileData(el); - if (!data || !data.href) { + if (!data || (!data.href && !data.roHref)) { return void logError("Missing data for the file", el, data); } - href = data.href; + href = data.href || data.roHref; } window.open(APP.origin + href); }; @@ -1271,9 +1271,10 @@ define([ if (!filesOp.isFile(element)) { return; } var data = filesOp.getFileData(element); + var href = data.href || data.roHref; if (!data) { return void logError("No data for the file", element); } - var hrefData = Hash.parsePadUrl(data.href); + var hrefData = Hash.parsePadUrl(href); if (hrefData.type) { $span.addClass('cp-border-color-'+hrefData.type); } @@ -1305,7 +1306,7 @@ define([ $span.attr('title', name); var type = Messages.type[hrefData.type] || hrefData.type; - common.displayThumbnail(data.href, data.channel, data.password, $span, function ($thumb) { + common.displayThumbnail(href || data.roHref, data.channel, data.password, $span, function ($thumb) { // Called only if the thumbnail exists // Remove the .hide() added by displayThumnail() because it hides the icon in // list mode too @@ -1847,7 +1848,7 @@ define([ var data = filesOp.getFileData(id); if (!data) { return ''; } if (prop === 'type') { - var hrefData = Hash.parsePadUrl(data.href); + var hrefData = Hash.parsePadUrl(data.href || data.roHref); return hrefData.type; } if (prop === 'atime' || prop === 'ctime') { @@ -1882,7 +1883,7 @@ define([ }; } if (prop === 'type') { - var hrefData = Hash.parsePadUrl(e.href); + var hrefData = Hash.parsePadUrl(e.href || e.roHref); return hrefData.type; } if (prop === 'atime' || prop === 'ctime') { @@ -2690,10 +2691,12 @@ define([ return $div.html(); }; + /* XXX var getReadOnlyUrl = APP.getRO = function (id) { if (!filesOp.isFile(id)) { return; } var data = filesOp.getFileData(id); if (!data) { return; } + if (data.roHref) { return data.roHref; } var parsed = Hash.parsePadUrl(data.href); if (parsed.hashData.type !== "pad") { return; } var i = data.href.indexOf('#') + 1; @@ -2702,7 +2705,7 @@ define([ if (!hrefsecret.keys) { return; } var viewHash = Hash.getViewHashFromKeys(hrefsecret); return base + viewHash; - }; + };*/ // Disable middle click in the context menu to avoid opening /drive/inner.html# in new tabs $(window).click(function (e) { @@ -2717,12 +2720,14 @@ define([ if (!filesOp.isFile(el)) { return void cb('NOT_FILE'); } - var ro = filesOp.isReadOnlyFile(el); + //var ro = filesOp.isReadOnlyFile(el); var base = APP.origin; var data = JSON.parse(JSON.stringify(filesOp.getFileData(el))); if (!data || !data.href) { return void cb('INVALID_FILE'); } data.href = base + data.href; + data.roHref = base + data.roHref; + /* XXX var roUrl; if (ro) { data.roHref = data.href; @@ -2731,6 +2736,7 @@ define([ roUrl = getReadOnlyUrl(el); if (roUrl) { data.roHref = base + roUrl; } } + */ UIElements.getProperties(common, data, cb); }; @@ -2806,8 +2812,9 @@ define([ var el = filesOp.find(p.path); if (filesOp.isPathIn(p.path, [FILES_DATA])) { el = el.href; } if (!el || filesOp.isFolder(el)) { return; } - var roUrl = getReadOnlyUrl(el); - openFile(null, roUrl); + // var roUrl = getReadOnlyUrl(el); + openFile(el); + //, roUrl); XXX }); } else if ($(this).hasClass('cp-app-drive-context-newfolder')) { @@ -2847,7 +2854,7 @@ define([ el = filesOp.find(paths[0].path); var data = filesOp.getFileData(el); if (!data) { return void console.error("Expected to find a file"); } - var href = data.href; + var href = data.href || data.roHref; common.updateTags(href); } else if ($(this).hasClass("cp-app-drive-context-empty")) { From 0f9a71686e338dc0d70dda0bd9f5b27dbe102abd Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 28 Jun 2018 18:16:34 +0200 Subject: [PATCH 04/86] Add support for read-only href stored in filesData --- www/common/common-hash.js | 12 ++++++++- www/common/mergeDrive.js | 23 ++++++++-------- www/common/outer/async-store.js | 24 ++++++++++++----- www/common/outer/userObject.js | 48 ++++++++++++++++++++------------- www/common/userObject.js | 8 ++++-- 5 files changed, 76 insertions(+), 39 deletions(-) diff --git a/www/common/common-hash.js b/www/common/common-hash.js index 4b0c2c607..d5066b757 100644 --- a/www/common/common-hash.js +++ b/www/common/common-hash.js @@ -398,10 +398,16 @@ Version 1 Hash.findWeaker = function (href, channel, recents) { var parsed = parsePadUrl(href); if (!parsed.hash) { return false; } + // We can't have a weaker hash if we're already in view mode + if (parsed.hashData && parsed.hashData.mode === 'view') { return; } var weaker; Object.keys(recents).some(function (id) { var pad = recents[id]; - var p = parsePadUrl(pad.href); + if (pad.href || !pad.roHref) { + // This pad has an edit link, so it can't be weaker + return; + } + var p = parsePadUrl(pad.roHref); if (p.type !== parsed.type) { return; } // Not the same type if (p.hash === parsed.hash) { return; } // Same hash, not stronger if (channel !== pad.channel) { return; } // Not the same channel @@ -430,6 +436,10 @@ Version 1 var stronger; Object.keys(recents).some(function (id) { var pad = recents[id]; + if (!pad.href) { + // This pad doesn't have an edit link, so it can't be stronger + return; + } var p = parsePadUrl(pad.href); if (p.type !== parsed.type) { return; } // Not the same type if (p.hash === parsed.hash) { return; } // Same hash, not stronger diff --git a/www/common/mergeDrive.js b/www/common/mergeDrive.js index ea4c6edc7..bcc30666e 100644 --- a/www/common/mergeDrive.js +++ b/www/common/mergeDrive.js @@ -115,23 +115,24 @@ define([ var newRecentPads = proxy.drive[newFo.FILES_DATA]; var oldFiles = oldFo.getFiles([newFo.FILES_DATA]); var newHrefs = Object.keys(newRecentPads).map(function (id) { - return newRecentPads[id].href; + return newRecentPads[id].href || newRecentPads[id].roHref; }); oldFiles.forEach(function (id) { - var href = oldRecentPads[id].href; + var href = oldRecentPads[id].href || oldRecentPads[id].roHref; // Do not migrate a pad if we already have it, it would create a duplicate in the drive if (newHrefs.indexOf(href) !== -1) { return; } // If we have a stronger version, do not add the current href - if (Hash.findStronger(href, oldRecentPads[id].channel, newRecentPads)) { return; } + // If the current href is read-only, don't check, we won't have a stronger + if (isRo && Hash.findStronger(href, oldRecentPads[id].channel, newRecentPads)) { return; } // If we have a weaker version, replace the href by the new one - // NOTE: if that weaker version is in the trash, the strong one will be put in unsorted - var weaker = Hash.findWeaker(href, oldRecentPads[id].channel, newRecentPads); - if (weaker) { - // Update RECENTPADS - weaker.href = href; - // Update the file in the drive - newFo.replace(weaker.href, href); - return; + // If the current href is an edit link, don't check, we won't have a weaker + if (!isRo) { + var weaker = Hash.findWeaker(href, oldRecentPads[id].channel, newRecentPads); + if (weaker) { + // Update RECENTPADS + weaker.href = href; + return; + } } // Here it means we have a new href, so we should add it to the drive at its old location var paths = oldFo.findFile(id); diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 52c0efb9c..3837b338a 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -426,10 +426,11 @@ define([ cb(JSON.parse(JSON.stringify(metadata))); }; - var makePad = function (href, title) { + var makePad = function (href, roHref, title) { var now = +new Date(); return { href: href, + roHref: roHref, atime: now, ctime: now, title: title || Hash.getDefaultName(Hash.parsePadUrl(href)), @@ -437,8 +438,13 @@ define([ }; Store.addPad = function (clientId, data, cb) { - if (!data.href) { return void cb({error:'NO_HREF'}); } - var pad = makePad(data.href, data.title); + if (!data.href && !data.roHref) { return void cb({error:'NO_HREF'}); } + if (!data.roHref) { + var parsed = Hash.parsePadUrl(data.href); + var secret = Hash.getSecrets(parsed.type, parsed.hash, data.password); + data.roHref = '/' + parsed.type + '/#' + Hash.getViewHashFromKeys(secret); + } + var pad = makePad(data.href, data.roHref, data.title); if (data.owners) { pad.owners = data.owners; } if (data.expire) { pad.expire = data.expire; } if (data.password) { pad.password = data.password; } @@ -736,9 +742,9 @@ define([ // Edit > Edit (present) > View > View (present) for (var id in allPads) { var pad = allPads[id]; - if (!pad.href) { continue; } + if (!pad.href || !pad.roHref) { continue; } - var p2 = Hash.parsePadUrl(pad.href); + var p2 = Hash.parsePadUrl(pad.href || pad.roHref); var h2 = p2.hashData; // Different types, proceed to the next one @@ -789,8 +795,14 @@ define([ // Add the pad if it does not exist in our drive if (!contains) { + var roHref; + if (h.mode === "view") { + roHref = href; + href = undefined; + } Store.addPad(clientId, { href: href, + roHref: roHref, channel: channel, title: title, owners: owners, @@ -827,7 +839,7 @@ define([ }; store.userObject.getFiles(where).forEach(function (id) { var data = store.userObject.getFileData(id); - var parsed = Hash.parsePadUrl(data.href); + var parsed = Hash.parsePadUrl(data.href || data.roHref); if ((!types || types.length === 0 || types.indexOf(parsed.type) !== -1) && hashes.indexOf(parsed.hash) === -1 && !isFiltered(parsed.type, data)) { diff --git a/www/common/outer/userObject.js b/www/common/outer/userObject.js index 31e70a3bb..630f8aae1 100644 --- a/www/common/outer/userObject.js +++ b/www/common/outer/userObject.js @@ -50,19 +50,6 @@ define([ var data = exp.getFileData(id); cb(null, clone(data[attr])); }; - var removePadAttribute = exp.removePadAttribute = function (f) { - if (typeof(f) !== 'string') { - console.error("Can't find pad attribute for an undefined pad"); - return; - } - Object.keys(files).forEach(function (key) { - var hash = f.indexOf('#') !== -1 ? f.slice(f.indexOf('#') + 1) : null; - if (hash && key.indexOf(hash) === 0) { - exp.debug("Deleting pad attribute in the realtime object"); - delete files[key]; - } - }); - }; exp.pushData = function (data, cb) { if (typeof cb !== "function") { cb = function () {}; } @@ -145,12 +132,14 @@ define([ if (!loggedIn && !config.testMode) { allFilesPaths.forEach(function (path) { + var id = path[1]; + /* XXX var el = exp.find(path); if (!el) { return; } var id = exp.getIdFromHref(el.href); + */ if (!id) { return; } spliceFileData(id); - removePadAttribute(el.href); }); return; } @@ -259,7 +248,6 @@ define([ if (!id) { return; } if (!loggedIn && !config.testMode) { // delete permanently - exp.removePadAttribute(href); spliceFileData(id); return; } @@ -268,6 +256,7 @@ define([ }; // REPLACE + /* XXX exp.replace = function (o, n) { var idO = exp.getIdFromHref(o); if (!idO || !exp.isFile(idO)) { return; } @@ -275,7 +264,8 @@ define([ if (!data) { return; } data.href = n; }; - // If all the occurences of an href are in the trash, remvoe them and add the file in root. + */ + // If all the occurences of an href are in the trash, remove them and add the file in root. // This is use with setPadTitle when we open a stronger version of a deleted pad exp.restoreHref = function (href) { var idO = exp.getIdFromHref(href); @@ -563,13 +553,15 @@ define([ continue; } // Clean missing href - if (!el.href) { + if (!el.href && !el.roHref) { debug("Removing an element in filesData with a missing href.", el); toClean.push(id); continue; } - var parsed = Hash.parsePadUrl(el.href); + var parsed = Hash.parsePadUrl(el.href || el.roHref); + var secret; + // Clean invalid hash if (!parsed.hash) { debug("Removing an element in filesData with a invalid href.", el); @@ -583,6 +575,22 @@ define([ continue; } + // If we have an edit link, check the view link + if (el.href) { + var fixRo = function () { + secret = Hash.getSecrets(parsed.type, parsed.hash, el.password); + el.roHref = '/' + parsed.type + '/#' + Hash.getViewHasFromKeys(secret); + }; + if (!el.roHref) { + fixRo(); + } else { + var parsed2 = Hash.parsePadUrl(el.roHref); + if (!parsed2.hash || !parsed2.type) { + fixRo(); + } + } + } + // Fix href if (/^https*:\/\//.test(el.href)) { el.href = Hash.getRelativeHref(el.href); } // Fix creation time @@ -592,7 +600,9 @@ define([ // Fix channel if (!el.channel) { try { - var secret = Hash.getSecrets(parsed.type, parsed.hash, el.password); + if (!secret) { + secret = Hash.getSecrets(parsed.type, parsed.hash, el.password); + } el.channel = secret.channel; console.log('Adding missing channel in filesData ', el.channel); } catch (e) { diff --git a/www/common/userObject.js b/www/common/userObject.js index fb39eb484..4d8a6a0a2 100644 --- a/www/common/userObject.js +++ b/www/common/userObject.js @@ -78,11 +78,14 @@ define([ exp.isReadOnlyFile = function (element) { if (!isFile(element)) { return false; } var data = exp.getFileData(element); + return Boolean(data.roHref && !data.href); + /* XXX var parsed = Hash.parsePadUrl(data.href); if (!parsed) { return false; } var pHash = parsed.hashData; if (!pHash || pHash.type !== "pad") { return; } return pHash && pHash.mode === 'view'; + */ }; var isFolder = exp.isFolder = function (element) { @@ -139,7 +142,7 @@ define([ var getTitle = exp.getTitle = function (file, type) { if (workgroup) { debug("No titles in workgroups"); return; } var data = getFileData(file); - if (!file || !data || !data.href) { + if (!file || !data || !(data.href || data.roHref)) { error("getTitle called with a non-existing file id: ", file, data); return; } @@ -288,7 +291,8 @@ define([ var getIdFromHref = exp.getIdFromHref = function (href) { var result; getFiles([FILES_DATA]).some(function (id) { - if (files[FILES_DATA][id].href === href) { + if (files[FILES_DATA][id].href === href || + files[FILES_DATA][id].roHref === href) { result = id; return true; } From 425ac8ea57bb30a9c502b69494c50ef105f97f22 Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 29 Jun 2018 18:16:04 +0200 Subject: [PATCH 05/86] Migration for read-only links + fix issues with read-only pads --- www/common/common-interface.js | 2 +- www/common/common-ui-elements.js | 24 ++------------ www/common/mergeDrive.js | 1 + www/common/migrate-user-object.js | 52 +++++++++++++++++++++++++++++-- www/common/outer/async-store.js | 10 +++--- www/common/outer/userObject.js | 29 +++++------------ www/common/userObject.js | 7 ----- www/drive/inner.js | 50 ++++++++++------------------- www/drive/tests.js | 8 ++--- 9 files changed, 85 insertions(+), 98 deletions(-) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 974490796..5e5c75176 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -665,7 +665,7 @@ define([ // Update the current state loading.driveState = data.state; data.progress = data.progress || 100; - data.msg = Messages['loading_drive_'+data.state] || ''; + data.msg = Messages['loading_drive_'+ Math.floor(data.state)] || ''; $progress.html(data.msg); if (data.progress) { $progress.append(h('div.cp-loading-progress-bar', [ diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index b35bebdfd..3d057ed04 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -74,32 +74,12 @@ define([ })); }).nThen(function (waitFor) { var base = common.getMetadataMgr().getPrivateData().origin; - /* XXX - common.getPadAttribute('href', waitFor(function (err, val) { - var base = common.getMetadataMgr().getPrivateData().origin; - - var parsed = Hash.parsePadUrl(val); - if (parsed.hashData.mode === "view") { - data.roHref = base + val; - return; - } - - // We're not in a read-only pad - data.href = base + val; - - // Get Read-only href - if (parsed.hashData.type !== "pad") { return; } - var i = data.href.indexOf('#') + 1; - var hBase = data.href.slice(0, i); - var hrefsecret = Hash.getSecrets(parsed.type, parsed.hash, data.password); - if (!hrefsecret.keys) { return; } - var viewHash = Hash.getViewHashFromKeys(hrefsecret); - data.roHref = hBase + viewHash; - }));*/ common.getPadAttribute('href', waitFor(function (err, val) { + if (!val) { return; } data.href = base + val; })); common.getPadAttribute('roHref', waitFor(function (err, val) { + if (!val) { return; } data.roHref = base + val; })); common.getPadAttribute('channel', waitFor(function (err, val) { diff --git a/www/common/mergeDrive.js b/www/common/mergeDrive.js index bcc30666e..020861481 100644 --- a/www/common/mergeDrive.js +++ b/www/common/mergeDrive.js @@ -119,6 +119,7 @@ define([ }); oldFiles.forEach(function (id) { var href = oldRecentPads[id].href || oldRecentPads[id].roHref; + var isRo = href === oldRecentPads[id].roHref; // Do not migrate a pad if we already have it, it would create a duplicate in the drive if (newHrefs.indexOf(href) !== -1) { return; } // If we have a stronger version, do not add the current href diff --git a/www/common/migrate-user-object.js b/www/common/migrate-user-object.js index fb69fb20b..2f1ea5e88 100644 --- a/www/common/migrate-user-object.js +++ b/www/common/migrate-user-object.js @@ -123,12 +123,58 @@ define([ })); }); }); - n.nThen(waitFor()); + n.nThen(waitFor(function () { + Feedback.send('Migrate-6', true); + userObject.version = version = 6; + })); }; if (version < 6) { addChannelId(); - Feedback.send('Migrate-6', true); - userObject.version = version = 6; + } + }).nThen(function (waitFor) { + var addRoHref = function () { + var data = userObject.drive.filesData; + var el, parsed; + var n = nThen(function () {}); + var padsLength = Object.keys(data).length; + Object.keys(data).forEach(function (k, i) { + n = n.nThen(function (w) { + setTimeout(w(function () { + el = data[k]; + if (!el.href || (el.roHref && false)) { + // Already migrated + return void progress(7, Math.round(100*i/padsLength)); + } + parsed = Hash.parsePadUrl(el.href); + if (parsed.hashData.type !== "pad") { + // No read-only mode for files + return void progress(7, Math.round(100*i/padsLength)); + } + if (parsed.hashData.mode === "view") { + // This is a read-only pad in our drive + el.roHref = el.href; + delete el.href; + console.log('Move href to roHref in filesData ', el.roHref); + } else { + var secret = Hash.getSecrets(parsed.type, parsed.hash, el.password); + var hash = Hash.getViewHashFromKeys(secret); + if (hash) { + // Version 0 won't have a view hash available + el.roHref = '/' + parsed.type + '/#' + hash; + console.log('Adding missing roHref in filesData ', el.href); + } + } + progress(6, Math.round(100*i/padsLength)); + })); + }); + }); + n.nThen(waitFor(function () { + Feedback.send('Migrate-7', true); + userObject.version = version = 7; + })); + }; + if (version < 7) { + addRoHref(); } /*}).nThen(function (waitFor) { // Test progress bar in the loading screen diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 3837b338a..7981cec53 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -441,8 +441,10 @@ define([ if (!data.href && !data.roHref) { return void cb({error:'NO_HREF'}); } if (!data.roHref) { var parsed = Hash.parsePadUrl(data.href); - var secret = Hash.getSecrets(parsed.type, parsed.hash, data.password); - data.roHref = '/' + parsed.type + '/#' + Hash.getViewHashFromKeys(secret); + if (parsed.hashData.type === "pad") { + var secret = Hash.getSecrets(parsed.type, parsed.hash, data.password); + data.roHref = '/' + parsed.type + '/#' + Hash.getViewHashFromKeys(secret); + } } var pad = makePad(data.href, data.roHref, data.title); if (data.owners) { pad.owners = data.owners; } @@ -742,7 +744,7 @@ define([ // Edit > Edit (present) > View > View (present) for (var id in allPads) { var pad = allPads[id]; - if (!pad.href || !pad.roHref) { continue; } + if (!pad.href && !pad.roHref) { continue; } var p2 = Hash.parsePadUrl(pad.href || pad.roHref); var h2 = p2.hashData; @@ -1364,7 +1366,7 @@ define([ }).nThen(function (waitFor) { Migrate(proxy, waitFor(), function (version, progress) { postMessage(clientId, 'LOADING_DRIVE', { - state: 2, + state: (2 + (version / 10)), progress: progress }); }); diff --git a/www/common/outer/userObject.js b/www/common/outer/userObject.js index 630f8aae1..4bc0019c3 100644 --- a/www/common/outer/userObject.js +++ b/www/common/outer/userObject.js @@ -133,11 +133,6 @@ define([ if (!loggedIn && !config.testMode) { allFilesPaths.forEach(function (path) { var id = path[1]; - /* XXX - var el = exp.find(path); - if (!el) { return; } - var id = exp.getIdFromHref(el.href); - */ if (!id) { return; } spliceFileData(id); }); @@ -256,15 +251,6 @@ define([ }; // REPLACE - /* XXX - exp.replace = function (o, n) { - var idO = exp.getIdFromHref(o); - if (!idO || !exp.isFile(idO)) { return; } - var data = exp.getFileData(idO); - if (!data) { return; } - data.href = n; - }; - */ // If all the occurences of an href are in the trash, remove them and add the file in root. // This is use with setPadTitle when we open a stronger version of a deleted pad exp.restoreHref = function (href) { @@ -576,17 +562,18 @@ define([ } // If we have an edit link, check the view link - if (el.href) { - var fixRo = function () { + if (el.href && parsed.hashData.type === "pad") { + if (parsed.hashData.mode === "view") { + el.roHref = el.href; + delete el.href; + } else if (!el.roHref) { secret = Hash.getSecrets(parsed.type, parsed.hash, el.password); - el.roHref = '/' + parsed.type + '/#' + Hash.getViewHasFromKeys(secret); - }; - if (!el.roHref) { - fixRo(); + el.roHref = '/' + parsed.type + '/#' + Hash.getViewHashFromKeys(secret); } else { var parsed2 = Hash.parsePadUrl(el.roHref); if (!parsed2.hash || !parsed2.type) { - fixRo(); + secret = Hash.getSecrets(parsed.type, parsed.hash, el.password); + el.roHref = '/' + parsed.type + '/#' + Hash.getViewHashFromKeys(secret); } } } diff --git a/www/common/userObject.js b/www/common/userObject.js index 4d8a6a0a2..e19614363 100644 --- a/www/common/userObject.js +++ b/www/common/userObject.js @@ -79,13 +79,6 @@ define([ if (!isFile(element)) { return false; } var data = exp.getFileData(element); return Boolean(data.roHref && !data.href); - /* XXX - var parsed = Hash.parsePadUrl(data.href); - if (!parsed) { return false; } - var pHash = parsed.hashData; - if (!pHash || pHash.type !== "pad") { return; } - return pHash && pHash.mode === 'view'; - */ }; var isFolder = exp.isFolder = function (element) { diff --git a/www/drive/inner.js b/www/drive/inner.js index 9e538b1f4..fb6f56bf4 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -2691,22 +2691,6 @@ define([ return $div.html(); }; - /* XXX - var getReadOnlyUrl = APP.getRO = function (id) { - if (!filesOp.isFile(id)) { return; } - var data = filesOp.getFileData(id); - if (!data) { return; } - if (data.roHref) { return data.roHref; } - var parsed = Hash.parsePadUrl(data.href); - if (parsed.hashData.type !== "pad") { return; } - var i = data.href.indexOf('#') + 1; - var base = data.href.slice(0, i); - var hrefsecret = Hash.getSecrets(parsed.type, parsed.hash, data.password); - if (!hrefsecret.keys) { return; } - var viewHash = Hash.getViewHashFromKeys(hrefsecret); - return base + viewHash; - };*/ - // Disable middle click in the context menu to avoid opening /drive/inner.html# in new tabs $(window).click(function (e) { if (!e.target || !$(e.target).parents('.cp-dropdown-content').length) { return; } @@ -2723,20 +2707,14 @@ define([ //var ro = filesOp.isReadOnlyFile(el); var base = APP.origin; var data = JSON.parse(JSON.stringify(filesOp.getFileData(el))); - if (!data || !data.href) { return void cb('INVALID_FILE'); } - data.href = base + data.href; - data.roHref = base + data.roHref; - - /* XXX - var roUrl; - if (ro) { - data.roHref = data.href; - delete data.href; - } else { - roUrl = getReadOnlyUrl(el); - if (roUrl) { data.roHref = base + roUrl; } + if (!data || !(data.href || data.roHref)) { return void cb('INVALID_FILE'); } + + if (data.href) { + data.href = base + data.href; + } + if (data.roHref) { + data.roHref = base + data.roHref; } - */ UIElements.getProperties(common, data, cb); }; @@ -2810,11 +2788,15 @@ define([ else if ($(this).hasClass('cp-app-drive-context-openro')) { paths.forEach(function (p) { var el = filesOp.find(p.path); - if (filesOp.isPathIn(p.path, [FILES_DATA])) { el = el.href; } - if (!el || filesOp.isFolder(el)) { return; } - // var roUrl = getReadOnlyUrl(el); - openFile(el); - //, roUrl); XXX + var href; + if (filesOp.isPathIn(p.path, [FILES_DATA])) { + href = el.roHref; + } else { + if (!el || filesOp.isFolder(el)) { return; } + var data = filesOp.getFileData(el); + href = data.roHref; + } + openFile(null, href); }); } else if ($(this).hasClass('cp-app-drive-context-newfolder')) { diff --git a/www/drive/tests.js b/www/drive/tests.js index a5fec1145..67d986d86 100644 --- a/www/drive/tests.js +++ b/www/drive/tests.js @@ -237,7 +237,8 @@ define([ && typeof files.template[0] === "number" && typeof files.filesData[files.template[0]] === "object" && !files.filesData[files.template[0]].filename - && files.filesData[files.template[0]].href === href3 + && !files.filesData[files.template[0]].href + && files.filesData[files.template[0]].roHref === href3 && typeof fileId2 === "number" && typeof files.filesData[fileId2] === "object" && files.filesData[fileId2].filename === "Trash" @@ -392,11 +393,6 @@ define([ console.log("DRIVE operations: rename"); return cb(); } - fo.replace(href1, href2); - if (fo.getFileData(id1).href !== href2) { - console.log("DRIVE operations: replace"); - return cb(); - } cb(true); }, "DRIVE operations"); From a25a72b5dbcbd45023c97d69f3de71eccffcf75b Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 5 Jul 2018 10:37:06 +0200 Subject: [PATCH 06/86] Add a proxy manager to handle operations between shared folders --- www/common/outer/async-store.js | 138 ++++--------- www/common/outer/userObject.js | 83 ++++++-- www/common/proxy-manager.js | 338 ++++++++++++++++++++++++++++++++ www/common/userObject.js | 17 +- www/drive/inner.js | 43 +--- 5 files changed, 472 insertions(+), 147 deletions(-) create mode 100644 www/common/proxy-manager.js diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 35d3dba67..b3601813a 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -1,6 +1,7 @@ define([ 'json.sortify', '/common/userObject.js', + '/common/proxy-manager.js', '/common/migrate-user-object.js', '/common/common-hash.js', '/common/common-util.js', @@ -18,7 +19,7 @@ define([ '/bower_components/chainpad-listmap/chainpad-listmap.js', '/bower_components/nthen/index.js', '/bower_components/saferphore/index.js', -], function (Sortify, UserObject, Migrate, Hash, Util, Constants, Feedback, Realtime, Messaging, Messenger, +], function (Sortify, UserObject, ProxyManager, Migrate, Hash, Util, Constants, Feedback, Realtime, Messaging, Messenger, CpNfWorker, NetConfig, AppConfig, Crypto, ChainPad, Listmap, nThen, Saferphore) { var Store = {}; @@ -78,17 +79,10 @@ define([ if (!userChannel) { return null; } // Get the list of pads' channel ID in your drive - // This list is filtered so that it doesn't include pad owned by other users (you should - // not pin these pads) - var files = store.userObject.getFiles([store.userObject.FILES_DATA]); + // This list is filtered so that it doesn't include pad owned by other users + // It now includes channels from shared folders var edPublic = store.proxy.edPublic; - var list = files.map(function (id) { - var d = store.userObject.getFileData(id); - if (d.owners && d.owners.length && edPublic && - d.owners.indexOf(edPublic) === -1) { return; } - return d.channel; - }) - .filter(function (x) { return x; }); + var list = store.manager.getPinList(edPublic); // Get the avatar var profile = store.proxy.profile; @@ -451,10 +445,16 @@ define([ if (data.expire) { pad.expire = data.expire; } if (data.password) { pad.password = data.password; } if (data.channel) { pad.channel = data.channel; } - store.userObject.pushData(pad, function (e, id) { + var uo = store.userObject; + var path = ['root']; + if (data.path) { + var resolved = store.manager.resolvePath(path); + uo = resolved.userObject; + path = resolved.path; + } + uo.pushData(pad, function (e, id) { if (e) { return void cb({error: "Error while adding a template:"+ e}); } - var path = data.path || ['root']; - store.userObject.add(id, path); + uo.add(id, path); sendDriveEvent('DRIVE_CHANGE', { path: ['drive', UserObject.FILES_DATA] }, clientId); @@ -733,67 +733,28 @@ define([ expire = +channelData.data.expire || undefined; } - var allPads = Util.find(store.proxy, ['drive', 'filesData']) || {}; - var isStronger; - - // If we don't find the new channel in our existing pads, we'll have to add the pads - // to filesData - var contains; - - // Update all pads that use the same channel but with a weaker hash - // Edit > Edit (present) > View > View (present) - for (var id in allPads) { - var pad = allPads[id]; - if (!pad.href && !pad.roHref) { continue; } - - var p2 = Hash.parsePadUrl(pad.href || pad.roHref); - var h2 = p2.hashData; - - // Different types, proceed to the next one - // No hash data: corrupted pad? - if (p.type !== p2.type || !h2) { continue; } - // Different channel: continue - if (pad.channel !== channel) { continue; } - - var shouldUpdate = p.hash.replace(/\/$/, '') === p2.hash.replace(/\/$/, ''); - - // If the hash is different but represents the same channel, check if weaker or stronger - if (!shouldUpdate && h.version !== 0) { - // We had view & now we have edit, update - if (h2.mode === 'view' && h.mode === 'edit') { shouldUpdate = true; } - // Same mode and we had present URL, update - else if (h.mode === h2.mode && h2.present) { shouldUpdate = true; } - // If we're here it means we have a weaker URL: - // update the date but keep the existing hash - else { - pad.atime = +new Date(); - contains = true; - continue; - } + var datas = store.manager.findChannel(channel); + var contains = datas.length !== 0; + datas.forEach(function (obj) { + var pad = obj.data; + pad.atime = +new Date(); + pad.title = title; + if (owners || h.type !== "file") { + // OWNED_FILES + // Never remove owner for files + pad.owners = owners; } - - if (shouldUpdate) { - contains = true; - pad.atime = +new Date(); - pad.title = title; - if (owners || h.type !== "file") { - // OWNED_FILES - // Never remove owner for files - pad.owners = owners; - } - pad.expire = expire; - - // If the href is different, it means we have a stronger one - if (href !== pad.href) { isStronger = true; } - pad.href = href; + pad.expire = expire; + if (h.mode === 'view') { return; } + + // If we only have rohref, it means we have a stronger href + if (!pad.href) { + // If we have a stronger url, remove the possible weaker from the trash. + // If all of the weaker ones were in the trash, add the stronger to ROOT + obj.userObject.restoreHref(href); } - } - - if (isStronger) { - // If we have a stronger url, remove the possible weaker from the trash. - // If all of the weaker ones were in the trash, add the stronger to ROOT - store.userObject.restoreHref(href); - } + pad.href = href; + }); // Add the pad if it does not exist in our drive if (!contains) { @@ -1215,11 +1176,11 @@ define([ }; var rt = Listmap.create(listmapConfig); store.sharedFolders[id] = rt; + store.manager.addProxy(rt.proxy); return rt; }; Store.addSharedFolder = function (clientId, data, cb) { var path = data.path; - var href = data.href; var id; nThen(function (waitFor) { // TODO @@ -1232,13 +1193,13 @@ define([ } id = folderId; })); - nThen(function (waitFor) { + }).nThen(function (waitFor) { // 2a. add the shared folder to the path in our drive store.userObject.add(id, path); onSync(waitFor()); // 2b. load the proxy - var rt = loadSharedFolder(folderId, data); + var rt = loadSharedFolder(id, data); rt.on('ready', waitFor(function () { // TODO // "fixFiles" @@ -1267,22 +1228,7 @@ define([ }); cb(data2); }; - switch (cmdData.cmd) { - case 'move': - store.userObject.move(data.paths, data.newPath, cb2); break; - case 'restore': - store.userObject.restore(data.path, cb2); break; - case 'addFolder': - store.userObject.addFolder(data.path, data.name, cb2); break; - case 'delete': - store.userObject.delete(data.paths, cb2, data.nocheck, data.isOwnPadRemoved); break; - case 'emptyTrash': - store.userObject.emptyTrash(cb2); break; - case 'rename': - store.userObject.rename(data.path, data.newName, cb2); break; - default: - cb(); - } + store.manager.command(cmdData, cb2); }; // Clients management @@ -1416,7 +1362,7 @@ define([ var onReady = function (clientId, returned, cb) { var proxy = store.proxy; - var userObject = store.userObject = UserObject.init(proxy.drive, { + var manager = store.manager = ProxyManager.create(proxy.drive, proxy.edPublic, { pinPads: function (data, cb) { Store.pinPads(null, data, cb); }, unpinPads: function (data, cb) { Store.unpinPads(null, data, cb); }, removeOwnedChannel: function (data, cb) { Store.removeOwnedChannel(null, data, cb); }, @@ -1427,6 +1373,7 @@ define([ sendDriveEvent("DRIVE_LOG", msg); } }); + var userObject = store.userObject = manager.user.userObject; nThen(function (waitFor) { postMessage(clientId, 'LOADING_DRIVE', { state: 2 @@ -1439,12 +1386,13 @@ define([ progress: progress }); }); - }).nThen(function () { + }).nThen(function (waitFor) { postMessage(clientId, 'LOADING_DRIVE', { state: 3 }); userObject.fixFiles(); - + loadSharedFolders(waitFor); + }).nThen(function () { var requestLogin = function () { broadcast([], "REQUEST_LOGIN"); }; diff --git a/www/common/outer/userObject.js b/www/common/outer/userObject.js index 4bc0019c3..94363a2d2 100644 --- a/www/common/outer/userObject.js +++ b/www/common/outer/userObject.js @@ -22,7 +22,7 @@ define([ console.error("removeOwnedChannel was not provided"); }; var loggedIn = config.loggedIn; - var workgroup = config.workgroup; + var sharedFolder = config.sharedFolder; var edPublic = config.edPublic; var ROOT = exp.ROOT; @@ -31,6 +31,7 @@ define([ var UNSORTED = exp.UNSORTED; var TRASH = exp.TRASH; var TEMPLATE = exp.TEMPLATE; + var SHARED_FOLDERS = exp.SHARED_FOLDERS; var debug = exp.debug; @@ -76,9 +77,8 @@ define([ // Find files in FILES_DATA that are not anymore in the drive, and remove them from // FILES_DATA. If there are owned pads, remove them from server too, unless the flag tells // us they're already removed - exp.checkDeletedFiles = function (isOwnPadRemoved) { - // Nothing in FILES_DATA for workgroups - if (workgroup || (!loggedIn && !config.testMode)) { return; } + exp.checkDeletedFiles = function (isOwnPadRemoved, noUnpin) { + if (!loggedIn && !config.testMode) { return; } var filesList = exp.getFiles([ROOT, 'hrefArray', TRASH]); var toClean = []; @@ -107,6 +107,7 @@ define([ } }); if (!toClean.length) { return; } + if (noUnpin) { return; } unpinPads(toClean, function (response) { if (response && response.error) { return console.error(response.error); } // console.error(response); @@ -124,7 +125,7 @@ define([ files[TRASH][obj.name].splice(idx, 1); }); }; - exp.deleteMultiplePermanently = function (paths, nocheck, isOwnPadRemoved) { + exp.deleteMultiplePermanently = function (paths, nocheck, isOwnPadRemoved, noUnpin) { var hrefPaths = paths.filter(function(x) { return exp.isPathIn(x, ['hrefArray']); }); var rootPaths = paths.filter(function(x) { return exp.isPathIn(x, [ROOT]); }); var trashPaths = paths.filter(function(x) { return exp.isPathIn(x, [TRASH]); }); @@ -176,11 +177,66 @@ define([ deleteMultipleTrashRoot(trashRoot); // In some cases, we want to remove pads from a location without removing them from - // OLD_FILES_DATA (replaceHref) - if (!nocheck) { exp.checkDeletedFiles(isOwnPadRemoved); } + // FILES_DATA (replaceHref) + if (!nocheck) { exp.checkDeletedFiles(isOwnPadRemoved, noUnpin); } }; // Move + + // From another drive + exp.copyFromOtherDrive = function (path, element, data) { + // Copy files data + // We have to remove pads that are already in the current proxy to make sure + // we won't create duplicates + + var toRemove = []; + Object.keys(data).forEach(function (id) { + // Find and maybe update existing pads with the same channel id + var d = data[id]; + var found = false; + for (var i in files[FILES_DATA]) { + if (files[FILES_DATA][i].channel === d.channel) { + // Update href? + if (!files[FILES_DATA][i].href) { files[FILES_DATA][i].href = d.href; } + found = true; + break; + } + } + if (found) { + toRemove.push(id); + return; + } + files[FILES_DATA][id] = data[id]; + }); + + // Remove existing pads from the "element" variable + if (exp.isFile(element) && toRemove.indexOf(element) !== -1) { + // XXX display error in the UI + return; + } else if (exp.isFolder(element)) { + var _removeExisting = function (root) { + for (var k in root) { + if (exp.isFile(root[k])) { + if (toRemove.indexOf(root[k]) !== -1) { + // XXX display message in UI + delete root[k]; + } + } else if (exp.isFolder(root[k])) { + _removeExisting(root[k]); + } + } + }; + _removeExisting(element); + } + + + // Copy file or folder + var newParent = exp.find(path); + var newName = exp.getAvailableName(newParent, Hash.createChannelId()); + newParent[newName] = element; + }; + + // From the same drive var pushToTrash = function (name, element, path) { var trash = files[TRASH]; if (typeof(trash[name]) === "undefined") { trash[name] = []; } @@ -449,6 +505,7 @@ define([ } }; var fixTrashRoot = function () { + if (sharedFolder) { return; } if (typeof(files[TRASH]) !== "object") { debug("TRASH was not an object"); files[TRASH] = {}; } var tr = files[TRASH]; var toClean; @@ -492,6 +549,7 @@ define([ } }; var fixTemplate = function () { + if (sharedFolder) { return; } if (!Array.isArray(files[TEMPLATE])) { debug("TEMPLATE was not an array"); files[TEMPLATE] = []; } files[TEMPLATE] = Util.deduplicateString(files[TEMPLATE].slice()); var us = files[TEMPLATE]; @@ -608,6 +666,10 @@ define([ spliceFileData(id); }); }; + var fixSharedFolders = function () { + if (sharedFolder) { return; } + if (typeof(files[SHARED_FOLDERS]) !== "object") { debug("SHARED_FOLDER was not an object"); files[SHARED_FOLDERS] = {}; } + }; var fixDrive = function () { Object.keys(files).forEach(function (key) { @@ -617,10 +679,9 @@ define([ fixRoot(); fixTrashRoot(); - if (!workgroup) { - fixTemplate(); - fixFilesData(); - } + fixTemplate(); + fixFilesData(); + fixSharedFolders(); fixDrive(); if (JSON.stringify(files) !== before) { diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js new file mode 100644 index 000000000..9b774b86d --- /dev/null +++ b/www/common/proxy-manager.js @@ -0,0 +1,338 @@ +define([ + '/common/userObject.js', + '/common/common-util.js', + '/bower_components/nthen/index.js', +], function (UserObject, Util, nThen) { + + + var getConfig = function (Env) { + var cfg = {}; + for (var k in Env.cfg) { cfg[k] = Env[k]; } + return cfg; + }; + + // Add a shared folder to the list + var addProxy = function (Env, id, proxy, leave) { + var cfg = getConfig(); + cfg.sharedFolder = true; + cfg.id = id; + var userObject = UserObject.init(proxy, Env.cfg); + userObject.fixFiles(); + Env.folders[id] = { + proxy: proxy, + userObject: userObject, + leave: leave + }; + return userObject; + }; + + // TODO: Remove a shared folder from the list + var removeProxy = function (Env, id) { + var f = Env.folders[id]; + if (!f) { return; } + f.leave(); + delete Env.folders[id]; + }; + + /* + Paths + */ + + // Transform an absolute path into a path relative to the correct shared folder + var _resolvePath = function (Env, path) { + var res = { + id: null, + userObject: Env.user.userObject, + path: path + }; + if (!Array.isArray(path) || path.length <= 1) { + return res; + } + var current; + var uo = Env.user.userObject; + for (var i=2; i<=path.length; i++) { + current = uo.find(path.slice(0,i)); + if (uo.isSharedFolder(current)) { + res = { + id: current, + userObject: Env.folders[current].userObject, + path: path.slice(i) + }; + break; + } + } + return res; + }; + var _resolvePaths = function (Env, paths) { + var main = []; + var folders = {}; + paths.forEach(function (path) { + var r = _resolvePath(Env, path); + if (r.id) { + if (!folders[r.id]) { + folders[r.id] = [r.path]; + } else { + folders[r.id].push(r.path); + } + } else { + main.push(r.path); + } + }); + return { + main: main, + folders: folders + }; + }; + + // Get a copy of the elements located in the given paths, with their files data + var _getCopyFromPaths = function (paths, userObject) { + var data = []; + paths.forEach(function (path) { + var el = userObject.find(path); + var files = []; + + // Get the files ID from the current path (file or folder) + if (userObject.isFile(el)) { + files.push(el); + } else { + userObject.getFilesRecursively(el, files); + } + + // Remove the shared folder from this list of files ID + files.filter(function (f) { return !userObject.isSharedFolder(f); }); + // Deduplicate + Util.deduplicateString(files); + + // Get the files data associated to these files + var filesData = {}; + files.forEach(function (f) { + filesData[f] = userObject.getFileData(f); + }); + + // TODO RO + // Encrypt or decrypt edit link here + // filesData.forEach(function (d) { d.href = encrypt(d.href); }); + + + data.push({ + el: el, + data: filesData + }); + }); + return data; + }; + + /* + RPC commands + */ + + // Move files or folders in the drive + var _move = function (Env, data, cb) { + var resolved = _resolvePaths(Env, data.paths); + var newResolved = _resolvePath(Env, data.newPath); + + if (!newResolved.userObject.isFolder(newResolved.path)) { return void cb(); } // XXX + + nThen(function (waitFor) { + if (resolved.main.length) { + // Move from the main drive + if (!newResolved.id) { + // Move from the main drive to the main drive + Env.user.userObject.move(resolved.main, newResolved.path, waitFor()); + } else { + // Move from the main drive to a shared folder + + // Copy the elements to the new location + var toCopy = _getCopyFromPaths(resolved.main, Env.user.userObject); + var newUserObject = newResolved.userObject; + newUserObject.copyFromOtherDrive(newResolved.path, toCopy.el, toCopy.data); + + // Filter owned pads so that we won't remove them from our drive + var toRemove = resolved.main.slice(); + toRemove.filter(function (id) { + var owners = Env.user.userObject.getFileData(id).owners; + return !Array.isArray(owners) || owners.indexOf(Env.edPublic) === -1; + }); + + // Remove the elements from the old location (without unpinning) + Env.user.userObject.delete(resolved.main, waitFor(), false, false, true); + } + } + var folderIds = Object.keys(resolved.folders); + if (folderIds.length) { + // Move from a shared folder + folderIds.forEach(function (fIdStr) { + var fId = Number(fIdStr); + var paths = resolved.folders[fId]; + if (newResolved.id === fId) { + // Move to the same shared folder + newResolved.userObject.move(paths, newResolved.path, waitFor()); + } else { + // Move to a different shared folder or to main drive + var uoFrom = Env.folders[fId].userObject; + var uoTo = newResolved.userObject; + + // Copy the elements to the new location + var toCopy = _getCopyFromPaths(paths, uoFrom); + uoTo.copyFromOtherDrive(newResolved.path, toCopy.el, toCopy.data); + + // Remove the elements from the old location (without unpinning) + uoFrom.delete(paths, waitFor(), false, false, true); + } + }); + } + }).nThen(function () { + cb(); + }); + }; + // Restore from the trash (main drive only) + var _restore = function (Env, data, cb) { + var userObject = Env.user.userObject; + data = data || {}; + userObject.restore(data.path, cb); + }; + // Add a folder/subfolder + var _addFolder = function (Env, data, cb) { + data = data || {}; + var resolved = _resolvePath(Env, data.path); + if (!resolved || !resolved.userObject) { return void cb({error: 'E_NOTFOUND'}); } + resolved.userObject.addFolder(resolved.path, data.name, cb); + }; + // Delete permanently some pads or folders + var _delete = function (Env, data, cb) { + data = data || {}; + var resolved = _resolvePaths(Env, data.paths); + if (!resolved.main.length && !Object.keys(resolved.folders).length) { + return void cb({error: 'E_NOTFOUND'}); + } + nThen(function (waitFor)  { + if (resolved.main.length) { + Env.user.userObject.delete(resolved.main, waitFor(), data.nocheck, + data.isOwnPadRemoved); + } + Object.keys(resolved.folders).forEach(function (id) { + Env.folders[id].userObject.delete(resolved.folders[id], waitFor(), data.nocheck, + data.isOwnPadRemoved); + }); + }).nThen(function () { + cb(); + }); + }; + // Empty the trash (main drive only) + var _emptyTrash = function (Env, data, cb) { + Env.user.userObject.emptyTrash(cb); + }; + // Rename files or folders + var _rename = function (Env, data, cb) { + data = data || {}; + var resolved = _resolvePath(Env, data.path); + if (!resolved || !resolved.userObject) { return void cb({error: 'E_NOTFOUND'}); } + resolved.userObject.rename(resolved.path, data.newName, cb); + }; + var onCommand = function (Env, cmdData, cb) { + var cmd = cmdData.cmd; + var data = cmdData.data || {}; + switch (cmd) { + case 'move': + _move(Env, data, cb); break; + //store.userObject.move(data.paths, data.newPath, cb2); break; + case 'restore': + _restore(Env, data, cb); break; + case 'addFolder': + _addFolder(Env, data, cb); break; + case 'delete': + _delete(Env, data, cb); break; + case 'emptyTrash': + _emptyTrash(Env, data, cb); break; + case 'rename': + _rename(Env, data, cb); break; + default: + cb(); + } + }; + + // Return files data objects associated to a channel for setPadTitle + // All occurences are returned, in drive or shared folders + var findChannel = function (Env, channel) { + var ret = []; + Env.user.userObject.findChannels([channel]).forEach(function (id) { + ret.push({ + data: Env.user.userObject.getFileData(id), + userObject: Env.user.userObject + }); + }); + Object.keys(Env.folders).forEach(function (fId) { + Env.folders[fId].userObject.findChannels([channel]).forEach(function (id) { + ret.push({ + data: Env.folders[fId].userObject.getFileData(id), + userObject: Env.folders[fId].userObject + }); + }); + }); + return ret; + }; + + // Get the list of channels that should be pinned + var getPinList = function (Env, edPublic) { + if (!edPublic) { return; } + var toPin = []; + var addChannel = function (userObject) { + return function (fileId) { + var data = userObject.getFileData(fileId); + // Don't pin pads owned by someone else + if (Array.isArray(data.owners) && data.owners.length && + data.owners.indexOf(edPublic) === -1) { return; } + // Don't push duplicates + if (toPin.indexOf(data.channel) === -1) { + toPin.push(data.channel); + } + }; + }; + + // Get the list of user objects + var userObjects = [Env.user.userObject]; + var foldersUO = Object.keys(Env.folders).map(function (k) { + return Env.folders[k].userObject; + }); + Array.prototype.push.apply(userObjects, foldersUO); + + userObjects.forEach(function (uo) { + var files = uo.getFiles([UserObject.FILES_DATA]); + files.forEach(addChannel(uo)); + }); + }; + + var create = function (proxy, edPublic, uoConfig) { + var Env = { + cfg: uoConfig, + edPublic: edPublic, + user: { + proxy: proxy, + userObject: UserObject.init(proxy, uoConfig) + }, + folders: {} + }; + + var callWithEnv = function (f) { + return function () { + [].unshift.call(arguments, Env); + return f.apply(null, arguments); + }; + }; + + return { + addProxy: callWithEnv(addProxy), + removeProxy: callWithEnv(removeProxy), + command: callWithEnv(onCommand), + findChannel: callWithEnv(findChannel), + getPinList: callWithEnv(getPinList), + resolvePath: callWithEnv(_resolvePath), + user: Env.user, + folders: Env.folders + }; + }; + + return { + create: create + }; +}); diff --git a/www/common/userObject.js b/www/common/userObject.js index f44310296..87a1653fa 100644 --- a/www/common/userObject.js +++ b/www/common/userObject.js @@ -29,6 +29,7 @@ define([ exp.UNSORTED = UNSORTED; exp.TRASH = TRASH; exp.TEMPLATE = TEMPLATE; + exp.SHARED_FOLDERS = SHARED_FOLDERS; // Logging var logging = function () { @@ -42,9 +43,6 @@ define([ console.error.apply(console, arguments); }; - // TODO: workgroup - var workgroup = config.workgroup; - if (pinPads) { // Extend "exp" with methods used only outside of the iframe (requires access to store) OuterFO.init(config, exp, files); @@ -89,6 +87,9 @@ define([ if (!isFolder(element)) { return false; } return Object.keys(element).length === 0; }; + exp.isSharedFolder = function (element) { + return Boolean(files[SHARED_FOLDERS][element]); + }; exp.hasSubfolder = function (element, trashRoot) { if (!isFolder(element)) { return false; } @@ -134,7 +135,6 @@ define([ // Data from filesData var getTitle = exp.getTitle = function (file, type) { - if (workgroup) { debug("No titles in workgroups"); return; } var data = getFileData(file); if (!file || !data || !(data.href || data.roHref)) { error("getTitle called with a non-existing file id: ", file, data); @@ -206,7 +206,8 @@ define([ // GET FILES - var getFilesRecursively = function (root, arr) { + var getFilesRecursively = exp.getFilesRecursively = function (root, arr) { + arr = arr || []; for (var e in root) { if (isFile(root[e])) { if(arr.indexOf(root[e]) === -1) { arr.push(root[e]); } @@ -214,6 +215,7 @@ define([ getFilesRecursively(root[e], arr); } } + return arr; }; var _getFiles = {}; _getFiles['array'] = function (cat) { @@ -552,18 +554,19 @@ define([ // DELETE // Permanently delete multiple files at once using a list of paths // NOTE: We have to be careful when removing elements from arrays (trash root, unsorted or template) - exp.delete = function (paths, cb, nocheck, isOwnPadRemoved) { + exp.delete = function (paths, cb, nocheck, isOwnPadRemoved, noUnpin) { if (sframeChan) { return void sframeChan.query("Q_DRIVE_USEROBJECT", { cmd: "delete", data: { paths: paths, nocheck: nocheck, + noUnpin: noUnpin, isOwnPadRemoved: isOwnPadRemoved } }, cb); } - exp.deleteMultiplePermanently(paths, nocheck, isOwnPadRemoved); + exp.deleteMultiplePermanently(paths, nocheck, isOwnPadRemoved, noUnpin); if (typeof cb === "function") { cb(); } }; exp.emptyTrash = function (cb) { diff --git a/www/drive/inner.js b/www/drive/inner.js index fb6f56bf4..a6fd5c9ec 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -244,27 +244,27 @@ define([ 'tabindex': '-1', 'data-icon': faTags, }, Messages.fc_hashtag)), - h('li', h('a.cp-app-drive-context-newdoc.dropdown-item.cp-app-drive-context-editable.cp-app-drive-context-own', { + h('li', h('a.cp-app-drive-context-newdoc.dropdown-item.cp-app-drive-context-editable', { 'tabindex': '-1', 'data-icon': AppConfig.applicationsIcon.pad, 'data-type': 'pad' }, Messages.button_newpad)), - h('li', h('a.cp-app-drive-context-newdoc.dropdown-item.cp-app-drive-context-editable.cp-app-drive-context-own', { + h('li', h('a.cp-app-drive-context-newdoc.dropdown-item.cp-app-drive-context-editable', { 'tabindex': '-1', 'data-icon': AppConfig.applicationsIcon.code, 'data-type': 'code' }, Messages.button_newcode)), - h('li', h('a.cp-app-drive-context-newdoc.dropdown-item.cp-app-drive-context-editable.cp-app-drive-context-own', { + h('li', h('a.cp-app-drive-context-newdoc.dropdown-item.cp-app-drive-context-editable', { 'tabindex': '-1', 'data-icon': AppConfig.applicationsIcon.slide, 'data-type': 'slide' }, Messages.button_newslide)), - h('li', h('a.cp-app-drive-context-newdoc.dropdown-item.cp-app-drive-context-editable.cp-app-drive-context-own', { + h('li', h('a.cp-app-drive-context-newdoc.dropdown-item.cp-app-drive-context-editable', { 'tabindex': '-1', 'data-icon': AppConfig.applicationsIcon.poll, 'data-type': 'poll' }, Messages.button_newpoll)), - h('li', h('a.cp-app-drive-context-newdoc.dropdown-item.cp-app-drive-context-editable.cp-app-drive-context-own', { + h('li', h('a.cp-app-drive-context-newdoc.dropdown-item.cp-app-drive-context-editable', { 'tabindex': '-1', 'data-icon': AppConfig.applicationsIcon.whiteboard, 'data-type': 'whiteboard' @@ -311,13 +311,6 @@ define([ var edPublic = priv.edPublic; APP.origin = priv.origin; - var isOwnDrive = function () { - return true; // TODO - }; - var isWorkgroup = function () { - return files.workgroup === 1; - }; - config.workgroup = isWorkgroup(); config.loggedIn = APP.loggedIn; config.sframeChan = sframeChan; @@ -357,11 +350,9 @@ define([ } // FILE MANAGER - // _WORKGROUP_ and other people drive : display Documents as main page - var currentPath = APP.currentPath = isOwnDrive() ? getLastOpenedFolder() : [ROOT]; + var currentPath = APP.currentPath = getLastOpenedFolder(); // Categories dislayed in the menu - // _WORKGROUP_ : do not display unsorted var displayedCategories = [ROOT, TRASH, SEARCH, RECENT]; // PCS enabled: display owned pads @@ -371,7 +362,6 @@ define([ // Tags used: display Tags category if (Object.keys(filesOp.getTagsList()).length) { displayedCategories.push(TAGS); } - if (isWorkgroup()) { displayedCategories = [ROOT, TRASH, SEARCH]; } var virtualCategories = [SEARCH, RECENT, OWNED, TAGS]; if (!APP.loggedIn) { @@ -856,7 +846,6 @@ define([ show.forEach(function (className) { var $el = $contextMenu.find('.cp-app-drive-context-' + className); if (!APP.editable && $el.is('.cp-app-drive-context-editable')) { return; } - if (!isOwnDrive && $el.is('.cp-app-drive-context-own')) { return; } if (filter($el, className)) { return; } $el.parent('li').show(); filtered.push('.cp-app-drive-context-' + className); @@ -1212,10 +1201,6 @@ define([ if (movedPaths && movedPaths.length) { moveElements(movedPaths, newPath, null, refresh); } - if (importedElements && importedElements.length) { - // TODO workgroup - //filesOp.importElements(importedElements, newPath, refresh); - } }; var addDragAndDropHandlers = function ($element, path, isFolder, droppable) { @@ -1266,7 +1251,6 @@ define([ addDragAndDropHandlers($content, null, true, true); // In list mode, display metadata from the filesData object - // _WORKGROUP_ : Do not display title, atime and ctime columns since we don't have files data var addFileData = function (element, $span) { if (!filesOp.isFile(element)) { return; } @@ -1323,10 +1307,7 @@ define([ var $cdate = $('', { 'class': 'cp-app-drive-element-ctime cp-app-drive-element-list' }).text(getDate(data.ctime)); - $span.append($type); - if (!isWorkgroup()) { - $span.append($adate).append($cdate); - } + $span.append($type).append($adate).append($cdate); }; var addFolderData = function (element, key, $span) { @@ -1804,7 +1785,6 @@ define([ $list.find('.' + classSorted).addClass('cp-app-drive-sort-active').prepend($icon); } }; - // _WORKGROUP_ : do not display title, atime and ctime in workgroups since we don't have files data var getFileListHeader = function () { var $fihElement = $('
  • ', { 'class': 'cp-app-drive-element-header cp-app-drive-element-list' @@ -1827,9 +1807,7 @@ define([ }).text(Messages.fm_creation).click(onSortByClick); // If displayTitle is false, it means the "name" is the title, so do not display the "name" header $fihElement.append($fhIcon).append($fhName).append($fhState).append($fhType); - if (!isWorkgroup()) { - $fihElement.append($fhAdate).append($fhCdate); - } + $fihElement.append($fhAdate).append($fhCdate); addFileSortIcon($fihElement); return $fihElement; }; @@ -2277,7 +2255,6 @@ define([ // Display the selected directory into the content part (rightside) // NOTE: Elements in the trash are not using the same storage structure as the others - // _WORKGROUP_ : do not change the lastOpenedFolder value in localStorage var _displayDirectory = function (path, force) { APP.hideMenu(); if (!APP.editable) { debug("Read-only mode"); } @@ -2331,9 +2308,7 @@ define([ $tree.find('#cp-app-drive-tree-search-input')[0].selectionEnd = getSearchCursor(); } - if (!isWorkgroup()) { - setLastOpenedFolder(path); - } + setLastOpenedFolder(path); var $toolbar = createToolbar(path); var $info = createInfoBox(path); From bd6a199dca64494b271f64b2caec15fe60554c29 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 5 Jul 2018 13:56:16 +0200 Subject: [PATCH 07/86] Add missing functions to the proxy manager --- www/common/outer/async-store.js | 145 +++++++++------------- www/common/proxy-manager.js | 211 +++++++++++++++++++++++++++----- 2 files changed, 241 insertions(+), 115 deletions(-) diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index b3601813a..70e5ee95b 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -33,12 +33,17 @@ define([ var store = window.CryptPad_AsyncStore = {}; - var onSync = function (cb) { - Realtime.whenRealtimeSyncs(store.realtime, cb); + nThen(function (waitFor) { + Realtime.whenRealtimeSyncs(store.realtime, waitFor()); + if (store.sharedFolders) { + for (var k in store.sharedFolders) { + Realtime.whenRealtimeSync(store.sharedFolders[k].realtime, waitFor()); + } + } + }).nThen(function () { cb(); }); }; - Store.get = function (clientId, key, cb) { cb(Util.find(store.proxy, key)); }; @@ -82,7 +87,7 @@ define([ // This list is filtered so that it doesn't include pad owned by other users // It now includes channels from shared folders var edPublic = store.proxy.edPublic; - var list = store.manager.getPinList(edPublic); + var list = store.manager.getChannelsList(edPublic, 'pin'); // Get the avatar var profile = store.proxy.profile; @@ -105,19 +110,8 @@ define([ }; var getExpirableChannelList = function () { - var list = []; - store.userObject.getFiles([store.userObject.FILES_DATA]).forEach(function (id) { - var data = store.userObject.getFileData(id); - var edPublic = store.proxy.edPublic; - - // Push channels owned by someone else or channel that should have expired - // because of the expiration time - if ((data.owners && data.owners.length && data.owners.indexOf(edPublic) === -1) || - (data.expire && data.expire < (+new Date()))) { - list.push(data.channel); - } - }); - return list; + var edPublic = store.proxy.edPublic; + return store.manager.getChannelsList(edPublic, 'expirable'); }; var getCanonicalChannelList = function (expirable) { @@ -445,16 +439,8 @@ define([ if (data.expire) { pad.expire = data.expire; } if (data.password) { pad.password = data.password; } if (data.channel) { pad.channel = data.channel; } - var uo = store.userObject; - var path = ['root']; - if (data.path) { - var resolved = store.manager.resolvePath(path); - uo = resolved.userObject; - path = resolved.path; - } - uo.pushData(pad, function (e, id) { + store.manager.addPad(data.path, pad, function (e) { if (e) { return void cb({error: "Error while adding a template:"+ e}); } - uo.add(id, path); sendDriveEvent('DRIVE_CHANGE', { path: ['drive', UserObject.FILES_DATA] }, clientId); @@ -463,17 +449,8 @@ define([ }; var getOwnedPads = function () { - var list = []; - store.userObject.getFiles([store.userObject.FILES_DATA]).forEach(function (id) { - var data = store.userObject.getFileData(id); - var edPublic = store.proxy.edPublic; - - // Push channels owned by someone else or channel that should have expired - // because of the expiration time - if (data.owners && data.owners.length === 1 && data.owners.indexOf(edPublic) !== -1) { - list.push(data.channel); - } - }); + var edPublic = store.proxy.edPublic; + var list = store.manager.getChannelsList(edPublic, 'owned'); if (store.proxy.todo) { // No password for todo list.push(Hash.hrefToHexChannelId('/todo/#' + store.proxy.todo, null)); @@ -595,33 +572,6 @@ define([ }); }; - var getAttributeObject = function (attr) { - if (typeof attr === "string") { - console.error('DEPRECATED: use setAttribute with an array, not a string'); - return { - path: ['settings'], - obj: store.proxy.settings, - key: attr - }; - } - if (!Array.isArray(attr)) { return void console.error("Attribute must be string or array"); } - if (attr.length === 0) { return void console.error("Attribute can't be empty"); } - var obj = store.proxy.settings; - attr.forEach(function (el, i) { - if (i === attr.length-1) { return; } - if (!obj[el]) { - obj[el] = {}; - } - else if (typeof obj[el] !== "object") { return void console.error("Wrong attribute"); } - obj = obj[el]; - }); - return { - path: ['settings'].concat(attr), - obj: obj, - key: attr[attr.length-1] - }; - }; - // Set the display name (username) in the proxy Store.setDisplayName = function (clientId, value, cb) { store.proxy[Constants.displayNameKey] = value; @@ -650,7 +600,7 @@ define([ * - value (String) */ Store.setPadAttribute = function (clientId, data, cb) { - store.userObject.setPadAttribute(data.href, data.attr, data.value, function () { + store.manager.setPadAttribute(data, function () { sendDriveEvent('DRIVE_CHANGE', { path: ['drive', UserObject.FILES_DATA] }, clientId); @@ -658,11 +608,38 @@ define([ }); }; Store.getPadAttribute = function (clientId, data, cb) { - store.userObject.getPadAttribute(data.href, data.attr, function (err, val) { + store.manager.getPadAttribute(data, function (err, val) { if (err) { return void cb({error: err}); } cb(val); }); }; + + var getAttributeObject = function (attr) { + if (typeof attr === "string") { + console.error('DEPRECATED: use setAttribute with an array, not a string'); + return { + path: ['settings'], + obj: store.proxy.settings, + key: attr + }; + } + if (!Array.isArray(attr)) { return void console.error("Attribute must be string or array"); } + if (attr.length === 0) { return void console.error("Attribute can't be empty"); } + var obj = store.proxy.settings; + attr.forEach(function (el, i) { + if (i === attr.length-1) { return; } + if (!obj[el]) { + obj[el] = {}; + } + else if (typeof obj[el] !== "object") { return void console.error("Wrong attribute"); } + obj = obj[el]; + }); + return { + path: ['settings'].concat(attr), + obj: obj, + key: attr[attr.length-1] + }; + }; Store.setAttribute = function (clientId, data, cb) { try { var object = getAttributeObject(data.attr); @@ -680,11 +657,12 @@ define([ // Tags Store.listAllTags = function (clientId, data, cb) { - cb(store.userObject.getTagsList()); + cb(store.manager.getTagsList()); }; // Templates Store.getTemplates = function (clientId, data, cb) { + // No templates in shared folders: we don't need the manager here var templateFiles = store.userObject.getFiles(['template']); var res = []; templateFiles.forEach(function (f) { @@ -694,6 +672,7 @@ define([ cb(res); }; Store.incrementTemplateUse = function (clientId, href) { + // No templates in shared folders: we don't need the manager here store.userObject.getPadAttribute(href, 'used', function (err, data) { // This is a not critical function, abort in case of error to make sure we won't // create any issue with the user object or the async store @@ -705,6 +684,7 @@ define([ // Pads Store.moveToTrash = function (clientId, data, cb) { + // XXX move a pad from a shared folder to the trash? var href = Hash.getRelativeHref(data.href); store.userObject.forget(href); sendDriveEvent('DRIVE_CHANGE', { @@ -785,7 +765,6 @@ define([ // Filepicker app Store.getSecureFilesList = function (clientId, query, cb) { var list = {}; - var hashes = []; var types = query.types; var where = query.where; var filter = query.filter || {}; @@ -800,19 +779,19 @@ define([ } return filtered; }; - store.userObject.getFiles(where).forEach(function (id) { - var data = store.userObject.getFileData(id); + store.manager.getSecureFilesList(where).forEach(function (obj) { + var data = obj.data; + var id = obj.id; var parsed = Hash.parsePadUrl(data.href || data.roHref); if ((!types || types.length === 0 || types.indexOf(parsed.type) !== -1) && - hashes.indexOf(parsed.hash) === -1 && !isFiltered(parsed.type, data)) { - hashes.push(parsed.hash); list[id] = data; } }); cb(list); }; Store.getPadData = function (clientId, id, cb) { + // FIXME: this is only used for templates at the moment, so we don't need the manager cb(store.userObject.getFileData(id)); }; @@ -1159,7 +1138,7 @@ define([ }; // SHARED FOLDERS - var loadSharedFolder = function (id, data) { + var loadSharedFolder = function (id, data, cb) { var parsed = Hash.parsePadUrl(data.href); var secret = Hash.getSecrets('folder', parsed.hash, data.password); var listmapConfig = { @@ -1176,14 +1155,17 @@ define([ }; var rt = Listmap.create(listmapConfig); store.sharedFolders[id] = rt; - store.manager.addProxy(rt.proxy); + rt.proxy.on('ready', function (info) { + store.manager.addProxy(id, rt.proxy, info.leave); + cb(rt); + }); return rt; }; Store.addSharedFolder = function (clientId, data, cb) { var path = data.path; var id; nThen(function (waitFor) { - // TODO + // TODO XXX get the folder data (href, title, ...) var folderData = {}; // 1. add the shared folder to our list of shared folders store.userObject.pushSharedFolder(folderData, waitFor(function (err, folderId) { @@ -1199,11 +1181,7 @@ define([ onSync(waitFor()); // 2b. load the proxy - var rt = loadSharedFolder(id, data); - rt.on('ready', waitFor(function () { - // TODO - // "fixFiles" - })); + loadSharedFolder(id, data, waitFor()); }).nThen(function () { sendDriveEvent('DRIVE_CHANGE', { path: ['drive'].concat(path) @@ -1347,16 +1325,11 @@ define([ ////////////////////////////////////////////////////////////////// var loadSharedFolders = function (waitFor) { - // TODO store.sharedFolders = {}; var shared = Util.find(store.proxy, ['drive', UserObject.SHARED_FOLDERS]) || {}; Object.keys(shared).forEach(function (id) { var sf = shared[id]; - var rt = loadSharedFolder(id, sf); - rt.on('ready', waitFor(function () { - // TODO - // "fixFiles" - })); + loadSharedFolder(id, sf, waitFor()); }); }; diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index 9b774b86d..bacbb0d9f 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -35,9 +35,57 @@ define([ }; /* - Paths + Tools */ + var _getUserObjects = function (Env) { + var userObjects = [Env.user.userObject]; + var foldersUO = Object.keys(Env.folders).map(function (k) { + return Env.folders[k].userObject; + }); + Array.prototype.push.apply(userObjects, foldersUO); + return userObjects; + }; + + // Return files data objects associated to a channel for setPadTitle + // All occurences are returned, in drive or shared folders + var findChannel = function (Env, channel) { + var ret = []; + Env.user.userObject.findChannels([channel]).forEach(function (id) { + ret.push({ + data: Env.user.userObject.getFileData(id), + userObject: Env.user.userObject + }); + }); + Object.keys(Env.folders).forEach(function (fId) { + Env.folders[fId].userObject.findChannels([channel]).forEach(function (id) { + ret.push({ + data: Env.folders[fId].userObject.getFileData(id), + userObject: Env.folders[fId].userObject + }); + }); + }); + return ret; + }; + // Return files data objects associated to a given href for setPadAttribute... + var findHref = function (Env, href) { + var ret = []; + var id = Env.user.userObject.getIdFromHref(href); + ret.push({ + data: Env.user.userObject.getFileData(id), + userObject: Env.user.userObject + }); + Object.keys(Env.folders).forEach(function (fId) { + var id = Env.folders[fId].userObject.getIdFromHref(href); + ret.push({ + fId: fId, + data: Env.folders[fId].userObject.getFileData(id), + userObject: Env.folders[fId].userObject + }); + }); + return ret; + }; + // Transform an absolute path into a path relative to the correct shared folder var _resolvePath = function (Env, path) { var res = { @@ -123,7 +171,7 @@ define([ }; /* - RPC commands + Drive RPC */ // Move files or folders in the drive @@ -251,55 +299,152 @@ define([ } }; - // Return files data objects associated to a channel for setPadTitle - // All occurences are returned, in drive or shared folders - var findChannel = function (Env, channel) { - var ret = []; - Env.user.userObject.findChannels([channel]).forEach(function (id) { - ret.push({ - data: Env.user.userObject.getFileData(id), - userObject: Env.user.userObject - }); + // Set the value everywhere the given pad is stored (main and shared folders) + var setPadAttribute = function (Env, data, cb) { + cb = cb || function () {}; + var datas = findHref(Env, data.href); + var nt = nThen; + datas.forEach(function (d) { + nt = nt(function (waitFor) { + d.userObject.setPadAttribute(data.href, data.attr, data.value, waitFor()); + }).nThen; }); - Object.keys(Env.folders).forEach(function (fId) { - Env.folders[fId].userObject.findChannels([channel]).forEach(function (id) { - ret.push({ - data: Env.folders[fId].userObject.getFileData(id), - userObject: Env.folders[fId].userObject + nt(function () { cb(); }); + }; + // Get pad attribute must return only one value, even if the pad is stored in multiple places + // (main or shared folders) + // We're going to return the value with the most recent atime. The attributes may have been + // updated in a shared folder by another user, so the most recent one is more likely to be the + // correct one. + var getPadAttribute = function (Env, data, cb) { + cb = cb || function () {}; + var datas = findHref(Env, data.href); + var nt = nThen; + var res = {}; + datas.forEach(function (d) { + nt = nt(function (waitFor) { + var atime, value; + var w = waitFor(); + nThen(function (waitFor2) { + d.userObject.getPadAttribute(data.href, 'atime', waitFor2(function (err, v) { + atime = v; + })); + d.userObject.getPadAttribute(data.href, data.attr, waitFor2(function (err, v) { + value = v; + })); + }).nThen(function () { + if (!res.value || res.atime < atime) { + res.atime = atime; + res.value = value; + } + w(); }); + }).nThen; + }); + nt(function () { cb(null, res.value); }); + }; + + var getTagsList = function (Env) { + var list = []; + var userObjects = _getUserObjects(Env); + userObjects.forEach(function (uo) { + Array.prototype.push.apply(list, uo.getTagsList()); + }); + Util.deduplicateString(list); + return list; + }; + + var getSecureFilesList = function (Env, where) { + var userObjects = _getUserObjects(Env); + var list = []; + var channels = []; + userObjects.forEach(function (uo) { + var toPush = uo.getFiles(where).map(function (id) { + return { + id: id, + data: uo.getFileData(id) + }; + }).filter(function (d) { + if (channels.indexOf(d.data.channel) === -1) { + channels.push(d.data.channel); + return true; + } }); + Array.prototype.push.apply(list, toPush); }); - return ret; + return list; }; - // Get the list of channels that should be pinned - var getPinList = function (Env, edPublic) { + + /* + Store + */ + + // Get the list of channels filtered by a type (expirable channels, owned channels, pin list) + var getChannelsList = function (Env, edPublic, type) { if (!edPublic) { return; } - var toPin = []; + var result = []; var addChannel = function (userObject) { + if (type === 'expirable') { + return function (fileId) { + var data = userObject.getFileData(fileId); + // Don't push duplicates + if (result.indexOf(data.channel) !== -1) { return; } + // Return pads owned by someone else or expired by time + if ((data.owners && data.owners.length && data.owners.indexOf(edPublic) === -1) || + (data.expire && data.expire < (+new Date()))) { + result.push(data.channel); + } + }; + } + if (type === 'owned') { + return function (fileId) { + var data = userObject.getFileData(fileId); + // Don't push duplicates + if (result.indexOf(data.channel) !== -1) { return; } + // Return owned pads + if (Array.isArray(data.owners) && data.owners.length && + data.owners.indexOf(edPublic) !== -1) { + result.push(data.channel); + } + }; + } return function (fileId) { var data = userObject.getFileData(fileId); // Don't pin pads owned by someone else if (Array.isArray(data.owners) && data.owners.length && data.owners.indexOf(edPublic) === -1) { return; } // Don't push duplicates - if (toPin.indexOf(data.channel) === -1) { - toPin.push(data.channel); + if (result.indexOf(data.channel) === -1) { + result.push(data.channel); } }; }; // Get the list of user objects - var userObjects = [Env.user.userObject]; - var foldersUO = Object.keys(Env.folders).map(function (k) { - return Env.folders[k].userObject; - }); - Array.prototype.push.apply(userObjects, foldersUO); + var userObjects = _getUserObjects(Env); userObjects.forEach(function (uo) { var files = uo.getFiles([UserObject.FILES_DATA]); files.forEach(addChannel(uo)); }); + + return result; + }; + + var addPad = function (Env, path, pad, cb) { + var uo = Env.user.userObject; + var p = ['root']; + if (path) { + var resolved = _resolvePath(Env, path); + uo = resolved.userObject; + p = resolved.path; + } + uo.pushData(pad, function (e, id) { + if (e) { return void cb(e); } + uo.add(id, p); + cb(); + }); }; var create = function (proxy, edPublic, uoConfig) { @@ -321,12 +466,20 @@ define([ }; return { + // Manager addProxy: callWithEnv(addProxy), removeProxy: callWithEnv(removeProxy), + // Drive command: callWithEnv(onCommand), + getPadAttribute: callWithEnv(getPadAttribute), + setPadAttribute: callWithEnv(setPadAttribute), + getTagsList: callWithEnv(getTagsList), + getSecureFilesList: callWithEnv(getSecureFilesList), + // Store + getChannelsList: callWithEnv(getChannelsList), + addPad: callWithEnv(addPad), + // Tools findChannel: callWithEnv(findChannel), - getPinList: callWithEnv(getPinList), - resolvePath: callWithEnv(_resolvePath), user: Env.user, folders: Env.folders }; From 0c9dfc1fb55ed1839831639ecbe32ef17d5ee421 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 5 Jul 2018 16:33:37 +0200 Subject: [PATCH 08/86] Add proxy manager inner --- www/common/proxy-manager.js | 265 +++++++++++++++++++++++++++++++++++- www/common/userObject.js | 3 + www/drive/inner.js | 263 ++++++++++++++++++----------------- 3 files changed, 399 insertions(+), 132 deletions(-) diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index bacbb0d9f..ac2feb883 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -149,7 +149,7 @@ define([ // Remove the shared folder from this list of files ID files.filter(function (f) { return !userObject.isSharedFolder(f); }); // Deduplicate - Util.deduplicateString(files); + files = Util.deduplicateString(files); // Get the files data associated to these files var filesData = {}; @@ -350,7 +350,7 @@ define([ userObjects.forEach(function (uo) { Array.prototype.push.apply(list, uo.getTagsList()); }); - Util.deduplicateString(list); + list = Util.deduplicateString(list); return list; }; @@ -391,8 +391,8 @@ define([ // Don't push duplicates if (result.indexOf(data.channel) !== -1) { return; } // Return pads owned by someone else or expired by time - if ((data.owners && data.owners.length && data.owners.indexOf(edPublic) === -1) || - (data.expire && data.expire < (+new Date()))) { + if ((data.owners && data.owners.length && data.owners.indexOf(edPublic) === -1) + || (data.expire && data.expire < (+new Date()))) { result.push(data.channel); } }; @@ -485,7 +485,262 @@ define([ }; }; + /* + Inner only + */ + + var renameInner = function (Env, path, newName, cb) { + return void Env.sframeChan.query("Q_DRIVE_USEROBJECT", { + cmd: "rename", + data: { + path: path, + newName: newName + } + }, cb); + }; + var moveInner = function (Env, paths, newPath, cb) { + return void Env.sframeChan.query("Q_DRIVE_USEROBJECT", { + cmd: "move", + data: { + paths: paths, + newPath: newPath + } + }, cb); + }; + var emptyTrashInner = function (Env, cb) { + return void Env.sframeChan.query("Q_DRIVE_USEROBJECT", { + cmd: "emptyTrash" + }, cb); + }; + var addFolderInner = function (Env, path, name, cb) { + return void Env.sframeChan.query("Q_DRIVE_USEROBJECT", { + cmd: "addFolder", + data: { + path: path, + name: name + } + }, cb); + }; + var deleteInner = function (Env, paths, cb, nocheck, isOwnPadRemoved, noUnpin) { + return void Env.sframeChan.query("Q_DRIVE_USEROBJECT", { + cmd: "delete", + data: { + paths: paths, + nocheck: nocheck, + noUnpin: noUnpin, + isOwnPadRemoved: isOwnPadRemoved + } + }, cb); + }; + var restoreInner = function (Env, path, cb) { + return void Env.sframeChan.query("Q_DRIVE_USEROBJECT", { + cmd: "restore", + data: { + path: path + } + }, cb); + }; + + /* Tools */ + + var _getUserObjectFromId = function (Env, id) { + var userObjects = _getUserObjects(Env); + var userObject = Env.user.userObject; + userObjects.some(function (uo) { + if (Object.keys(uo.getFileData(id)).length) { + userObject = uo; + return true; + } + }); + return userObject; + }; + + var _getUserObjectPath = function (Env, uo) { + var fId = uo.id; + if (!fId) { return; } + var fPath = Env.user.userObject.findFile(fId)[0]; + return fPath; + }; + + var getFileData = function (Env, id) { + var userObjects = _getUserObjects(Env); + var data = {}; + userObjects.some(function (uo) { + data = uo.getFileData(id); + if (Object.keys(data).length) { return true; } + }); + return data; + }; + + var find = function (Env, path) { + var resolved = _resolvePath(Env, path); + return resolved.userObject.find(path); + }; + + var getTitle = function (Env, id, type) { + var uo = _getUserObjectFromId(Env, id); + return uo.getTitle(id, type); + }; + + var isReadOnlyFile = function (Env, id) { + var uo = _getUserObjectFromId(Env, id); + return uo.isReadOnlyFile(id); + }; + + var getFiles = function (Env, categories) { + var files = []; + var userObjects = _getUserObjects(Env); + userObjects.forEach(function (uo) { + Array.prototype.push.apply(files, uo.getFiles(categories)); + }); + files = Util.deduplicateString(files); + return files; + }; + + var search = function (Env, value) { + var ret = []; + var userObjects = _getUserObjects(Env); + userObjects.forEach(function (uo) { + var fPath = _getUserObjectPath(Env, uo); + var results = uo.search(value); + if (fPath) { + // This is a shared folder, we have to fix the paths in the search results + results = results.map(function (r) { + r.paths.map(function (p) { + Array.prototype.unshift.apply(p, fPath); + }); + }); + } + // Push the results from this proxy + Array.prototype.push.apply(ret, results); + }); + return ret; + }; + + var findFile = function (Env, id) { + var ret = []; + var userObjects = _getUserObjects(Env); + userObjects.forEach(function (uo) { + var fPath = _getUserObjectPath(Env, uo); + var results = uo.findFile(id); + if (fPath) { + // This is a shared folder, we have to fix the paths in the results + results = results.map(function (p) { + Array.prototype.unshift.apply(p, fPath); + }); + } + // Push the results from this proxy + Array.prototype.push.apply(ret, results); + }); + return ret; + }; + + var findChannels = function (Env, channels) { + var ret = []; + var userObjects = _getUserObjects(Env); + userObjects.forEach(function (uo) { + var results = uo.findChannels(channels); + Array.prototype.push.apply(ret, results); + }); + ret = Util.deduplicateString(ret); + return ret; + }; + + var getRecentPads = function (Env) { + return Env.user.userObject.getRecentPads(); + }; + var getOwnedPads = function (Env, edPublic) { + return Env.user.userObject.getOwnedPads(edPublic); + }; + + /* Generic: doesn't need access to a proxy */ + var isFile = function (Env, el, allowStr) { + return Env.user.userObject.isFile(el, allowStr); + }; + var isFolder = function (Env, el) { + return Env.user.userObject.isFolder(el); + }; + var isFolderEmpty = function (Env, el) { + return Env.user.userObject.isFolderEmpty(el); + }; + var isPathIn = function (Env, path, categories) { + return Env.user.userObject.isPathIn(path, categories); + }; + var isSubpath = function (Env, path, parentPath) { + return Env.user.userObject.isSubpath(path, parentPath); + }; + var isInTrashRoot = function (Env, path) { + return Env.user.userObject.isInTrashRoot(path); + }; + var comparePath = function (Env, a, b) { + return Env.user.userObject.comparePath(a, b); + }; + var hasSubfolder = function (Env, el, trashRoot) { + return Env.user.userObject.hasSubfolder(el, trashRoot); + }; + var hasFile = function (Env, el, trashRoot) { + return Env.user.userObject.hasFile(el, trashRoot); + }; + + var createInner = function (proxy, sframeChan, uoConfig) { + var Env = { + cfg: uoConfig, + sframeChan: sframeChan, + user: { + proxy: proxy, + userObject: UserObject.init(proxy, uoConfig) + }, + folders: {} + }; + + var callWithEnv = function (f) { + return function () { + [].unshift.call(arguments, Env); + return f.apply(null, arguments); + }; + }; + + return { + // Manager + addProxy: callWithEnv(addProxy), + removeProxy: callWithEnv(removeProxy), + // Drive RPC commands + rename: callWithEnv(renameInner), + move: callWithEnv(moveInner), + emptyTrash: callWithEnv(emptyTrashInner), + addFolder: callWithEnv(addFolderInner), + delete: callWithEnv(deleteInner), + restore: callWithEnv(restoreInner), + // Tools + getFileData: callWithEnv(getFileData), + find: callWithEnv(find), + getTitle: callWithEnv(getTitle), + isReadOnlyFile: callWithEnv(isReadOnlyFile), + getFiles: callWithEnv(getFiles), + search: callWithEnv(search), + getRecentPads: callWithEnv(getRecentPads), + getOwnedPads: callWithEnv(getOwnedPads), + getTagsList: callWithEnv(getTagsList), + findFile: callWithEnv(findFile), + findChannels: callWithEnv(findChannels), + // Generic + isFile: callWithEnv(isFile), + isFolder: callWithEnv(isFolder), + isFolderEmpty: callWithEnv(isFolderEmpty), + isPathIn: callWithEnv(isPathIn), + isSubpath: callWithEnv(isSubpath), + isinTrashRoot: callWithEnv(isInTrashRoot), + comparePath: callWithEnv(comparePath), + hasSubfolder: callWithEnv(hasSubfolder), + hasFile: callWithEnv(hasFile), + // Data + user: Env.user, + folders: Env.folders + }; + }; + return { - create: create + create: create, + createInner: createInner }; }); diff --git a/www/common/userObject.js b/www/common/userObject.js index 87a1653fa..9dbfe4869 100644 --- a/www/common/userObject.js +++ b/www/common/userObject.js @@ -31,6 +31,9 @@ define([ exp.TEMPLATE = TEMPLATE; exp.SHARED_FOLDERS = SHARED_FOLDERS; + exp.sharedFolder = config.sharedFolder; + exp.id = config.id; + // Logging var logging = function () { console.log.apply(console, arguments); diff --git a/www/drive/inner.js b/www/drive/inner.js index a6fd5c9ec..fe981d4e3 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -12,7 +12,7 @@ define([ '/common/sframe-common.js', '/common/common-realtime.js', '/common/hyperscript.js', - '/common/userObject.js', + '/common/proxy-manager.js', '/customize/application_config.js', '/bower_components/chainpad-listmap/chainpad-listmap.js', '/customize/messages.js', @@ -34,7 +34,7 @@ define([ SFCommon, CommonRealtime, h, - FO, + ProxyManager, AppConfig, Listmap, Messages) @@ -302,7 +302,7 @@ define([ return $(menu); }; - var andThen = function (common, proxy) { + var andThen = function (common, proxy, folders) { var files = proxy.drive; var metadataMgr = common.getMetadataMgr(); var sframeChan = common.getSframeChannel(); @@ -315,8 +315,15 @@ define([ config.sframeChan = sframeChan; - var filesOp = FO.init(files, config); - var error = filesOp.error; + var manager = ProxyManager.createInner(files, sframeChan, config); + + Object.keys(folders).forEach(function (id) { + var f = folders[id]; + // f.data => metadata (href, title, password...) + // f.proxy => listmap + // f.id => id? + manager.addProxy(id, f.proxy); + }); var $tree = APP.$tree = $("#cp-app-drive-tree"); var $content = APP.$content = $("#cp-app-drive-content"); @@ -360,7 +367,7 @@ define([ // Templates enabled: display template category if (AppConfig.enableTemplates) { displayedCategories.push(TEMPLATE); } // Tags used: display Tags category - if (Object.keys(filesOp.getTagsList()).length) { displayedCategories.push(TAGS); } + if (Object.keys(manager.getTagsList()).length) { displayedCategories.push(TAGS); } var virtualCategories = [SEARCH, RECENT, OWNED, TAGS]; @@ -622,7 +629,7 @@ define([ var removeInput = function (cancel) { if (!cancel && $('.cp-app-drive-element-row > input').length === 1) { var $input = $('.cp-app-drive-element-row > input'); - filesOp.rename($input.data('path'), $input.val(), APP.refresh); + manager.rename($input.data('path'), $input.val(), APP.refresh); } $('.cp-app-drive-element-row > input').remove(); $('.cp-app-drive-element-row > span:hidden').removeAttr('style'); @@ -648,14 +655,14 @@ define([ ret = date.toLocaleDateString(); } } catch (e) { - error("Unable to format that string to a date with .toLocaleString", sDate, e); + console.error("Unable to format that string to a date with .toLocaleString", sDate, e); } return ret; }; var openFile = function (el, href) { if (!href) { - var data = filesOp.getFileData(el); + var data = manager.getFileData(el); if (!data || (!data.href && !data.roHref)) { return void logError("Missing data for the file", el, data); } @@ -690,8 +697,8 @@ define([ $name = $element.find('> .cp-app-drive-element'); } $name.hide(); - var el = filesOp.find(path); - var name = filesOp.isFile(el) ? filesOp.getTitle(el) : path[path.length - 1]; + var el = manager.find(path); + var name = manager.isFile(el) ? manager.getTitle(el) : path[path.length - 1]; var $input = $('', { placeholder: name, value: name @@ -705,7 +712,7 @@ define([ e.stopPropagation(); if (e.which === 13) { removeInput(true); - filesOp.rename(path, $input.val(), refresh); + manager.rename(path, $input.val(), refresh); return; } if (e.which === 27) { @@ -880,7 +887,7 @@ define([ }; var updateContextButton = function () { - if (filesOp.isPathIn(currentPath, [TRASH])) { + if (manager.isPathIn(currentPath, [TRASH])) { $driveToolbar.find('cp-app-drive-toolbar-emptytrash').show(); } else { $driveToolbar.find('cp-app-drive-toolbar-emptytrash').hide(); @@ -1098,19 +1105,19 @@ define([ }; var getElementName = function (path) { - var file = filesOp.find(path); - if (!file || !filesOp.isFile(file)) { return '???'; } - return filesOp.getTitle(file); + var file = manager.find(path); + if (!file || !manager.isFile(file)) { return '???'; } + return manager.getTitle(file); }; - // filesOp.moveElements is able to move several paths to a new location, including + // manager.moveElements is able to move several paths to a new location, including // the Trash or the "Unsorted files" folder var moveElements = function (paths, newPath, force, cb) { if (!APP.editable) { return; } var andThenMove = function () { - filesOp.move(paths, newPath, cb); + manager.move(paths, newPath, cb); }; // Cancel drag&drop from TRASH to TRASH - if (filesOp.isPathIn(newPath, [TRASH]) && paths.length && paths[0][0] === TRASH) { + if (manager.isPathIn(newPath, [TRASH]) && paths.length && paths[0][0] === TRASH) { return; } andThenMove(); @@ -1125,7 +1132,7 @@ define([ $selected.each(function (idx, elmt) { var ePath = $(elmt).data('path'); if (ePath) { - var val = filesOp.find(ePath); + var val = manager.find(ePath); if (!val) { return; } // Error? A ".selected" element in not in the object paths.push({ path: ePath, @@ -1139,7 +1146,7 @@ define([ } else { removeSelected(); $element.addClass('cp-app-drive-element-selected'); - var val = filesOp.find(path); + var val = manager.find(path); if (!val) { return; } // The element in not in the object paths = [{ path: path, @@ -1159,7 +1166,7 @@ define([ var $target = $(target); var $el = findDataHolder($target); var newPath = $el.data('path'); - if ((!newPath || filesOp.isFile(filesOp.find(newPath))) + if ((!newPath || manager.isFile(manager.find(newPath))) && $target.parents('#cp-app-drive-content')) { newPath = currentPath; } @@ -1188,7 +1195,7 @@ define([ var movedPaths = []; var importedElements = []; oldPaths.forEach(function (p) { - var el = filesOp.find(p.path); + var el = manager.find(p.path); if (el && (stringify(el) === stringify(p.value.el) || !p.value || !p.value.el)) { movedPaths.push(p.path); } else { @@ -1252,9 +1259,9 @@ define([ // In list mode, display metadata from the filesData object var addFileData = function (element, $span) { - if (!filesOp.isFile(element)) { return; } + if (!manager.isFile(element)) { return; } - var data = filesOp.getFileData(element); + var data = manager.getFileData(element); var href = data.href || data.roHref; if (!data) { return void logError("No data for the file", element); } @@ -1281,7 +1288,7 @@ define([ $owner.attr('title', Messages.fm_padIsOwnedOther); } - var name = filesOp.getTitle(element); + var name = manager.getTitle(element); // The element with the class '.name' is underlined when the 'li' is hovered var $name = $('', {'class': 'cp-app-drive-element-name'}).text(name); @@ -1311,10 +1318,10 @@ define([ }; var addFolderData = function (element, key, $span) { - if (!element || !filesOp.isFolder(element)) { return; } + if (!element || !manager.isFolder(element)) { return; } // The element with the class '.name' is underlined when the 'li' is hovered - var sf = filesOp.hasSubfolder(element); - var files = filesOp.hasFile(element); + var sf = manager.hasSubfolder(element); + var files = manager.hasFile(element); var $name = $('', {'class': 'cp-app-drive-element-name'}).text(key); var $state = $('', {'class': 'cp-app-drive-element-state'}); var $subfolders = $('', { @@ -1329,7 +1336,7 @@ define([ // This is duplicated in cryptpad-common, it should be unified var getFileIcon = function (id) { - var data = filesOp.getFileData(id); + var data = manager.getFileData(id); return UI.getFileIcon(data); }; var getIcon = UI.getIcon; @@ -1348,16 +1355,16 @@ define([ newPath.push(key); } - var element = filesOp.find(newPath); + var element = manager.find(newPath); var $icon = !isFolder ? getFileIcon(element) : undefined; - var ro = filesOp.isReadOnlyFile(element); + var ro = manager.isReadOnlyFile(element); // ro undefined means it's an old hash which doesn't support read-only var roClass = typeof(ro) === 'undefined' ?' cp-app-drive-element-noreadonly' : ro ? ' cp-app-drive-element-readonly' : ''; var liClass = 'cp-app-drive-element-file cp-app-drive-element' + roClass; if (isFolder) { liClass = 'cp-app-drive-element-folder cp-app-drive-element'; - $icon = filesOp.isFolderEmpty(root[key]) ? $folderEmptyIcon.clone() : $folderIcon.clone(); + $icon = manager.isFolderEmpty(root[key]) ? $folderEmptyIcon.clone() : $folderIcon.clone(); } var $element = $('
  • ', { draggable: true, @@ -1397,7 +1404,7 @@ define([ $element.contextmenu(openContextMenu('trash')); $element.data('context', 'trash'); } - var isNewFolder = APP.newFolder && filesOp.comparePath(newPath, APP.newFolder); + var isNewFolder = APP.newFolder && manager.comparePath(newPath, APP.newFolder); if (isNewFolder) { appStatus.onReady(function () { window.setTimeout(function () { displayRenameInput($element, newPath); }, 0); @@ -1444,12 +1451,12 @@ define([ // Create the title block with the "parent folder" button var createTitle = function ($container, path, noStyle) { if (!path || path.length === 0) { return; } - var isTrash = filesOp.isPathIn(path, [TRASH]); + var isTrash = manager.isPathIn(path, [TRASH]); if (APP.mobile() && !noStyle) { // noStyle means title in search result return $container; } var isVirtual = virtualCategories.indexOf(path[0]) !== -1; - var el = isVirtual ? undefined : filesOp.find(path); + var el = isVirtual ? undefined : manager.find(path); path = path[0] === SEARCH ? path.slice(0,1) : path; path.forEach(function (p, idx) { if (isTrash && [2,3].indexOf(idx) !== -1) { return; } @@ -1466,7 +1473,7 @@ define([ APP.displayDirectory(path.slice(0, sliceEnd)); }); } - } else if (idx > 0 && filesOp.isFile(el)) { + } else if (idx > 0 && manager.isFile(el)) { name = getElementName(path); } @@ -1569,7 +1576,7 @@ define([ $button.click(function () { UI.confirm(Messages.fm_emptyTrashDialog, function(res) { if (!res) { return; } - filesOp.emptyTrash(refresh); + manager.emptyTrash(refresh); }); }); $container.append($button); @@ -1605,7 +1612,7 @@ define([ }; $block.find('a.cp-app-drive-new-folder, li.cp-app-drive-new-folder') .click(function () { - filesOp.addFolder(currentPath, null, onCreated); + manager.addFolder(currentPath, null, onCreated); }); $block.find('a.cp-app-drive-new-upload, li.cp-app-drive-new-upload') .click(function () { @@ -1626,7 +1633,7 @@ define([ $block.find('a.cp-app-drive-new-doc, li.cp-app-drive-new-doc') .click(function () { var type = $(this).attr('data-type') || 'pad'; - var path = filesOp.isPathIn(currentPath, [TRASH]) ? '' : currentPath; + var path = manager.isPathIn(currentPath, [TRASH]) ? '' : currentPath; common.sessionStorage.put(Constants.newPadPathKey, path, function () { common.openURL('/' + type + '/'); }); @@ -1636,7 +1643,7 @@ define([ if (!APP.editable) { return; } if (!APP.loggedIn) { return; } // Anonymous users can use the + menu in the toolbar - if (!filesOp.isPathIn(currentPath, [ROOT, 'hrefArray'])) { return; } + if (!manager.isPathIn(currentPath, [ROOT, 'hrefArray'])) { return; } // Create dropdown var options = []; @@ -1813,8 +1820,8 @@ define([ }; var sortElements = function (folder, path, oldkeys, prop, asc, useId) { - var root = path && filesOp.find(path); - var test = folder ? filesOp.isFolder : filesOp.isFile; + var root = path && manager.find(path); + var test = folder ? manager.isFolder : manager.isFile; var keys = oldkeys.filter(function (e) { return useId ? test(e) : (path && test(root[e])); }); @@ -1823,7 +1830,7 @@ define([ var getProp = function (el, prop) { if (folder) { return el.toLowerCase(); } var id = useId ? el : root[el]; - var data = filesOp.getFileData(id); + var data = manager.getFileData(id); if (!data) { return ''; } if (prop === 'type') { var hrefData = Hash.parsePadUrl(data.href || data.roHref); @@ -1832,7 +1839,7 @@ define([ if (prop === 'atime' || prop === 'ctime') { return new Date(data[prop]); } - return (filesOp.getTitle(id) || "").toLowerCase(); + return (manager.getTitle(id) || "").toLowerCase(); }; keys.sort(function(a, b) { if (getProp(a, prop) < getProp(b, prop)) { return mult * -1; } @@ -1842,7 +1849,7 @@ define([ return keys; }; var sortTrashElements = function (folder, oldkeys, prop, asc) { - var test = folder ? filesOp.isFolder : filesOp.isFile; + var test = folder ? manager.isFolder : manager.isFile; var keys = oldkeys.filter(function (e) { return test(e.element); }); @@ -1851,7 +1858,7 @@ define([ var getProp = function (el, prop) { if (prop && !folder) { var element = el.element; - var e = filesOp.getFileData(element); + var e = manager.getFileData(element); if (!e) { e = { href : el, @@ -1966,7 +1973,7 @@ define([ sortBy = sortBy === "" ? sortBy = 'name' : sortBy; var sortedFiles = sortElements(false, [rootName], keys, sortBy, !getSortFileDesc(), true); sortedFiles.forEach(function (id) { - var file = filesOp.getFileData(id); + var file = manager.getFileData(id); if (!file) { //debug("Unsorted or template returns an element not present in filesData: ", href); file = { title: Messages.fm_noname }; @@ -1974,7 +1981,7 @@ define([ } var idx = files[rootName].indexOf(id); var $icon = getFileIcon(id); - var ro = filesOp.isReadOnlyFile(id); + var ro = manager.isReadOnlyFile(id); // ro undefined mens it's an old hash which doesn't support read-only var roClass = typeof(ro) === 'undefined' ? ' cp-app-drive-element-noreadonly' : ro ? ' cp-app-drive-element-readonly' : ''; @@ -2018,11 +2025,11 @@ define([ if (allfiles.length === 0) { return; } var $fileHeader = getFileListHeader(false); $container.append($fileHeader); - var keys = filesOp.getFiles([FILES_DATA]); + var keys = manager.getFiles([FILES_DATA]); var sortedFiles = sortElements(false, [FILES_DATA], keys, APP.store[SORT_FILE_BY], !getSortFileDesc(), true); sortedFiles.forEach(function (id) { var $icon = getFileIcon(id); - var ro = filesOp.isReadOnlyFile(id); + var ro = manager.isReadOnlyFile(id); // ro undefined maens it's an old hash which doesn't support read-only var roClass = typeof(ro) === 'undefined' ? ' cp-app-drive-element-noreadonly' : ro ? ' cp-app-drive-element-readonly' : ''; @@ -2056,7 +2063,7 @@ define([ return; } root[key].forEach(function (el, idx) { - if (!filesOp.isFile(el.element) && !filesOp.isFolder(el.element)) { return; } + if (!manager.isFile(el.element) && !manager.isFolder(el.element)) { return; } var spath = [key, idx, 'element']; filesList.push({ element: el.element, @@ -2067,12 +2074,12 @@ define([ }); var sortedFolders = sortTrashElements(true, filesList, null, !getSortFolderDesc()); var sortedFiles = sortTrashElements(false, filesList, APP.store[SORT_FILE_BY], !getSortFileDesc()); - if (filesOp.hasSubfolder(root, true)) { $list.append($folderHeader); } + if (manager.hasSubfolder(root, true)) { $list.append($folderHeader); } sortedFolders.forEach(function (f) { var $element = createElement([TRASH], f.spath, root, true); $list.append($element); }); - if (filesOp.hasFile(root, true)) { $list.append($fileHeader); } + if (manager.hasFile(root, true)) { $list.append($fileHeader); } sortedFiles.forEach(function (f) { var $element = createElement([TRASH], f.spath, root, false); $list.append($element); @@ -2080,7 +2087,7 @@ define([ }; var displaySearch = function ($list, value) { - var filesList = filesOp.search(value); + var filesList = manager.search(value); filesList.forEach(function (r) { r.paths.forEach(function (path) { var href = r.data.href; @@ -2106,7 +2113,7 @@ define([ .text(Messages.fm_creation); var $ctime = $('', {'class': 'cp-app-drive-search-col2'}) .text(new Date(r.data.ctime).toLocaleString()); - if (filesOp.isPathIn(path, ['hrefArray'])) { + if (manager.isPathIn(path, ['hrefArray'])) { path.pop(); path.push(r.data.title); } @@ -2119,7 +2126,7 @@ define([ if (parentPath) { $a = $('').text(Messages.fm_openParent).click(function (e) { e.preventDefault(); - if (filesOp.isInTrashRoot(parentPath)) { parentPath = [TRASH]; } + if (manager.isInTrashRoot(parentPath)) { parentPath = [TRASH]; } else { parentPath.pop(); } APP.selectedFiles = [r.id]; APP.displayDirectory(parentPath); @@ -2144,25 +2151,25 @@ define([ }; var displayRecent = function ($list) { - var filesList = filesOp.getRecentPads(); + var filesList = manager.getRecentPads(); var limit = 20; var i = 0; filesList.forEach(function (id) { if (i >= limit) { return; } // Check path (pad exists and not in trash) - var paths = filesOp.findFile(id); + var paths = manager.findFile(id); if (!paths.length) { return; } var path = paths[0]; - if (filesOp.isPathIn(path, [TRASH])) { return; } + if (manager.isPathIn(path, [TRASH])) { return; } // Display the pad - var file = filesOp.getFileData(id); + var file = manager.getFileData(id); if (!file) { //debug("Unsorted or template returns an element not present in filesData: ", href); file = { title: Messages.fm_noname }; //return; } var $icon = getFileIcon(id); - var ro = filesOp.isReadOnlyFile(id); + var ro = manager.isReadOnlyFile(id); // ro undefined mens it's an old hash which doesn't support read-only var roClass = typeof(ro) === 'undefined' ? ' cp-app-drive-element-noreadonly' : ro ? ' cp-app-drive-element-readonly' : ''; @@ -2190,17 +2197,17 @@ define([ // Owned pads category var displayOwned = function ($container) { - var list = filesOp.getOwnedPads(edPublic); + var list = manager.getOwnedPads(edPublic); if (list.length === 0) { return; } var $fileHeader = getFileListHeader(false); $container.append($fileHeader); var sortedFiles = sortElements(false, false, list, APP.store[SORT_FILE_BY], !getSortFileDesc(), true); sortedFiles.forEach(function (id) { - var paths = filesOp.findFile(id); + var paths = manager.findFile(id); if (!paths.length) { return; } var path = paths[0]; var $icon = getFileIcon(id); - var ro = filesOp.isReadOnlyFile(id); + var ro = manager.isReadOnlyFile(id); // ro undefined maens it's an old hash which doesn't support read-only var roClass = typeof(ro) === 'undefined' ? ' cp-app-drive-element-noreadonly' : ro ? ' cp-app-drive-element-readonly' : ''; @@ -2226,7 +2233,7 @@ define([ // Tags category var displayTags = function ($container) { - var list = filesOp.getTagsList(); + var list = manager.getTagsList(); if (Object.keys(list).length === 0) { return; } var sortedTags = Object.keys(list); sortedTags.sort(function (a, b) { @@ -2276,16 +2283,16 @@ define([ if (!path || path.length === 0) { path = [ROOT]; } - var isInRoot = filesOp.isPathIn(path, [ROOT]); - var inTrash = filesOp.isPathIn(path, [TRASH]); - var isTrashRoot = filesOp.comparePath(path, [TRASH]); - var isTemplate = filesOp.comparePath(path, [TEMPLATE]); - var isAllFiles = filesOp.comparePath(path, [FILES_DATA]); + var isInRoot = manager.isPathIn(path, [ROOT]); + var inTrash = manager.isPathIn(path, [TRASH]); + var isTrashRoot = manager.comparePath(path, [TRASH]); + var isTemplate = manager.comparePath(path, [TEMPLATE]); + var isAllFiles = manager.comparePath(path, [FILES_DATA]); var isVirtual = virtualCategories.indexOf(path[0]) !== -1; var isSearch = path[0] === SEARCH; var isTags = path[0] === TAGS; - var root = isVirtual ? undefined : filesOp.find(path); + var root = isVirtual ? undefined : manager.find(path); if (!isVirtual && typeof(root) === "undefined") { log(Messages.fm_unknownFolderError); debug("Unable to locate the selected directory: ", path); @@ -2385,20 +2392,20 @@ define([ displayTags($list); } else { $dirContent.contextmenu(openContextMenu('content')); - if (filesOp.hasSubfolder(root)) { $list.append($folderHeader); } + if (manager.hasSubfolder(root)) { $list.append($folderHeader); } // display sub directories var keys = Object.keys(root); var sortedFolders = sortElements(true, path, keys, null, !getSortFolderDesc()); var sortedFiles = sortElements(false, path, keys, APP.store[SORT_FILE_BY], !getSortFileDesc()); sortedFolders.forEach(function (key) { - if (filesOp.isFile(root[key])) { return; } + if (manager.isFile(root[key])) { return; } var $element = createElement(path, key, root, true); $element.appendTo($list); }); - if (filesOp.hasFile(root)) { $list.append($fileHeader); } + if (manager.hasFile(root)) { $list.append($fileHeader); } // display files sortedFiles.forEach(function (key) { - if (filesOp.isFolder(root[key])) { return; } + if (manager.isFolder(root[key])) { return; } var $element = createElement(path, key, root, false); $element.appendTo($list); }); @@ -2460,13 +2467,13 @@ define([ $collapse.removeClass('fa-minus-square-o'); $collapse.addClass('fa-plus-square-o'); // Change the current opened folder if it was collapsed - if (filesOp.isSubpath(currentPath, path)) { + if (manager.isSubpath(currentPath, path)) { displayDirectory(path); } } }); if (wasFolderOpened(path) || - (filesOp.isSubpath(currentPath, path) && path.length < currentPath.length)) { + (manager.isSubpath(currentPath, path) && path.length < currentPath.length)) { $collapse.click(); } } @@ -2479,20 +2486,20 @@ define([ }; var createTree = function ($container, path) { - var root = filesOp.find(path); + var root = manager.find(path); // don't try to display what doesn't exist if (!root) { return; } // Display the root element in the tree - var displayingRoot = filesOp.comparePath([ROOT], path); + var displayingRoot = manager.comparePath([ROOT], path); if (displayingRoot) { - var isRootOpened = filesOp.comparePath([ROOT], currentPath); - var $rootIcon = filesOp.isFolderEmpty(files[ROOT]) ? + var isRootOpened = manager.comparePath([ROOT], currentPath); + var $rootIcon = manager.isFolderEmpty(files[ROOT]) ? (isRootOpened ? $folderOpenedEmptyIcon : $folderEmptyIcon) : (isRootOpened ? $folderOpenedIcon : $folderIcon); var $rootElement = createTreeElement(ROOT_NAME, $rootIcon.clone(), [ROOT], false, true, true, isRootOpened); - if (!filesOp.hasSubfolder(root)) { + if (!manager.hasSubfolder(root)) { $rootElement.find('.cp-app-drive-icon-expcol').css('visibility', 'hidden'); } $rootElement.addClass('cp-app-drive-tree-root'); @@ -2501,19 +2508,19 @@ define([ $('
      ', {'class': 'cp-app-drive-tree-docs'}) .append($rootElement).appendTo($container); $container = $rootElement; - } else if (filesOp.isFolderEmpty(root)) { return; } + } else if (manager.isFolderEmpty(root)) { return; } // Display root content var $list = $('
        ').appendTo($container); var keys = Object.keys(root).sort(); keys.forEach(function (key) { // Do not display files in the menu - if (!filesOp.isFolder(root[key])) { return; } + if (!manager.isFolder(root[key])) { return; } var newPath = path.slice(); newPath.push(key); - var isCurrentFolder = filesOp.comparePath(newPath, currentPath); - var isEmpty = filesOp.isFolderEmpty(root[key]); - var subfolder = filesOp.hasSubfolder(root[key]); + var isCurrentFolder = manager.comparePath(newPath, currentPath); + var isEmpty = manager.isFolderEmpty(root[key]); + var subfolder = manager.hasSubfolder(root[key]); var $icon = isEmpty ? (isCurrentFolder ? $folderOpenedEmptyIcon : $folderEmptyIcon) : (isCurrentFolder ? $folderOpenedIcon : $folderIcon); @@ -2525,8 +2532,8 @@ define([ }; var createTrash = function ($container, path) { - var $icon = filesOp.isFolderEmpty(files[TRASH]) ? $trashEmptyIcon.clone() : $trashIcon.clone(); - var isOpened = filesOp.comparePath(path, currentPath); + var $icon = manager.isFolderEmpty(files[TRASH]) ? $trashEmptyIcon.clone() : $trashIcon.clone(); + var isOpened = manager.comparePath(path, currentPath); var $trashElement = createTreeElement(TRASH_NAME, $icon, [TRASH], false, true, false, isOpened); $trashElement.addClass('root'); $trashElement.find('>.cp-app-drive-element-row') @@ -2567,7 +2574,7 @@ define([ if (!isInSearchTmp) { search.oldLocation = currentPath.slice(); } var newLocation = [SEARCH, $input.val()]; setSearchCursor(); - if (!filesOp.comparePath(newLocation, currentPath.slice())) { displayDirectory(newLocation); } + if (!manager.comparePath(newLocation, currentPath.slice())) { displayDirectory(newLocation); } return; } if (e.which === 27) { @@ -2582,7 +2589,7 @@ define([ if (!isInSearchTmp) { search.oldLocation = currentPath.slice(); } var newLocation = [SEARCH, $input.val()]; setSearchCursor(); - if (!filesOp.comparePath(newLocation, currentPath.slice())) { displayDirectory(newLocation); } + if (!manager.comparePath(newLocation, currentPath.slice())) { displayDirectory(newLocation); } }, 500); }).appendTo($div); $searchIcon.clone().appendTo($div); @@ -2615,7 +2622,7 @@ define([ var createCategory = function ($container, cat) { var options = categories[cat]; var $icon = options.$icon.clone(); - var isOpened = filesOp.comparePath([cat], currentPath); + var isOpened = manager.comparePath([cat], currentPath); var $element = createTreeElement(options.name, $icon, [cat], options.draggable, options.droppable, false, isOpened); $element.addClass('cp-app-drive-tree-root'); var $list = $('
          ', { 'class': 'cp-app-drive-tree-category' }).append($element); @@ -2676,12 +2683,12 @@ define([ }); var getProperties = APP.getProperties = function (el, cb) { - if (!filesOp.isFile(el)) { + if (!manager.isFile(el)) { return void cb('NOT_FILE'); } - //var ro = filesOp.isReadOnlyFile(el); + //var ro = manager.isReadOnlyFile(el); var base = APP.origin; - var data = JSON.parse(JSON.stringify(filesOp.getFileData(el))); + var data = JSON.parse(JSON.stringify(manager.getFileData(el))); if (!data || !(data.href || data.roHref)) { return void cb('INVALID_FILE'); } if (data.href) { @@ -2710,7 +2717,7 @@ define([ UI.confirm(msg, function(res) { $(window).focus(); if (!res) { return; } - filesOp.delete(pathsList, refresh); + manager.delete(pathsList, refresh); }); }; var deleteOwnedPaths = function (paths, pathsList) { @@ -2723,7 +2730,7 @@ define([ UI.confirm(msgD, function(res) { $(window).focus(); if (!res) { return; } - filesOp.delete(pathsList, refresh); + manager.delete(pathsList, refresh); }); }; $contextMenu.on("click", "a", function(e) { @@ -2762,13 +2769,13 @@ define([ } else if ($(this).hasClass('cp-app-drive-context-openro')) { paths.forEach(function (p) { - var el = filesOp.find(p.path); + var el = manager.find(p.path); var href; - if (filesOp.isPathIn(p.path, [FILES_DATA])) { + if (manager.isPathIn(p.path, [FILES_DATA])) { href = el.roHref; } else { - if (!el || filesOp.isFolder(el)) { return; } - var data = filesOp.getFileData(el); + if (!el || manager.isFolder(el)) { return; } + var data = manager.getFileData(el); href = data.roHref; } openFile(null, href); @@ -2781,11 +2788,11 @@ define([ APP.newFolder = info.newPath; APP.displayDirectory(paths[0].path); }; - filesOp.addFolder(paths[0].path, null, onFolderCreated); + manager.addFolder(paths[0].path, null, onFolderCreated); } else if ($(this).hasClass("cp-app-drive-context-newdoc")) { var ntype = $(this).data('type') || 'pad'; - var path2 = filesOp.isPathIn(currentPath, [TRASH]) ? '' : currentPath; + var path2 = manager.isPathIn(currentPath, [TRASH]) ? '' : currentPath; common.sessionStorage.put(Constants.newPadPathKey, path2, function () { common.openURL('/' + ntype + '/'); }); @@ -2794,13 +2801,13 @@ define([ if (type === 'trash') { var pPath = paths[0].path; if (paths.length !== 1 || pPath.length !== 4) { return; } - var element = filesOp.find(pPath.slice(0,3)); // element containing the oldpath + var element = manager.find(pPath.slice(0,3)); // element containing the oldpath var sPath = stringifyPath(element.path); UI.alert('' + Messages.fm_originalPath + ":
          " + sPath, undefined, true); return; } if (paths.length !== 1) { return; } - el = filesOp.find(paths[0].path); + el = manager.find(paths[0].path); getProperties(el, function (e, $prop) { if (e) { return void logError(e); } UI.alert($prop[0], undefined, true); @@ -2808,21 +2815,21 @@ define([ } else if ($(this).hasClass("cp-app-drive-context-hashtag")) { if (paths.length !== 1) { return; } - el = filesOp.find(paths[0].path); - var data = filesOp.getFileData(el); + el = manager.find(paths[0].path); + var data = manager.getFileData(el); if (!data) { return void console.error("Expected to find a file"); } var href = data.href || data.roHref; common.updateTags(href); } else if ($(this).hasClass("cp-app-drive-context-empty")) { if (paths.length !== 1 || !paths[0].element - || !filesOp.comparePath(paths[0].path, [TRASH])) { + || !manager.comparePath(paths[0].path, [TRASH])) { log(Messages.fm_forbidden); return; } UI.confirm(Messages.fm_emptyTrashDialog, function(res) { if (!res) { return; } - filesOp.emptyTrash(refresh); + manager.emptyTrash(refresh); }); } else if ($(this).hasClass("cp-app-drive-context-remove")) { @@ -2833,24 +2840,24 @@ define([ var restorePath = paths[0].path; var restoreName = paths[0].path[paths[0].path.length - 1]; if (restorePath.length === 4) { - var rEl = filesOp.find(restorePath); - if (filesOp.isFile(rEl)) { - restoreName = filesOp.getTitle(rEl); + var rEl = manager.find(restorePath); + if (manager.isFile(rEl)) { + restoreName = manager.getTitle(rEl); } else { restoreName = restorePath[1]; } } UI.confirm(Messages._getKey("fm_restoreDialog", [restoreName]), function(res) { if (!res) { return; } - filesOp.restore(restorePath, refresh); + manager.restore(restorePath, refresh); }); } else if ($(this).hasClass("cp-app-drive-context-openparent")) { if (paths.length !== 1) { return; } var parentPath = paths[0].path.slice(); - if (filesOp.isInTrashRoot(parentPath)) { parentPath = [TRASH]; } + if (manager.isInTrashRoot(parentPath)) { parentPath = [TRASH]; } else { parentPath.pop(); } - el = filesOp.find(paths[0].path); + el = manager.find(paths[0].path); APP.selectedFiles = [el]; APP.displayDirectory(parentPath); } @@ -2883,13 +2890,13 @@ define([ $appContainer.on('keydown', function (e) { // "Del" if (e.which === 46) { - if (filesOp.isPathIn(currentPath, [FILES_DATA]) && APP.loggedIn) { + if (manager.isPathIn(currentPath, [FILES_DATA]) && APP.loggedIn) { return; // We can't remove elements directly from filesData } var $selected = $('.cp-app-drive-element-selected'); if (!$selected.length) { return; } var paths = []; - var isTrash = filesOp.isPathIn(currentPath, [TRASH]); + var isTrash = manager.isPathIn(currentPath, [TRASH]); $selected.each(function (idx, elmt) { if (!$(elmt).data('path')) { return; } paths.push($(elmt).data('path')); @@ -2939,8 +2946,8 @@ define([ if (path[0] !== 'drive') { return false; } path = path.slice(1); var cPath = currentPath.slice(); - if ((filesOp.isPathIn(cPath, ['hrefArray', TRASH]) && cPath[0] === path[0]) || - (path.length >= cPath.length && filesOp.isSubpath(path, cPath))) { + if ((manager.isPathIn(cPath, ['hrefArray', TRASH]) && cPath[0] === path[0]) || + (path.length >= cPath.length && manager.isSubpath(path, cPath))) { // Reload after a few ms to make sure all the change events have been received onRefresh.refresh(); } else if (path.length && path[0] === FILES_DATA) { @@ -2955,8 +2962,8 @@ define([ if (path[0] !== 'drive') { return false; } path = path.slice(1); var cPath = currentPath.slice(); - if ((filesOp.isPathIn(cPath, ['hrefArray', TRASH]) && cPath[0] === path[0]) || - (path.length >= cPath.length && filesOp.isSubpath(path, cPath))) { + if ((manager.isPathIn(cPath, ['hrefArray', TRASH]) && cPath[0] === path[0]) || + (path.length >= cPath.length && manager.isSubpath(path, cPath))) { // Reload after a few to make sure all the change events have been received onRefresh.refresh(); } @@ -2987,13 +2994,13 @@ define([ UI.removeLoadingScreen(); sframeChan.query('Q_DRIVE_GETDELETED', null, function (err, data) { - var ids = filesOp.findChannels(data); + var ids = manager.findChannels(data); var titles = []; ids.forEach(function (id) { - var title = filesOp.getTitle(id); + var title = manager.getTitle(id); titles.push(title); - var paths = filesOp.findFile(id); - filesOp.delete(paths, refresh); + var paths = manager.findFile(id); + manager.delete(paths, refresh); }); if (!titles.length) { return; } UI.log(Messages._getKey('fm_deletedPads', [titles.join(', ')])); @@ -3011,6 +3018,7 @@ define([ var main = function () { var common; var proxy = {}; + var folders = {}; var readOnly; nThen(function (waitFor) { @@ -3051,6 +3059,7 @@ define([ var sframeChan = common.getSframeChannel(); updateObject(sframeChan, proxy, waitFor()); + // XXX Load shared folders }).nThen(function () { var sframeChan = common.getSframeChannel(); var metadataMgr = common.getMetadataMgr(); @@ -3113,7 +3122,7 @@ define([ if (!proxy.drive || typeof(proxy.drive) !== 'object') { throw new Error("Corrupted drive"); } - andThen(common, proxy); + andThen(common, proxy, folders); var onDisconnect = APP.onDisconnect = function (noAlert) { setEditable(false); From e0cc1a6eb6f1c51f9bfbcc6db177d10983316c14 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 9 Jul 2018 14:36:55 +0200 Subject: [PATCH 09/86] Display a shared folder in the drive --- www/common/cryptpad-common.js | 5 ++ www/common/outer/async-store.js | 29 ++++++++++- www/common/outer/store-rpc.js | 1 + www/common/outer/userObject.js | 28 +++++++++-- www/common/proxy-manager.js | 86 ++++++++++++++++++++++++--------- www/common/userObject.js | 27 +++++++---- www/drive/inner.js | 42 ++++++++++++---- www/drive/main.js | 6 +++ 8 files changed, 176 insertions(+), 48 deletions(-) diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index afd177577..b9d089c6a 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -83,6 +83,11 @@ define([ cb(obj); }); }; + common.getSharedFolder = function (id, cb) { + postMessage("GET_SHARED_FOLDER", id, function (obj) { + cb(obj); + }); + }; // Settings and ready common.mergeAnonDrive = function (cb) { var data = { diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 70e5ee95b..7c3ec7376 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -38,7 +38,7 @@ define([ Realtime.whenRealtimeSyncs(store.realtime, waitFor()); if (store.sharedFolders) { for (var k in store.sharedFolders) { - Realtime.whenRealtimeSync(store.sharedFolders[k].realtime, waitFor()); + Realtime.whenRealtimeSyncs(store.sharedFolders[k].realtime, waitFor()); } } }).nThen(function () { cb(); }); @@ -61,6 +61,13 @@ define([ onSync(cb); }; + Store.getSharedFolder = function (clientId, id, cb) { + if (store.manager.folders[id]) { + return void cb(store.manager.folders[id].proxy); + } + cb({}); + }; + Store.hasSigningKeys = function () { if (!store.proxy) { return; } return typeof(store.proxy.edPrivate) === 'string' && @@ -1166,7 +1173,7 @@ define([ var id; nThen(function (waitFor) { // TODO XXX get the folder data (href, title, ...) - var folderData = {}; + var folderData = data.folderData || {}; // 1. add the shared folder to our list of shared folders store.userObject.pushSharedFolder(folderData, waitFor(function (err, folderId) { if (err) { @@ -1177,6 +1184,7 @@ define([ })); }).nThen(function (waitFor) { // 2a. add the shared folder to the path in our drive + console.log('adding'); store.userObject.add(id, path); onSync(waitFor()); @@ -1189,6 +1197,23 @@ define([ cb(); }); }; + store.createSharedFolder = function () { + // XXX + var hash = Hash.createRandomHash('folder'); + var href = '/folder/#' + hash; + var secret = Hash.getSecrets('folder', hash); + Store.addSharedFolder(null, { + path: ['root'], + folderData: { + href: href, + roHref: '/folder/#' + Hash.getViewHashFromKeys(secret), + channel: secret.channel, + title: "Test", + } + }, function () { + console.log('done'); + }); + }; // Drive diff --git a/www/common/outer/store-rpc.js b/www/common/outer/store-rpc.js index 972776abe..e041533da 100644 --- a/www/common/outer/store-rpc.js +++ b/www/common/outer/store-rpc.js @@ -52,6 +52,7 @@ define([ GET_PAD_DATA: Store.getPadData, GET_STRONGER_HASH: Store.getStrongerHash, INCREMENT_TEMPLATE_USE: Store.incrementTemplateUse, + GET_SHARED_FOLDER: Store.getSharedFolder, // Messaging INVITE_FROM_USERLIST: Store.inviteFromUserlist, ADD_DIRECT_MESSAGE_HANDLERS: Store.addDirectMessageHandlers, diff --git a/www/common/outer/userObject.js b/www/common/outer/userObject.js index 94363a2d2..5a5469935 100644 --- a/www/common/outer/userObject.js +++ b/www/common/outer/userObject.js @@ -69,6 +69,23 @@ define([ }); }; + exp.pushSharedFolder = function (data, cb) { + if (typeof cb !== "function") { cb = function () {}; } + var todo = function () { + var id = Util.createRandomInteger(); + files[SHARED_FOLDERS][id] = data; + cb(null, id); + }; + if (!loggedIn || !AppConfig.enablePinning || config.testMode) { + return void cb("EAUTH"); + } + if (!pinPads) { return void cb('EAUTH'); } + pinPads([data.channel], function (obj) { + if (obj && obj.error) { return void cb(obj.error); } + todo(); + }); + }; + // FILES DATA var spliceFileData = function (id) { delete files[FILES_DATA][id]; @@ -191,6 +208,7 @@ define([ var toRemove = []; Object.keys(data).forEach(function (id) { + id = Number(id); // Find and maybe update existing pads with the same channel id var d = data[id]; var found = false; @@ -332,9 +350,9 @@ define([ }; exp.add = function (id, path) { - // TODO WW if (!loggedIn && !config.testMode) { return; } - var data = files[FILES_DATA][id]; + id = Number(id); + var data = files[FILES_DATA][id] || files[SHARED_FOLDERS][id]; if (!data || typeof(data) !== "object") { return; } var newPath = path, parentEl; if (path && !Array.isArray(path)) { @@ -438,7 +456,6 @@ define([ }); delete files[OLD_FILES_DATA]; delete files.migrate; - console.log('done'); todo(); }; if (exp.rt) { @@ -581,7 +598,7 @@ define([ }); }; var fixFilesData = function () { - if (typeof files[FILES_DATA] !== "object") { debug("OLD_FILES_DATA was not an object"); files[FILES_DATA] = {}; } + if (typeof files[FILES_DATA] !== "object") { debug("FILES_DATA was not an object"); files[FILES_DATA] = {}; } var fd = files[FILES_DATA]; var rootFiles = exp.getFiles([ROOT, TRASH, 'hrefArray']); var root = exp.find([ROOT]); @@ -649,7 +666,8 @@ define([ secret = Hash.getSecrets(parsed.type, parsed.hash, el.password); } el.channel = secret.channel; - console.log('Adding missing channel in filesData ', el.channel); + console.log(el); + debug('Adding missing channel in filesData ', el.channel); } catch (e) { console.error(e); } diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index ac2feb883..2047a017a 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -7,17 +7,20 @@ define([ var getConfig = function (Env) { var cfg = {}; - for (var k in Env.cfg) { cfg[k] = Env[k]; } + for (var k in Env.cfg) { cfg[k] = Env.cfg[k]; } return cfg; }; // Add a shared folder to the list var addProxy = function (Env, id, proxy, leave) { - var cfg = getConfig(); + var cfg = getConfig(Env); cfg.sharedFolder = true; cfg.id = id; - var userObject = UserObject.init(proxy, Env.cfg); - userObject.fixFiles(); + var userObject = UserObject.init(proxy, cfg); + if (userObject.fixFiles) { + // Only in outer + userObject.fixFiles(); + } Env.folders[id] = { proxy: proxy, userObject: userObject, @@ -98,7 +101,9 @@ define([ } var current; var uo = Env.user.userObject; - for (var i=2; i<=path.length; i++) { + // We don't need to check the last element of the path because we only need to split it + // when the path contains an element inside the shared folder + for (var i=2; i metadata (href, title, password...) - // f.proxy => listmap - // f.id => id? - manager.addProxy(id, f.proxy); + manager.addProxy(id, f); }); var $tree = APP.$tree = $("#cp-app-drive-tree"); @@ -1166,7 +1179,10 @@ define([ var $target = $(target); var $el = findDataHolder($target); var newPath = $el.data('path'); - if ((!newPath || manager.isFile(manager.find(newPath))) + var dropEl = newPath && manager.find(newPath); + if (newPath && manager.isSharedFolder(dropEl)) { + newPath.push(manager.user.userObject.ROOT); + } else if ((!newPath || manager.isFile(dropEl)) && $target.parents('#cp-app-drive-content')) { newPath = currentPath; } @@ -2293,6 +2309,11 @@ define([ var isTags = path[0] === TAGS; var root = isVirtual ? undefined : manager.find(path); + if (manager.isSharedFolder(root)) { + path.push(manager.user.userObject.ROOT); + root = manager.find(path); + if (!root) { return; } + } if (!isVirtual && typeof(root) === "undefined") { log(Messages.fm_unknownFolderError); debug("Unable to locate the selected directory: ", path); @@ -2434,7 +2455,9 @@ define([ } updateObject(sframeChan, proxy, function () { copyObjectValue(files, proxy.drive); - _displayDirectory(path, force); + updateSharedFolders(sframeChan, files, folders, function () { + _displayDirectory(path, force); + }); }); }; @@ -3058,8 +3081,9 @@ define([ };*/ var sframeChan = common.getSframeChannel(); - updateObject(sframeChan, proxy, waitFor()); - // XXX Load shared folders + updateObject(sframeChan, proxy, waitFor(function () { + updateSharedFolders(sframeChan, proxy.drive, folders, waitFor()); + })); }).nThen(function () { var sframeChan = common.getSframeChannel(); var metadataMgr = common.getMetadataMgr(); diff --git a/www/drive/main.js b/www/drive/main.js index 79347695c..3e96f2e6f 100644 --- a/www/drive/main.js +++ b/www/drive/main.js @@ -53,6 +53,12 @@ define([ Cryptpad.userObjectCommand(data, cb); }); sframeChan.on('Q_DRIVE_GETOBJECT', function (data, cb) { + if (data && data.sharedFolder) { + Cryptpad.getSharedFolder(data.sharedFolder, function (obj) { + cb(obj); + }); + return; + } Cryptpad.getUserObject(function (obj) { cb(obj); }); From 6312dadb600d9f880acb6217cd35bdbe9d586f4a Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 9 Jul 2018 18:11:04 +0200 Subject: [PATCH 10/86] Fix shared folders names in the drive --- www/common/cryptpad-common.js | 8 +++++ www/common/outer/async-store.js | 2 ++ www/common/proxy-manager.js | 10 ++++++ www/common/sframe-protocol.js | 1 + www/drive/inner.js | 61 ++++++++++++++++++++++++++++----- www/drive/main.js | 3 ++ 6 files changed, 77 insertions(+), 8 deletions(-) diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index b9d089c6a..0fc70b681 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -103,6 +103,14 @@ define([ common.userObjectCommand = function (data, cb) { postMessage("DRIVE_USEROBJECT", data, cb); }; + common.restoreDrive = function (data, cb) { + postMessage("SET", { + key:['drive'], + value: data + }, function (obj) { + cb(obj); + }); + }; common.drive = {}; common.drive.onLog = Util.mkEvent(); common.drive.onChange = Util.mkEvent(); diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 7c3ec7376..c76f73814 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -1173,6 +1173,8 @@ define([ var id; nThen(function (waitFor) { // TODO XXX get the folder data (href, title, ...) + // XXX href should be stored in your drive's .sharedFolders + // and title should be stored in the sharef folder's metadata var folderData = data.folderData || {}; // 1. add the shared folder to our list of shared folders store.userObject.pushSharedFolder(folderData, waitFor(function (err, folderId) { diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index 2047a017a..6712da200 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -677,6 +677,15 @@ define([ return Env.user.userObject.getOwnedPads(edPublic); }; + var getSharedFolderData = function (Env, id) { + if (!Env.folders[id]) { return; } + var obj = Env.folders[id].proxy.metadata || {}; + for (var k in Env.user.proxy[UserObject.SHARED_FOLDERS][id] || {}) { + obj[k] = Env.user.proxy[UserObject.SHARED_FOLDERS][id][k]; + } + return obj; + }; + /* Generic: doesn't need access to a proxy */ var isFile = function (Env, el, allowStr) { return Env.user.userObject.isFile(el, allowStr); @@ -762,6 +771,7 @@ define([ getTagsList: callWithEnv(getTagsList), findFile: callWithEnv(findFile), findChannels: callWithEnv(findChannels), + getSharedFolderData: callWithEnv(getSharedFolderData), // Generic isFile: callWithEnv(isFile), isFolder: callWithEnv(isFolder), diff --git a/www/common/sframe-protocol.js b/www/common/sframe-protocol.js index a23124a65..cc41dcbf3 100644 --- a/www/common/sframe-protocol.js +++ b/www/common/sframe-protocol.js @@ -203,6 +203,7 @@ define({ // Inner drive needs to send command and receive updates from the async store 'Q_DRIVE_USEROBJECT': true, 'Q_DRIVE_GETOBJECT': true, + 'Q_DRIVE_RESTORE': true, // Get the pads deleted from the server by other users to remove them from the drive 'Q_DRIVE_GETDELETED': true, // Store's userObject need to send log messages to inner to display them in the UI diff --git a/www/drive/inner.js b/www/drive/inner.js index 844557f0f..2c78b1904 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -71,6 +71,7 @@ define([ // Icons var faFolder = 'fa-folder'; var faFolderOpen = 'fa-folder-open'; + var faSharedFolder = 'fa-users'; var faReadOnly = 'fa-eye'; var faRename = 'fa-pencil'; var faTrash = 'fa-trash'; @@ -88,6 +89,8 @@ define([ var $folderOpenedIcon = $('', {"class": faFolderOpen + " fa cp-app-drive-icon-folder"}); //var $folderOpenedIcon = $('', {src: "/customize/images/icons/folderOpen.svg", "class": "folder icon"}); var $folderOpenedEmptyIcon = $folderOpenedIcon.clone(); + var $sharedFolderIcon = $('', {"class": faSharedFolder + " fa cp-app-drive-icon-folder"}); + var $sharedFolderOpenedIcon = $sharedFolderIcon.clone(); //var $upIcon = $('', {"class": "fa fa-arrow-circle-up"}); var $unsortedIcon = $('', {"class": "fa fa-files-o"}); var $templateIcon = $('', {"class": "fa fa-cubes"}); @@ -1336,6 +1339,12 @@ define([ var addFolderData = function (element, key, $span) { if (!element || !manager.isFolder(element)) { return; } // The element with the class '.name' is underlined when the 'li' is hovered + if (manager.isSharedFolder(element)) { + var data = manager.getSharedFolderData(element); + key = data && data.title ? data.title : key; + element = manager.folders[element].proxy[manager.user.userObject.ROOT]; + } + var sf = manager.hasSubfolder(element); var files = manager.hasFile(element); var $name = $('', {'class': 'cp-app-drive-element-name'}).text(key); @@ -1372,13 +1381,18 @@ define([ } var element = manager.find(newPath); + var isSharedFolder = manager.isSharedFolder(element); + var $icon = !isFolder ? getFileIcon(element) : undefined; var ro = manager.isReadOnlyFile(element); // ro undefined means it's an old hash which doesn't support read-only var roClass = typeof(ro) === 'undefined' ?' cp-app-drive-element-noreadonly' : ro ? ' cp-app-drive-element-readonly' : ''; var liClass = 'cp-app-drive-element-file cp-app-drive-element' + roClass; - if (isFolder) { + if (isSharedFolder) { + liClass = 'cp-app-drive-element-folder cp-app-drive-element'; + $icon = $sharedFolderIcon.clone(); + } else if (isFolder) { liClass = 'cp-app-drive-element-folder cp-app-drive-element'; $icon = manager.isFolderEmpty(root[key]) ? $folderEmptyIcon.clone() : $folderIcon.clone(); } @@ -1474,11 +1488,20 @@ define([ var isVirtual = virtualCategories.indexOf(path[0]) !== -1; var el = isVirtual ? undefined : manager.find(path); path = path[0] === SEARCH ? path.slice(0,1) : path; + + var skipNext = false; // When encountering a shared folder, skip a key in the path path.forEach(function (p, idx) { + if (skipNext) { return skipNext = false; } if (isTrash && [2,3].indexOf(idx) !== -1) { return; } var name = p; + var el = manager.find(path.slice(0, idx+1)); + if (manager.isSharedFolder(el)) { + name = manager.getSharedFolderData(el).title; + skipNext = true; + } + var $span = $('', {'class': 'cp-app-drive-path-element'}); if (idx < path.length - 1) { if (!noStyle) { @@ -1844,7 +1867,12 @@ define([ if (keys.length < 2) { return keys; } var mult = asc ? 1 : -1; var getProp = function (el, prop) { - if (folder) { return el.toLowerCase(); } + if (folder && root[el] && manager.isSharedFolder(root[el])) { + var title = manager.getSharedFolderData(root[el]).title || el; + return title.toLowerCase(); + } else if (folder) { + return el.toLowerCase(); + } var id = useId ? el : root[el]; var data = manager.getFileData(id); if (!data) { return ''; } @@ -2541,12 +2569,28 @@ define([ if (!manager.isFolder(root[key])) { return; } var newPath = path.slice(); newPath.push(key); - var isCurrentFolder = manager.comparePath(newPath, currentPath); - var isEmpty = manager.isFolderEmpty(root[key]); - var subfolder = manager.hasSubfolder(root[key]); - var $icon = isEmpty ? - (isCurrentFolder ? $folderOpenedEmptyIcon : $folderEmptyIcon) : - (isCurrentFolder ? $folderOpenedIcon : $folderIcon); + var isSharedFolder = manager.isSharedFolder(root[key]); + var $icon, isCurrentFolder, subfolder; + if (isSharedFolder) { + var fId = root[key]; + // Fix path + newPath.push(manager.user.userObject.ROOT); + isCurrentFolder = manager.comparePath(newPath, currentPath); + // Subfolders? + root = manager.folders[fId].proxy[manager.user.userObject.ROOT]; + subfolder = manager.hasSubfolder(root); + // Fix name + key = manager.getSharedFolderData(fId).title; + // Fix icon + $icon = $sharedFolderIcon; + } else { + var isEmpty = manager.isFolderEmpty(root[key]); + subfolder = manager.hasSubfolder(root[key]); + isCurrentFolder = manager.comparePath(newPath, currentPath); + $icon = isEmpty ? + (isCurrentFolder ? $folderOpenedEmptyIcon : $folderEmptyIcon) : + (isCurrentFolder ? $folderOpenedIcon : $folderIcon); + } var $element = createTreeElement(key, $icon.clone(), newPath, true, true, subfolder, isCurrentFolder); $element.appendTo($list); $element.find('>.cp-app-drive-element-row').contextmenu(openContextMenu('tree')); @@ -3113,6 +3157,7 @@ define([ APP.histConfig = { onLocal: function () { proxy.drive = history.currentObj.drive; + sframeChan.query("Q_DRIVE_RESTORE", history.currentObj.drive, function () {}); }, onRemote: function () {}, setHistory: setHistory, diff --git a/www/drive/main.js b/www/drive/main.js index 3e96f2e6f..3a600d18c 100644 --- a/www/drive/main.js +++ b/www/drive/main.js @@ -52,6 +52,9 @@ define([ sframeChan.on('Q_DRIVE_USEROBJECT', function (data, cb) { Cryptpad.userObjectCommand(data, cb); }); + sframeChan.on('Q_DRIVE_RESTORE', function (data, cb) { + Cryptpad.restoreDrive(data, cb); + }); sframeChan.on('Q_DRIVE_GETOBJECT', function (data, cb) { if (data && data.sharedFolder) { Cryptpad.getSharedFolder(data.sharedFolder, function (obj) { From bc7524c134a0a017a32969827f5c4254040cae14 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 10 Jul 2018 10:39:21 +0200 Subject: [PATCH 11/86] Fix tippy --- www/common/common-interface.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 5e5c75176..b1308bc7b 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -826,13 +826,13 @@ define([ var out = false; var xId = $(x).attr('aria-describedby'); if (xId) { - if (xId.indexOf('tippy-tooltip-') === 0) { + if (xId.indexOf('tippy-') === 0) { return true; } } $(x).find('[aria-describedby]').each(function (i, el) { var id = el.getAttribute('aria-describedby'); - if (id.indexOf('tippy-tooltip-') !== 0) { return; } + if (id.indexOf('tippy-') !== 0) { return; } out = true; }); return out; From 4b86ed2dec62afbee70d3c47177cc6389f07a759 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 10 Jul 2018 14:41:37 +0200 Subject: [PATCH 12/86] Shared folders UI --- customize.dist/translations/messages.fr.js | 1 + customize.dist/translations/messages.js | 1 + www/common/common-ui-elements.js | 24 ++++---- www/common/cryptpad-common.js | 11 ++++ www/common/outer/async-store.js | 22 +++++--- www/common/outer/store-rpc.js | 1 + www/common/outer/userObject.js | 10 +++- www/common/proxy-manager.js | 28 +++++++++- www/drive/inner.js | 65 +++++++++++++++++----- www/drive/main.js | 16 +++++- 10 files changed, 142 insertions(+), 37 deletions(-) diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index dc1a76040..520a6ceaf 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -454,6 +454,7 @@ define(function () { out.fc_delete_owned = "Supprimer du serveur"; out.fc_restore = "Restaurer"; out.fc_remove = "Supprimer de votre CryptDrive"; + out.fc_remove_sharedfolder = "Supprimer"; out.fc_empty = "Vider la corbeille"; out.fc_prop = "Propriétés"; out.fc_hashtag = "Mots-clés"; diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 07fe95c7a..a9299e71a 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -454,6 +454,7 @@ define(function () { out.fc_delete_owned = "Delete from the server"; out.fc_restore = "Restore"; out.fc_remove = "Remove from your CryptDrive"; + out.fc_remove_sharedfolder = "Remove"; out.fc_empty = "Empty the trash"; out.fc_prop = "Properties"; out.fc_hashtag = "Tags"; diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 3d057ed04..ab7d304f3 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -222,17 +222,21 @@ define([ })); } - $('
          Lade die Seite neu um die neue version zu benutzen, oder drücke Esc um im Offline-Modus weiterzuarbeiten."; + out.loading = "Laden..."; out.error = "Fehler"; out.saved = "Gespeichert"; out.synced = "Alles gespeichert"; - out.deleted = "Dokumente, die von deinem CryptDrive gelöscht wurden"; + out.deleted = "Dokumente, die von Deinem CryptDrive gelöscht wurden"; out.deletedFromServer = "Dokumente, die vom Server gelöscht wurden"; - out.realtime_unrecoverableError = "Das Echtzeitengine hat ein nicht-reparierbaren Fehler getroffen. Klicke auf OK, um neuzuladen."; + out.realtime_unrecoverableError = "Es ist ein nicht reparierbarer Fehler aufgetreten.. Klicke auf OK, um neuzuladen."; out.disconnected = 'Getrennt'; out.synchronizing = 'Synchronisieren'; @@ -82,7 +87,7 @@ 'Release notes for CryptPad {0}'; out.upgrade = "aufrüsten"; - out.upgradeTitle = "Rüste dein Konto auf, um mehr Speicherplatz zu haben"; + out.upgradeTitle = "Rüste Dein Konto auf, um mehr Speicherplatz zu haben"; out.upgradeAccount = "Konto aufrüsten"; out.MB = "MB"; @@ -95,44 +100,44 @@ out.formattedGB = "{0} GB"; out.formattedKB = "{0} KB"; - out.greenLight = "Alles funktioniert bestens"; - out.orangeLight = "Deine langsame Verbindung kann die Nutzung beeinträchtigen"; - out.redLight = "Du wurdest von dieser Sitzung getrennt"; + out.greenLight = "Alles funktioniert bestens"; + out.orangeLight = "Deine langsame Verbindung kann die Nutzung beeinträchtigen"; + out.redLight = "Du wurdest von dieser Sitzung getrennt"; - out.pinLimitReached = "Du hast deine Speicherplatzgrenze erreicht"; - out.updated_0_pinLimitReachedAlert = "Du hast deine Speicherplatzgrenze erreicht. Neue Dokumente werden nicht mehr in deinem CryptDrive gespeichert.
          " + - 'Du kannst entweder Dokument von deinem CryptDrive entfernen oder ein Premiumagenbot anfordern, damit deine Grenze erhöht wird.'; + out.pinLimitReached = "Du hast Deine Speicherplatzgrenze erreicht"; + out.updated_0_pinLimitReachedAlert = "Du hast Deine Speicherplatzgrenze erreicht. Neue Dokumente werden nicht mehr in Deinem CryptDrive gespeichert.
          " + + 'Du kannst entweder ein Dokument von Deinem CryptDrive entfernen oder ein Premiumangebot anfordern, damit Deine Grenze erhöht wird.'; out.pinLimitReachedAlert = out.updated_0_pinLimitReachedAlert; out.pinLimitReachedAlertNoAccounts = out.pinLimitReached; - out.pinLimitNotPinned = "Du hast deine Speicherplatzgrenze erreicht.
          "+ - "Dieses Dokument ist nicht in deinem CryptDrive gespeichert."; - out.pinLimitDrive = "Du hast deine Speicherplatzgrenze erreicht.
          " + + out.pinLimitNotPinned = "Du hast Deine Speicherplatzgrenze erreicht.
          "+ + "Dieses Dokument ist nicht in Deinem CryptDrive gespeichert."; + out.pinLimitDrive = "Du hast Deine Speicherplatzgrenze erreicht.
          " + "Du kannst keine neue Dokumente gestalten."; out.moreActions = "Mehr Aktionen"; out.importButton = "Importieren"; - out.importButtonTitle = 'Importiere eine lokale Datei in dieses Dokument'; + out.importButtonTitle = 'Importiere eine lokale Datei in dieses Dokument'; out.exportButton = "Exportieren"; - out.exportButtonTitle = 'Exportiere dieses Dokument in eine lokale Datei'; - out.exportPrompt = 'Wie möchtest du die Datei nennen?'; + out.exportButtonTitle = 'Exportiere dieses Dokument in eine lokale Datei'; + out.exportPrompt = 'Wie möchtest Du die Datei nennen?'; - out.changeNamePrompt = 'Ändere deinen Namen (oder lasse dieses Feld leer, um anonym mitzuarbeiten): '; - out.user_rename = "Bearbeite deinen Name"; + out.changeNamePrompt = 'Ändere Deinen Namen (oder lasse dieses Feld leer, um anonym mitzuarbeiten): '; + out.user_rename = "Bearbeite Deinen Namen"; out.user_displayName = "Name"; out.user_accountName = "Kontoname"; - out.clickToEdit = "Zum Bearbeiten klicken"; - out.saveTitle = "Bitte gebe das Titel ein (enter)"; + out.clickToEdit = "Zum Bearbeiten klicken"; + out.saveTitle = "Bitte gebe den Titel ein (Enter)"; - out.forgetButtonTitle = 'Entferne dieses Dokument von deiner Startseitenliste'; + out.forgetButtonTitle = 'Entferne dieses Dokument von Deiner Startseitenliste'; out.forgetButtonTitle = 'Dieses Dokument zum Papierkorb verschieben'; - out.forgetPrompt = 'Mit dem Klick auf OK wird das Dokument aus deinem lokalen Speicher gelöscht. Fortfahren?'; + out.forgetPrompt = 'Mit dem Klick auf OK wird das Dokument aus Deinem lokalen Speicher gelöscht. Fortfahren?'; out.movedToTrash = 'Dieses Dokument liegt im Papierkorb.
          Du kannst zum CryptDrive navigieren'; - out.shareButton = 'Teilen'; - out.shareSuccess = 'Die URL wurde in die Zwischenablage kopiert'; + out.shareButton = 'Teilen'; + out.shareSuccess = 'Die URL wurde in die Zwischenablage kopiert'; out.userListButton = "Benutzerliste"; @@ -141,24 +146,24 @@ out.newButton = 'Neu'; out.newButtonTitle = 'Neues Dokument gestalten'; out.uploadButton = 'Hochladen'; - out.uploadButtonTitle = 'Eine neue Datei ins aktuelle Ordner hochladen'; + out.uploadButtonTitle = 'Eine neue Datei in den aktuelle Ordner hochladen'; out.saveTemplateButton = "Als Vorlage speichern"; - out.saveTemplatePrompt = "Bitte gib ein Titel für die Vorlag ein"; + out.saveTemplatePrompt = "Bitte gib einen Titel für die Vorlage ein"; out.templateSaved = "Vorlage gespeichert!"; out.selectTemplate = "Bitte wähle eine Vorlage oder drucke die Esc Taste"; out.useTemplate = "Mit einer Vorlage starten?"; //Would you like to "You have available templates for this type of pad. Do you want to use one?"; - out.useTemplateOK = 'Wähle ein Template (Enter)'; + out.useTemplateOK = 'Wähle eine Vorlage (Enter)'; out.useTemplateCancel = 'Frisch starten (Esc)'; out.template_import = "Eine Vorlage importieren"; out.template_empty = "Keine Vorlage verfügbar"; - out.previewButtonTitle = "Der Markdownvorschau (un)sichtbar machen"; + out.previewButtonTitle = "Die Markdownvorschau (un)sichtbar machen"; out.presentButtonTitle = "Zum Präsentationsmodus wechseln"; out.backgroundButtonTitle = 'Hintergrundfarbe'; - out.colorButtonTitle = 'Die Hintergrundfrabe des Präsentationsmodus bearbeiten'; + out.colorButtonTitle = 'Die Hintergrundfarbe des Präsentationsmodus bearbeiten'; out.propertiesButton = "Eigenschaften"; out.propertiesButtonTitle = 'Die Eigenschaften des Dokuments ansehen'; @@ -171,26 +176,26 @@ out.printDate = "Datum anzeigen"; out.printTitle = "Titel der Präsentation anzeigen"; out.printCSS = "Custom CSS Regeln (CSS):"; - out.printTransition = "Animierte Transitionen aktivieren"; + out.printTransition = "Animierte Übergänge aktivieren"; out.printBackground = "Ein Hintergrundbild verwenden"; out.printBackgroundButton = "Bitte ein Bild wählen"; out.printBackgroundValue = "Aktueller Hintergrund: {0}"; out.printBackgroundNoValue = "Kein Hintergrundbild gewählt"; out.printBackgroundRemove = "Das Hintergrundbild wählen"; - out.filePickerButton = "Eine Datei deines CryptDrives einbetten"; + out.filePickerButton = "Eine Datei Deines CryptDrives einbetten"; out.filePicker_close = "Schliessen"; - out.filePicker_description = "Bitte wähle eine Datei aus deinem CryptDrive oder lade eine neue hoch"; + out.filePicker_description = "Bitte wähle eine Datei aus Deinem CryptDrive oder lade eine neue hoch"; out.filePicker_filter = "Namensfilter"; out.or = 'oder'; - out.tags_title = "Tags (for you only)"; + out.tags_title = "Tags (nur für Dich)"; out.tags_add = "Die Tags dieser Seite bearbeiten"; - out.tags_searchHint = "Dateien mit Tags in deinem CryptDrive suchen"; - out.tags_searchHint = "Die Suche mit dem Tag # in deinem CryptDrive starten."; + out.tags_searchHint = "Dateien mit Tags in Deinem CryptDrive suchen"; + out.tags_searchHint = "Die Suche mit dem Tag # in Deinem CryptDrive starten."; out.tags_notShared = "Deine Tags sind nicht mit anderen Benutzern geteilt"; out.tags_duplicate = "Doppeltes Tag: {0}"; - out.tags_noentry = "Du kannst ein Tag auf einem gelöschten Dokument nicht hinzufügen!"; + out.tags_noentry = "Du kannst kein Tag bei einem gelöschten Dokument hinzufügen!"; out.slideOptionsText = "Einstellungen"; out.slideOptionsTitle = "Präsentationseinstellungen"; @@ -200,27 +205,27 @@ out.languageButton = "Sprache"; out.languageButtonTitle = "Bitte wähle die Sprache für die Syntaxhervorhebung"; out.themeButton = "Farbschema"; - out.themeButtonTitle = "Wähle das Farbschema um Kode und Folieneditor darzustellen"; - - out.editShare = "Mitarbeit-URL teilen"; - out.editShareTitle = "Mitarbeit-URL in die Zwischenablage kopieren"; - out.editOpen = "Die Mitarbeit-URL in ein neues Tab öffnen"; - out.editOpenTitle = "Öffne dieses Dokument in Mitarbeitmodus in einem neuem Tab"; - out.viewShare = "Schreibgeschützt-URL teilen"; - out.viewShareTitle = "Schreibgeschützt-URL in die Zwischenablage kopieren"; - out.viewOpen = "In neuem Tab anzeigen"; - out.viewOpenTitle = "Dokument schreibgeschützt in neuem Tab öffnen."; + out.themeButtonTitle = "Wähle das Farbschema für Code und Folieneditor"; + + out.editShare = "Mitarbeits-URL teilen"; + out.editShareTitle = "Mitarbeit-URL in die Zwischenablage kopieren"; + out.editOpen = "Die Mitarbeits-URL in einem neuen Tab öffnen"; + out.editOpenTitle = "Öffne dieses Dokument im Mitarbeitmodus in einem neuen Tab"; + out.viewShare = "Schreibgeschützte URL teilen"; + out.viewShareTitle = "Schreibgeschützte URL in die Zwischenablage kopieren"; + out.viewOpen = "In neuem Tab anzeigen"; + out.viewOpenTitle = "Dokument schreibgeschützt in neuem Tab öffnen."; out.fileShare = "Link kopieren"; out.getEmbedCode = "Einbettungscode anzeigen"; - out.viewEmbedTitle = "Das Dokument in einer externe Webseite einbetten"; - out.viewEmbedTag = "Um dieses Dokument einzubetten, benutzt du dieses iframe in deiner HTML Seite, wie du wilsst. Du kannst mit CSS oder HTML Attributen das Stil erweitern"; + out.viewEmbedTitle = "Das Dokument in eine externe Webseite einbetten"; + out.viewEmbedTag = "Um dieses Dokument einzubetten, platziere dieses iframe an der gewünschten Stelle Deiner HTML Seite. Du kannst es mit CSS oder HTML Attributen gestalten"; out.fileEmbedTitle = "Die Datei in einer externen Seite einbetten"; - out.fileEmbedScript = "Um diese Datei einzubetten, bringst du dieses Skript einmal in deiner Webseite, damit das Media-Tag geladen wird:"; - out.fileEmbedTag = "Dann kannst du das Media-Tag, wo du willst auf einder Seite platzieren:"; + out.fileEmbedScript = "Um diese Datei einzubetten, füge dieses Skript einmal in Deiner Webseite ein, damit das Media-Tag geladen wird:"; + out.fileEmbedTag = "Dann platziere das Media-Tag an der gewünschten Stelle der Seite:"; - out.notifyJoined = "{0} ist in der Mitarbeit-Sitzung "; + out.notifyJoined = "{0} ist in der Mitarbeits-Sitzung "; out.notifyRenamed = "{0} ist jetzt als {1} bekannt"; - out.notifyLeft = "{0} hat die Mitarbeit-Sitzung verlassen"; + out.notifyLeft = "{0} hat die Mitarbeits-Sitzung verlassen"; out.okButton = 'OK (enter)'; @@ -237,11 +242,12 @@ out.history_next = "früher"; out.history_prev = "Zur früheren Version wechseln"; out.history_goTo = "Zur genannten Version wechseln"; + out.history_loadMore = "Load more history"; out.history_close = "Zurück"; out.history_closeTitle = "Verlauf schliessen"; out.history_restore = "wiederherstellen"; out.history_restoreTitle = "Die gewählte Version des Dokuments wiederherstellen"; - out.history_restorePrompt = "Bist du sicher, dass du die aktuelle Version mit der angezeigten ersetzen möchtest?"; + out.history_restorePrompt = "Bist Du sicher, dass Du die aktuelle Version mit der angezeigten ersetzen möchtest?"; out.history_restoreDone = "Version wiederhergestellt"; out.history_version = "Version:"; @@ -251,59 +257,68 @@ out.pad_mediatagWidth = "Breite (px)"; out.pad_mediatagHeight = "Höhe (px)"; - // Polls - - out.poll_title = "Datumsplaner ohne Preisgabe von Infos"; - out.poll_subtitle = "Echtzeit-planen ohne Preisgabe von Infos"; - - out.poll_p_save = "Deine Einstellungen werden sofort automatisch gesichert."; - out.poll_p_encryption = "Alle Eingaben sind verschlüsselt, deshalb haben nur Leute im Besitz des Links Zugriff. Selbst der Server sieht nicht was du änderst."; - - out.wizardLog = "Klicke auf den Button links oben um zur Umfrage zurückzukehren."; - out.wizardTitle = "Nutze den Assistenten um deine Umfrage zu erstellen."; - out.wizardConfirm = "Bist du wirklich bereit die angegebenen Optionen bereits zu deiner Umfrage hinzuzufügen?"; - - - out.poll_publish_button = "Veröffentlichen"; - out.poll_admin_button = "Admin"; - out.poll_create_user = "Neuen Benutzer hinzufügen"; - out.poll_create_option = "Neue Option hinzufügen"; - out.poll_commit = "Einchecken"; - - out.poll_closeWizardButton = "Assistent schließen"; - out.poll_closeWizardButtonTitle = "Assistent schließen"; - out.poll_wizardComputeButton = "Optionen übernehmen"; - out.poll_wizardClearButton = "Tabelle leeren"; - out.poll_wizardDescription = "Erstelle die Optionen automatisch, indem du eine beliebige Anzahl von Daten und Zeiten eingibst."; - out.poll_wizardAddDateButton = "+ Daten"; - out.poll_wizardAddTimeButton = "+ Zeiten"; - - out.poll_optionPlaceholder = "Option"; - out.poll_userPlaceholder = "Dein Name"; - out.poll_removeOption = "Bist du sicher, dass du diese Option entfernen möchtest?"; - out.poll_removeUser = "Bist du sicher, dass du diese(n) Nutzer*in entfernen möchtest?"; - - out.poll_titleHint = "Titel"; - out.poll_descriptionHint = "Beschreibe deine Abstimmung und publiziere sie mit dem 'Veröffentlichen'-Knopf wenn du fertig bis."+ - " Die Beschreibung kann mit dem Markdown Syntax geschrieben werden und du kannst Media-Elemente von deinem CryptPad einbetten." + - "Jeder mit dem Link kann die Beschreibung ändern, aber es ist keine gute Praxis."; + // Kanban + out.kanban_newBoard = "Neues Kanban-Bord"; + out.kanban_item = "Item {0}"; // Item number for initial content + out.kanban_todo = "Zu bearbeiten"; + out.kanban_done = "Erledigt"; + out.kanban_working = "In Bearbeitung"; + out.kanban_deleteBoard = "Bist Du sicher, dass Du dieses Bord löschen möchtest?"; + out.kanban_addBoard = "Ein Bord hinzufügen"; + out.kanban_removeItem = "Dieses Item entfernen"; + out.kanban_removeItemConfirm = "Bist Du sicher, dass Du dieses Item löschen möchtest?"; + + // Polls + out.poll_title = "Terminplaner ohne Preisgabe von Daten"; + out.poll_subtitle = "Echtzeit-planen ohne Preisgabe von Daten"; + + out.poll_p_save = "Deine Einstellungen werden sofort automatisch gesichert."; + out.poll_p_encryption = "Alle Eingaben sind verschlüsselt, deshalb haben nur Leute Zugriff, die den Link kennen. Selbst der Server sieht nicht was Du änderst."; + + out.wizardLog = "Klicke auf den Button links oben um zur Umfrage zurückzukehren."; + out.wizardTitle = "Nutze den Assistenten um Deine Umfrage zu erstellen."; + out.wizardConfirm = "Bist Du wirklich bereit, die angegebenen Optionen bereits zu Deiner Umfrage hinzuzufügen?"; + + out.poll_publish_button = "Veröffentlichen"; + out.poll_admin_button = "Admin"; + out.poll_create_user = "Neuen Benutzer hinzufügen"; + out.poll_create_option = "Neue Option hinzufügen"; + out.poll_commit = "Einchecken"; + + out.poll_closeWizardButton = "Assistent schließen"; + out.poll_closeWizardButtonTitle = "Assistent schließen"; + out.poll_wizardComputeButton = "Optionen übernehmen"; + out.poll_wizardClearButton = "Tabelle leeren"; + out.poll_wizardDescription = "Erstelle die Optionen automatisch, indem Du eine beliebige Anzahl von Daten und Zeiten eingibst."; + out.poll_wizardAddDateButton = "+ Daten"; + out.poll_wizardAddTimeButton = "+ Zeiten"; + + out.poll_optionPlaceholder = "Option"; + out.poll_userPlaceholder = "Dein Name"; + out.poll_removeOption = "Bist Du sicher, dass Du diese Option entfernen möchtest?"; + out.poll_removeUser = "Bist Du sicher, dass Du diese(n) Nutzer*in entfernen möchtest?"; + + out.poll_titleHint = "Titel"; + out.poll_descriptionHint = "Beschreibe Deine Abstimmung und publiziere sie mit dem 'Veröffentlichen'-Knopf wenn Du fertig bist."+ + " Die Beschreibung kann mit Markdown Syntax geschrieben werden und Du kannst Media-Elemente von Deinem CryptPad einbetten." + + "Jeder, der den Link kennt, kann die Beschreibung ändern, aber es ist keine gute Praxis."; out.poll_remove = "Entfernen"; out.poll_edit = "Bearbeiten"; out.poll_locked = "Gesperrt"; out.poll_unlocked = "Editierbar"; - out.poll_bookmark_col = 'Setze ein Lesezeichen auf dieser Spalte, damit sie immer editierbar und links immer für dich erscheint.'; - out.poll_bookmarked_col = 'Dieses ist die Splate mit Lesezeichen für dich. Sie wird immer editierbar und links für dich angezeigt.'; + out.poll_bookmark_col = 'Setze ein Lesezeichen auf dieser Spalte, damit sie immer gleich editierbar und links angezeigt wird.'; + out.poll_bookmarked_col = 'Dieses ist die Spalte mit Lesezeichen für Dich. Sie wird immer editierbar und links angezeigt.'; out.poll_total = 'SUMME'; out.poll_comment_list = "Komentare"; - out.poll_comment_add = "Ein Kommentar hinzufügen"; + out.poll_comment_add = "Einen Kommentar hinzufügen"; out.poll_comment_submit = "Schicken"; - out.poll_comment_remove = "Dieses Kommentar entfernen"; + out.poll_comment_remove = "Diesen Kommentar entfernen"; out.poll_comment_placeholder = "Dein Kommentar"; - out.poll_comment_disabled = "Diese Umfrage mit dem ✓ Knopf veröffentlichen, damit die Kommentare möglich sind."; + out.poll_comment_disabled = "Diese Umfrage mit dem ✓ Knopf veröffentlichen, damit Kommentare möglich sind."; // Canvas out.canvas_clear = "Löschen"; @@ -314,56 +329,55 @@ out.canvas_opacity = "Deckkraft"; out.canvas_opacityLabel = "Deckkraft: {0}"; out.canvas_widthLabel = "Breite: {0}"; - out.canvas_saveToDrive = "Dieses Bild in deinem CryptDrive speichern"; + out.canvas_saveToDrive = "Dieses Bild in Deinem CryptDrive speichern"; out.canvas_currentBrush = "Aktueller Pinsel"; out.canvas_chooseColor = "Eine Farbe wählen"; - out.canvas_imageEmbed = "Ein Bild aus deinem Rechner einbetten"; + out.canvas_imageEmbed = "Ein Bild aus Deinem Rechner einbetten"; // Profile out.profileButton = "Profil"; // dropdown menu out.profile_urlPlaceholder = 'URL'; - out.profile_namePlaceholder = 'Angezeigte name'; + out.profile_namePlaceholder = 'Angezeigter Name'; out.profile_avatar = "Avatar"; - out.profile_upload = " Ein neues Avatar hochladen"; + out.profile_upload = " Einen neuen Avatar hochladen"; out.profile_uploadSizeError = "Fehler: Dein Avatar muss kleiner als {0} sein"; - out.profile_uploadTypeError = "Fehler: Das Typ dieses Bild ist nicht unterestützt. Unterstütze Typen sind: {0}"; - out.profile_error = "Fehler bei der Erstellung deines Profils: {0}"; - out.profile_register = "Du muss dich einloggen, um ein Profil zu erstellen!"; + out.profile_uploadTypeError = "Fehler: Der Typ dieses Bildes wird nicht unterstützt. Unterstütze Typen sind: {0}"; + out.profile_error = "Fehler bei der Erstellung Deines Profils: {0}"; + out.profile_register = "Du muss Dich einloggen, um ein Profil zu erstellen!"; out.profile_create = "Ein Profil erstellen"; out.profile_description = "Beschreibung"; out.profile_fieldSaved = 'Neuer Wert gespeichert: {0}'; out.profile_inviteButton = "Sich in Verbindung setzen"; - out.profile_inviteButtonTitle ='Ein Link erstellen, damit dieser Benutzer sich mit dir in Verbindung setzt.'; - out.profile_inviteExplanation = "Ein Klick auf OK wird ein Link erstellen, dass eine sichere Chatsession nur mit {0} erlaubt.

          Dieses Link kann öffentlich gepostet werden."; + out.profile_inviteButtonTitle ='Ein Link erstellen, damit dieser Benutzer sich mit Dir in Verbindung setzt.'; + out.profile_inviteExplanation = "Ein Klick auf OK wird einen Link erstellen, der eine sichere Chatsession nur mit {0} erlaubt.

          Dieser Link kann öffentlich gepostet werden."; out.profile_viewMyProfile = "Mein Profil anzeigen"; // contacts/userlist out.userlist_addAsFriendTitle = 'Benutzer "{0}" als Kontakt hinzufügen'; - out.userlist_thisIsYou = 'Das bist du ("{0}")'; - out.userlist_pending = "Wartet..."; + out.userlist_thisIsYou = 'Das bist Du ("{0}")'; + out.userlist_pending = "Warte..."; out.contacts_title = "Kontakte"; out.contacts_addError = 'Fehler bei dem Hinzufügen des Kontakts in die Liste'; - out.contacts_added = 'Verbindungeinladung angenommen.'; - out.contacts_rejected = 'Verbindungeinladung abgelehnt'; - out.contacts_request = 'Benutzer {0} möchtet dich als Kontakt hinzufügen. Annehmen?'; + out.contacts_added = 'Verbindungseinladung angenommen.'; + out.contacts_rejected = 'Verbindungseinladung abgelehnt'; + out.contacts_request = 'Benutzer {0} möchtet Dich als Kontakt hinzufügen. Annehmen?'; out.contacts_send = 'Schicken'; - out.contacts_remove = 'Dieses Kontakt entfernen'; - out.contacts_confirmRemove = 'Bist du sicher, dass du {0} von der Kontaktliste entfernen möchtest?'; + out.contacts_remove = 'Diesen Kontakt entfernen'; + out.contacts_confirmRemove = 'Bist Du sicher, dass Du {0} von der Kontaktliste entfernen möchtest?'; out.contacts_typeHere = "Gebe eine Nachricht ein..."; - out.contacts_info1 = "Diese ist deine Kontaktliste. Ab hier, kannst du:"; - out.contacts_info2 = "Auf dem Avatar eines Kontakts klicken, um mit diesem Benutzer zu chatten"; - out.contacts_info3 = "Das Avatar doppelklicken, um sein Profil anzuzeigen"; - out.contacts_info4 = "Jede Teilnehmer, kann den Chatverlauf löschen"; + out.contacts_info1 = "Diese ist Deine Kontaktliste. Ab hier, kannst Du:"; + out.contacts_info2 = "Auf den Avatar eines Kontakts klicken, um mit diesem Benutzer zu chatten"; + out.contacts_info3 = "Den Avatar doppelklicken, um sein Profil anzuzeigen"; + out.contacts_info4 = "Jeder Teilnehmer kann den Chatverlauf löschen"; out.contacts_removeHistoryTitle = 'Den Chatverlauf löschen'; - out.contacts_confirmRemoveHistory = 'Bist du sicher, den Chatverlauf komplett zu löschen? Die Daten sind dann weg.'; - out.contacts_removeHistoryServerError = 'Es gab ein Fehler bei dem Löschen des Chatverlaufs. Versuche es noch einmal später'; + out.contacts_confirmRemoveHistory = 'Bist Du sicher, Dass Du den Chatverlauf komplett löschen willst? Die Daten sind dann weg.'; + out.contacts_removeHistoryServerError = 'Es gab einen Fehler bei dem Löschen des Chatverlaufs. Versuche es später noch einmal'; out.contacts_fetchHistory = "Den früheren Verlauf laden"; // File manager - out.fm_rootName = "Dokumente"; out.fm_trashName = "Papierkorb"; out.fm_unsortedName = "Dateien (ohne Ordnung)"; @@ -372,9 +386,10 @@ out.fm_searchName = "Suchen"; out.fm_recentPadsName = "Zuletzt geöffnete Dokumente"; out.fm_ownedPadsName = "Eigene"; + out.fm_tagsName = "Tags"; out.fm_searchPlaceholder = "Suchen..."; out.fm_newButton = "Neu"; - out.fm_newButtonTitle = "Ein neues Dokument oder Ordner gestalten, oder eine Datei in dem aktuellen Ordner importiere"; + out.fm_newButtonTitle = "Ein neues Dokument oder Ordner erstellen, oder eine Datei in den aktuellen Ordner importieren"; out.fm_newFolder = "Neuer Ordner"; out.fm_newFile = "Neues Dokument"; out.fm_folder = "Ordner"; @@ -391,49 +406,52 @@ out.fm_openParent = "Im Ordner zeigen"; out.fm_noname = "Dokument ohne Titel"; out.fm_emptyTrashDialog = "Soll der Papierkorb wirklich gelöscht werden?"; - out.fm_removeSeveralPermanentlyDialog = "Bist sicher, diese {0} Elemente dauerhaft aus deinem CryptDrive zu entfernen?"; - out.fm_removePermanentlyDialog = "Bist sicher, dieses Element dauerhaft aus deinem CryptDrive zu entfernen?"; - out.fm_removeSeveralDialog = "Bist du sicher, diese {0} Elemente aus dem Papierkorb zu entfernen?"; - out.fm_removeDialog = "Bist sicher, {0} zum Papierkorb zu verschieben?"; - out.fm_deleteOwnedPad = "Bist du sicher, dieses Dokument aus dem Server dauerhaft zu löschen?"; - out.fm_deleteOwnedPads = "Bist du sicher, dass du diese Dokumente dauerhaft aus dem Server entfernen möchtest?"; - out.fm_restoreDialog = "Bist du sicher, dass du {0} zurück zum originalen Ordner verschieben möchtests?"; - out.fm_unknownFolderError = "Der Ordner, der gerade gewählt oder letzlich besucht wurde, existiert nicht mehr. Der Parentordner wird geöffnet..."; - out.fm_contextMenuError = "Fehler bei der Öfnnung des Kontextmenü für dieses Element. Wenn dieses Problem wieder erscheint, versuche die Seite neuzuladen."; - out.fm_selectError = "Fehler bei der Selektierung des Zielelements. Wenn dieses Problem wieder erscheint, versuche die Seite neuzuladen."; - out.fm_categoryError = "Fehler bei dem Öffnen der selektierten Kategorie. Der Wurzel wird angezeigt."; - out.fm_info_root = "Gestalte hier soviele Ordnern, wie du willst, um deine Dateien und Dokumente zu organisieren."; - out.fm_info_unsorted = 'Hier sind alle Dateien, die du besucht hast, noch nicht in "Dokumente" sortiert sind oder zum Papierkorb verschoben wurden.'; - out.fm_info_template = 'Hier sind alle Dokumente, die als Vorlage gespeichert wurden und die du wiederverwenden kannst, um ein neues Dokument zu erstellen.'; - out.fm_info_recent = "Liste der zuletzt geöffnete Dokumente."; - out.updated_0_fm_info_trash = 'Leere den Papierkorb, um mehr freien Platz in deinem CryptDrive zu erhalten.'; + out.fm_removeSeveralPermanentlyDialog = "Bist Du sicher, dass Du diese {0} Elemente dauerhaft aus Deinem CryptDrive entfernen willst?"; + out.fm_removePermanentlyDialog = "Bist Du sicher, dass Du dieses Element dauerhaft aus Deinem CryptDrive entfernen willst?"; + out.fm_removeSeveralDialog = "Bist Du sicher, dasss Du diese {0} Elemente aus dem Papierkorb entfernen willst?"; + out.fm_removeDialog = "Bist Du sicher, dass Du {0} zum Papierkorb zu verschieben?"; + out.fm_deleteOwnedPad = "Bist Du sicher, dass Du dieses Dokument aus dem Server dauerhaft löschen willst?"; + out.fm_deleteOwnedPads = "Bist Du sicher, dass Du diese Dokumente dauerhaft aus dem Server entfernen möchtest?"; + out.fm_restoreDialog = "Bist Du sicher, dass Du {0} zurück zum originalen Ordner verschieben möchtests?"; + out.fm_unknownFolderError = "Der Ordner, der gerade gewählt oder letzlich besucht wurde, existiert nicht mehr. Der übergeordnete Ordner wird geöffnet..."; + out.fm_contextMenuError = "Fehler bei der Öfnnung des Kontextmenü für dieses Element. Wenn dieses Problem wieder erscheint, versuche die Seite neu zu laden."; + out.fm_selectError = "Fehler bei der Selektierung des Zielelements. Wenn dieses Problem wieder erscheint, versuche die Seite neu zu laden."; + out.fm_categoryError = "Fehler beim Öffnen der selektierten Kategorie. Der Stamm-Ordner wird angezeigt."; + out.fm_info_root = "Erstelle hier so viele Ordner, wie Du willst, um Deine Dateien und Dokumente zu organisieren."; + out.fm_info_unsorted = 'Hier sind alle Dateien, die Du besucht hast, die noch nicht in "Dokumente" sortiert sind oder zum Papierkorb verschoben wurden.'; + out.fm_info_template = 'Hier sind alle Dokumente, die als Vorlage gespeichert wurden und die Du wiederverwenden kannst, um ein neues Dokument zu erstellen.'; + out.fm_info_recent = "Liste der zuletzt geöffneten Dokumente."; + out.updated_0_fm_info_trash = 'Leere den Papierkorb, um mehr freien Platz in Deinem CryptDrive zu erhalten.'; out.fm_info_trash = out.updated_0_fm_info_trash; out.fm_info_allFiles = 'Beinhaltet alle Dateien von "Dokumente", "Unklassifiziert" und "Papierkorb". Dateien können hier nicht verschoben werden.'; out.fm_info_anonymous = 'Du bist nicht eingeloggt, daher laufen die Dokumente nach 3 Monaten aus (mehr dazu lesen). ' + - 'Zugang zu den Dokumenten ist in deinem Browser gespeichert, daher wir das Löschen des Browserverlaufs auch die Dokumente verschwinden lassen.
          ' + - 'Registriere dich oder logge dich ein, um sie dauerhaft zu machen.
          '; - out.fm_info_owned = "Diese Dokumente sind deine eigene. Das heisst, dass du sie vom Server entfernen kannst, wann du willst. Wenn du das machst, dann wird es auch keinen Zugriff zu diesem für andere Benutzer geben."; + 'Der Zugang zu den Dokumenten ist in Deinem Browser gespeichert, daher wird das Löschen des Browserverlaufs auch die Dokumente verschwinden lassen.
          ' + + 'Registriere Dich oder logge Dich ein, um sie dauerhaft zu machen.
          '; + out.fm_info_owned = "Diese Dokumente sind Deine eigenen. Das heisst, dass Du sie vom Server entfernen kannst, wann Du willst. Wenn Du das machst, dann wird es auch keinen Zugriff zu diesem für andere Benutzer geben."; out.fm_alert_backupUrl = "Backuplink für dieses CryptDrive.
          " + - "Es ist hoch empfohlen dieses Link geheim zu halten.
          " + - "Du kannst es benutzen, um deine gesamte Dateien abzurufen, wenn dein Browserspeicher gelöscht wurde.
          " + - "Jede Person, die dieses Link hat, kann die Dateien in deinem CryptDrive bearbeiten oder löschen.
          "; - out.fm_alert_anonymous = "Hallo, du benutzt CryptPad anonym. Das ist in Ordnung aber Dokumente können nach einer Inaktivitätsperiode gelöscht werden. " + - "Wir haben fortgeschrittene Aktionen aus dem anonymen CryptDrive entfernt, weil wir klar machen wollen, dass es kein sicherer Platz ist, Dinge zu lagern." + - 'Du kannst lesen, weshalb wir das machen und weshalb du wirklich ' + - 'registrieren oder eingloggen solltest.'; + "Es ist hoch empfohlen diesen Link geheim zu halten.
          " + + "Du kannst es benutzen, um Deine gesamten Dateien abzurufen, wenn Dein Browserspeicher gelöscht wurde.
          " + + "Jede Person, die diesen Link hat, kann die Dateien in Deinem CryptDrive bearbeiten oder löschen.
          "; + out.fm_alert_anonymous = "Hallo, Du benutzt CryptPad anonym. Das ist in Ordnung aber Dokumente können nach einer Inaktivitätsperiode gelöscht werden. " + + "Wir haben fortgeschrittene Aktionen aus dem anonymen CryptDrive entfernt, weil wir klar machen wollen, dass es kein sicherer Platz ist, Dinge zu lagern." + + 'Du kannst lesen, weshalb wir das machen und weshalb Du wirklich ' + + 'registrieren oder einloggen solltest.'; out.fm_backup_title = 'Backup link'; out.fm_nameFile = 'Wie soll diese Datei heissen?'; out.fm_error_cantPin = "Interner Serverfehler. Bitte lade die Seite neu und versuche es wieder."; - out.fm_viewListButton = "Listeansicht"; - out.fm_viewGridButton = "Kachelnansicht"; - out.fm_renamedPad = "Du hast ein spezielle Name für dieses Dokument gesetzt. Seine geteiltes Titel ist:
          {0}"; + out.fm_viewListButton = "Listenansicht"; + out.fm_viewGridButton = "Kachelansicht"; + out.fm_renamedPad = "Du hast einen speziellen Name für dieses Dokument gesetzt. Seine geteilter Titel ist:
          {0}"; out.fm_prop_tagsList = "Tags"; - out.fm_burnThisDriveButton = "Alle Informationen löschen , die CryptPad in deinem Browser hält"; - out.fm_burnThisDrive = "Bist du sicher, dass du alles, was CryptPad in deinem Browser hält löschen möchtest?
          " + - "Das wird dein CryptDrive und seinen Verlauf von deinem Browser löschen, Dokumente werden noch auf unseres Server (verschlüsselt) bleiben."; - out.fm_padIsOwned = "Dieses Dokument ist dein Eigenes"; + out.fm_burnThisDriveButton = "Alle Informationen löschen, die CryptPad in Deinem Browser hält"; + out.fm_burnThisDrive = "Bist Du sicher, dass Du alles, was CryptPad in Deinem Browser gespeichert hat, löschen möchtest?
          " + + "Das wird Dein CryptDrive und seinen Verlauf in Deinem Browser löschen, Dokumente werden noch (verschlüsselt) auf unserem Server bleiben."; + out.fm_padIsOwned = "Dieses Dokument ist Dein Eigenes"; out.fm_padIsOwnedOther = "Dieses Dokument ist von einem anderen Benutzer"; - out.fm_deletedPads = "Dieses Dokument existiert nicht mehr auf dem Server, es wurde von deinem CryptDrive gelöscht: {0}"; + out.fm_deletedPads = "Dieses Dokument existiert nicht mehr auf dem Server, es wurde von Deinem CryptDrive gelöscht: {0}"; + out.fm_tags_name = "Tag Bezeichnung"; + out.fm_tags_used = "Anzahl"; + // File - Context menu out.fc_newfolder = "Neuer Ordner"; out.fc_rename = "Unbenennen"; @@ -442,19 +460,20 @@ out.fc_delete = "Zum Papierkorb verschieben"; out.fc_delete_owned = "Vom Server löschen"; out.fc_restore = "Restaurieren"; - out.fc_remove = "Von deinem CryptDrive entfernen"; + out.fc_remove = "Von Deinem CryptDrive entfernen"; out.fc_empty = "Den Papierkorb leeren"; out.fc_prop = "Eigenschaften"; out.fc_hashtag = "Tags"; out.fc_sizeInKilobytes = "Grösse in Kilobytes"; + // fileObject.js (logs) - out.fo_moveUnsortedError = "Du kannst, ein Ordner nicht in die Liste von allen Pads verschieben"; - out.fo_existingNameError = "Dieser Dokumentname ist in diesem Verzeichnis schon da. Bitte wähle einen Anderen."; - out.fo_moveFolderToChildError = "Du kannst ein Ordner nicht in eine seine Nachfolgern verchieben"; - out.fo_unableToRestore = "Ein Fehler ist aufgetreten, um diese Datei zu seinem Herkunftordner zu verschieben. Du kannst probieren, diese zu einem anderen Ordner zu verschieben."; - out.fo_unavailableName = "Ein Dokument oder Ordner mit dem selben Name existiert in diesem Ordner schon. Bitte benenne es zuerst um, und versucht wieder zu verschieben."; + out.fo_moveUnsortedError = "Du kannst einen Ordner nicht in die Liste von allen Pads verschieben"; + out.fo_existingNameError = "Dieser Dokumentname existiert schon in diesem Verzeichnis. Bitte wähle einen Anderen."; + out.fo_moveFolderToChildError = "Du kannst einen Ordner nicht in einen seiner Nachfolger verschieben"; + out.fo_unableToRestore = "Es hat nicht funktioniert, diese Datei an ihrem Herkunftort wiederherzustellen. Du kannst versuchen, sie an einen anderen Ort zu verschieben."; + out.fo_unavailableName = "Ein Dokument oder Ordner mit diesem Namen existiert in diesem Ordner schon. Bitte benenne sie zuerst um, und versuche es dann erneut."; - out.fs_migration = "Dein CryptDrive wird gerade zu einer neueren Version aktualisiert. Daher muss die Seite neugeladen werden.
          Bite lade die Seite neu, um sie weiter zu verwenden."; + out.fs_migration = "Dein CryptDrive wird gerade zu einer neueren Version aktualisiert. Daher muss die Seite neugeladen werden.
          Bitte lade die Seite neu, um sie weiter zu verwenden."; // login out.login_login = "Einloggen"; @@ -469,43 +488,43 @@ out.login_confirm = "Passwort bestätigen"; out.login_remember = "Mein Login speichern"; - out.login_hashing = "Dein Passwort wird gerade durchgerechnet, das kann etwas dauert."; + out.login_hashing = "Dein Passwort wird gerade durchgerechnet, das kann etwas dauern."; out.login_hello = 'Hallo {0},'; // {0} is the username out.login_helloNoName = 'Hallo,'; out.login_accessDrive = 'Dein CryptDrive ansehen'; out.login_orNoLogin = 'oder'; - out.login_noSuchUser = 'Ungültiger Benutzername oder Passwort. Versuche es erneute oder registriere'; + out.login_noSuchUser = 'Ungültiger Benutzername oder Passwort. Versuche es erneut oder registriere Dich'; out.login_invalUser = 'Der Benutzername kann nicht leer sein'; out.login_invalPass = 'Der Passwort kann nicht leer sein'; out.login_unhandledError = 'Ein Fehler ist aufgetreten:('; - out.register_importRecent = "Die Dokumente aus deiner anonymen Sitzung importieren"; - out.register_acceptTerms = "Ich bin mit den Servicebedingungen einverstanden"; + out.register_importRecent = "Die Dokumente aus Deiner anonymen Sitzung importieren"; + out.register_acceptTerms = "Ich bin mit den Nutzungsbedingungen einverstanden"; out.register_passwordsDontMatch = "Passwörter sind nicht gleich!"; - out.register_passwordTooShort = "Passwörter müssen mindestens {0} Buchstaben haben."; + out.register_passwordTooShort = "Passwörter müssen mindestens {0} Zeichen haben."; - out.register_mustAcceptTerms = "Du musst mit den Servicebedingungen einverstanden sein."; - out.register_mustRememberPass = "Wir können dein Passwort nicht zurücksetzen, im Fall dass du dieses vergisst. Es ist äusserst wichtig, dass du dieses erinnerst! Bitte ticke das Kästchen ein."; + out.register_mustAcceptTerms = "Du musst mit den Nutzungsbedingungen einverstanden sein."; + out.register_mustRememberPass = "Wir können Dein Passwort nicht zurücksetzen, falls Du es vergisst. Es ist äusserst wichtig, dass Du es Dir merkst! Bitte markiere das Kästchen."; - out.register_whyRegister = "Wieso sollst du dich registrieren?"; + out.register_whyRegister = "Wieso solltest Du Dich registrieren?"; out.register_header = "Willkommen zu CryptPad"; out.register_explanation = [ "

          Lass uns ein Paar Punkte überprüfen:

          ", "
            ", - "
          • Dein Passwort ist dein Geheimnis, um alle deine Dokumente zu verschlüsseln. Wenn du es verlierst, gibt es keine Methode die Daten zurückzufinden.
          • ", - "
          • Du kannst die Dokumente, die du letzlich angesehen hast importieren, damit sind sie in deinem CryptDrive.
          • ", - "
          • Wenn du auf einem geteilten Rechner bist, muss du ausloggen, wenn du fertig bist. Es ist nicht ausreichend, die Browserfensters (oder das Browser) zu schliessen.
          • ", + "
          • Dein Passwort ist Dein Geheimnis, um alle Deine Dokumente zu verschlüsseln. Wenn Du es verlierst, gibt es keine Methode, die Daten wiederzufinden.
          • ", + "
          • Du kannst die Dokumente, die Du zuletzt angesehen hast, importieren, damit sie in Deinem CryptDrive sind.
          • ", + "
          • Wenn Du den Rechner mit anderen teilst, musst Du ausloggen, wenn Du fertig bist. Es ist nicht ausreichend, das Browserfensters oder den Browser zu schliessen.
          • ", "
          " ].join(''); out.register_writtenPassword = "Ich habe meinen Benutzername und Passwort notiert. Weiter geht's."; out.register_cancel = "Zurück"; - out.register_warning = "\"Ohne Preisgabe von Information\" heisst, dass wir keine Methode haben, wenn du dein Passwort verlierst."; + out.register_warning = "\"Ohne Preisgabe von Daten\" heisst, dass niemand Deine Daten wiederherstellen kann, wenn Du Dein Passwort verlierst."; - out.register_alreadyRegistered = "Dieser Benutzer existiert schon, willst du dich einloggen?"; + out.register_alreadyRegistered = "Dieser Benutzer existiert schon, willst Du Dich einloggen?"; // Settings out.settings_cat_account = "Konto"; @@ -518,15 +537,15 @@ out.settings_save = "Speichern"; out.settings_backupCategory = "Backup"; - out.settings_backupTitle = "Eine Backup erstellen oder die Daten restaurieren"; + out.settings_backupTitle = "Eine Backup erstellen oder die Daten wiederherstellen"; out.settings_backup = "Backup"; - out.settings_restore = "Restaurieren"; + out.settings_restore = "Wiederherstellen"; out.settings_resetNewTitle = "CryptDrive säubern"; out.settings_resetButton = "Löschen"; - out.settings_reset = "Alle Dateien und Ordnern aus deinem CryptDrive löschen"; - out.settings_resetPrompt = "Diese Aktion wird alle Dokumente deines CryptDrives entfernen.
          "+ - "Bist du sicher, dass du es tun möchtest?
          " + + out.settings_reset = "Alle Dateien und Ordnern aus Deinem CryptDrive löschen"; + out.settings_resetPrompt = "Diese Aktion wird alle Dokumente Deines CryptDrives entfernen.
          "+ + "Bist Du sicher, dass Du das tun möchtest?
          " + "Gebe I love CryptPad ein, um zu bestätigen."; // TODO: I love CryptPad should be localized out.settings_resetDone = "Dein CryptDrive ist jetzt leer!"; out.settings_resetError = "Prüftext inkorrekt. Dein CryptDrive wurde nicht verändert."; @@ -537,67 +556,76 @@ out.settings_resetTipsDone = "Alle Tipps sind wieder sichtbar."; out.settings_thumbnails = "Vorschaubilder"; - out.settings_disableThumbnailsAction = "Die Gestaltung von Vorschaubilder in deinem CryptPad deaktivieren"; - out.settings_disableThumbnailsDescription = "Vorschaubilder sind automatisch erstellt und gespeichert in deinem Browser, wenn du ein Dokument besuchst. Du kannst dieses Feature hier deaktivieren."; + out.settings_disableThumbnailsAction = "Die Erstellung von Vorschaubilder in Deinem CryptPad deaktivieren"; + out.settings_disableThumbnailsDescription = "Vorschaubilder werden automatisch erstellt und in Deinem Browser gespeichert, wenn Du ein Dokument besuchst. Du kannst dieses Feature hier deaktivieren."; out.settings_resetThumbnailsAction = "Entfernen"; - out.settings_resetThumbnailsDescription = "Alle Vorschaubilder entfernen, die in deinem Browser gespeichert sind."; - out.settings_resetThumbnailsDone = "Alle Vorschaubilder sind entfern worden."; + out.settings_resetThumbnailsDescription = "Alle Vorschaubilder entfernen, die in Deinem Browser gespeichert sind."; + out.settings_resetThumbnailsDone = "Alle Vorschaubilder sind entfernt worden."; - out.settings_importTitle = "Importierie die neulich besuchte Dokumente in deinem CryptDrive"; + out.settings_importTitle = "Importiere die kürzlich besuchte Dokumente in Deinem CryptDrive"; out.settings_import = "Importieren"; - out.settings_importConfirm = "Bist du sicher, dass du die neulich besuchte Dokumente in deinem Konto importieren möchtest??"; + out.settings_importConfirm = "Bist Du sicher, dass Du die kürzlich besuchte Dokumente in Deinem Konto importieren möchtest??"; out.settings_importDone = "Import erledigt"; out.settings_userFeedbackTitle = "Rückmeldung"; - out.settings_userFeedbackHint1 = "CryptPad gibt grundlegende Rückmeldungen zum Server. Es erlaubt uns, wie wir deine Erfahrung verbessern können."; - out.settings_userFeedbackHint2 = "Der Inhalt deiner Dokumente wird nie mit dem Server geteilt."; + out.settings_userFeedbackHint1 = "CryptPad gibt grundlegende Rückmeldungen zum Server, um die Benutzer-Erfahrung zu verbessern können."; + out.settings_userFeedbackHint2 = "Der Inhalt Deiner Dokumente wird nie mit dem Server geteilt."; out.settings_userFeedback = "Rückmeldungen aktivieren"; out.settings_deleteTitle = "Löschung des Kontos"; - out.settings_deleteHint = "Die Löschung eines Kontos ist dauerhaft. Dein CryptDrive und eigene Dokumente werden alle von dem Server gelöscht. Die restliche Dokumente werden nach 90 Tage gelöscht, wenn keine andere diese bei sich gelagert haben."; + out.settings_deleteHint = "Die Löschung eines Kontos ist dauerhaft. Dein CryptDrive und eigene Dokumente werden alle von dem Server gelöscht. Die restliche Dokumente werden nach 90 Tage gelöscht, wenn niemand anderes diese bei sich gelagert hat."; out.settings_deleteButton = "Dein Konto löschen"; - out.settings_deleteModal = "Gebe die folgende Information zu deinem CryptPad Adminstrator, damit er die Daten vom Server löschen kann."; - out.settings_deleteConfirm = "OK klicken wird dein Konto dauerhaft löschen. Bist du sicher?"; - out.settings_deleted = "Dein Konto ist jetzt gelöscht. Drucke OK, um zum Homepage zu gelingen."; + out.settings_deleteModal = "Gebe die folgende Information Deinem CryptPad Adminstrator, damit er die Daten vom Server löschen kann."; + out.settings_deleteConfirm = "Wenn Du OK klickst, wird Dein Konto dauerhaft löschen. Bist Du sicher?"; + out.settings_deleted = "Dein Konto ist jetzt gelöscht. Drucke OK, um zum Homepage zu gelangen."; - out.settings_anonymous = "Du bist nicht eingeloggt. Die Einstellungen hier sind spezifisch zu deinem Browser."; + out.settings_anonymous = "Du bist nicht eingeloggt. Die Einstellungen hier gelten nur für diesem Browser."; out.settings_publicSigningKey = "Öffentliche Schlüssel zum Unterschreiben"; out.settings_usage = "Verbrauch"; - out.settings_usageTitle = "Die Gesamtgrösse deiner Dokumente in MB"; // TODO: pinned ?? - out.settings_pinningNotAvailable = "Genagelte Dokumente sind nur für angemeldete Benutzer verfügbar."; + out.settings_usageTitle = "Die Gesamtgrösse Deiner Dokumente in MB"; // TODO: pinned ?? + out.settings_pinningNotAvailable = "Gepinnte Dokumente sind nur für angemeldete Benutzer verfügbar."; out.settings_pinningError = "Etwas ging schief"; - out.settings_usageAmount = "Deine genagelte Dokumente verwenden {0}MB"; + out.settings_usageAmount = "Deine gepinnten Dokumente verwenden {0}MB"; out.settings_logoutEverywhereButton = "Ausloggen"; - out.settings_logoutEverywhereTitle = "Von jeden Browsers ausloggen"; - out.settings_logoutEverywhere = "Das Ausloggen in alle andere Websitzungen erzwingen"; - out.settings_logoutEverywhereConfirm = "Bist du sicher? Du wirdst auf allen deinen Geräten dich wieder einloggen müssen."; + out.settings_logoutEverywhereTitle = "Überall ausloggen"; + out.settings_logoutEverywhere = "Das Ausloggen in allen andere Websitzungen erzwingen"; + out.settings_logoutEverywhereConfirm = "Bist Du sicher? Du wirst Dich auf allen Deinen Geräten wieder einloggen müssen."; - out.settings_codeIndentation = 'Einrücken für das Codeeditor (Leerzeichen)'; + out.settings_codeIndentation = 'Einrücken für den Code-Editor (Leerzeichen)'; out.settings_codeUseTabs = "Mit Tabs einrücken (anstatt mit Leerzeichen)"; - out.settings_padWidth = "Maximumgrösse des Editors"; - out.settings_padWidthHint = "Rich-text Dokumente benutzen normalerweise die grösste verfügbare Breite und es kann manchmal schwer lesebar sein. Du kannst die Breite des Editors hier reduzieren."; + out.settings_padWidth = "Maximalgrösse des Editors"; + out.settings_padWidthHint = "Rich-text Dokumente benutzen normalerweise die grösste verfügbare Zeilenbreite, das kann manchmal schwer lesbar sein. Du kannst die Breite des Editors hier reduzieren."; out.settings_padWidthLabel = "Die Breite des Editors reduzieren"; - out.settings_creationSkip = "Das Erstellungsdialg für neue Dokumente vermeiden"; - out.settings_creationSkipHint = "Dieses Erstellungsdialog erlaubt Einstellungen vorzunehmen, um mehr Sicherheit und Kontroll für deine Dokumente zu geben. Aber es kann manchaml dir verlangsam, da es eine zusätzliche Stufe verlange. Mit dieser Option kannst du die dieses Dialog vermeiden und die default-Einstellungen wählen."; - out.settings_creationSkipTrue = "vermeiden"; - out.settings_creationSkipFalse = "anzeigen"; + out.settings_creationSkip = "Den Erstellungsdialg für neue Dokumente überspringen"; + out.settings_creationSkipHint = "Dieser Erstellungsdialog erlaubt Einstellungen für mehr Kontrolle und Sicherheit bei Deinen Dokumenten. Aber der zusätzliche Dialog verlangsamt die Arbeit. Mit dieser Option kannst Du diese Dialog überspringen und die Standard-Einstellungen wählen."; + out.settings_creationSkipTrue = "Überspringen"; + out.settings_creationSkipFalse = "Anzeigen"; + + out.settings_templateSkip = "Die Wahl der Vorlage überspringen"; + out.settings_templateSkipHint = "Wenn Du ein neues Dokument erstellst und Vorlagen vorhanden sind, erscheint ein Dialog, wo Du die Vorlage wählen kannst. Hier kannst Du diesen Dialog überspringen und somit keine Vorlage verwenden."; - out.settings_templateSkip = "Die Wahl der Vorlage vermeiden"; - out.settings_templateSkipHint = "Wenn du ein neues Dokument erstellt, und wenn Vorlagen da sind, erscheint ein Dialog, wo du die Vorlage wählen kannst. Hier kannst du dieses Dialog vermeiden und somit keine Vorlage verwenden."; + out.settings_changePasswordTitle = "Ändere Dein Passwort"; // XXX + out.settings_changePasswordHint = "Ändere das Passwort Deines Kontos ohne Deine Daten zu verlieren. Du mußt einmal das jetzige Passwort eintragen und dann das gewünschte neue Passwort zweimal.
          " + + "Wir können das Passwort nicht zurücksetzen, wenn Du es vergisst, also sei besonders sorgfältig!"; // XXX + out.settings_changePasswordButton = "Passwort ändern"; // XXX + out.settings_changePasswordCurrent = "Jetziges Passwort"; // XXX + out.settings_changePasswordNew = "Neues Passwort"; // XXX + out.settings_changePasswordNewConfirm = "Neues Passwort bestätigen"; // XXX + out.settings_changePasswordConfirm = "Bist Du sicher?"; // XXX out.upload_title = "Datei hochladen"; - out.upload_rename = "Willst du einen neuen Name für {0} geben, bevor es zum Server hochgeladen wird?
          " + + out.upload_rename = "Willst Du einen neuen Name für {0} geben, bevor es zum Server hochgeladen wird?
          " + "Die Dateieendung ({1}) wird automatisch hinzugefügt. "+ "Dieser Name bleibt für immer und wird für die andere Benutzer sichtbar."; - out.upload_serverError = "Serverfehler: Die Datei kann nicht aktuell hochgeladen werden. "; - out.upload_uploadPending = "Ein anderes Hochladen passiert gerade. Willst du es abbrechen und deine neue Datei hochladen?"; - out.upload_success = "Deine Datei ({0}) wurde erfolgreich hochgeladen und in deinem CryptDrive hinzugefügt."; - out.upload_notEnoughSpace = "Der verfügbare Speicherplatz auf deinem CryptDrive reicht leider nicht für diese Datei."; - out.upload_notEnoughSpaceBrief = "Unsaureichende Volumen"; + out.upload_serverError = "Serverfehler: Die Datei kann aktuell nicht hochgeladen werden. "; + out.upload_uploadPending = "Ein anderes Hochlade-Vorgang läuft gerade. Willst Du den abbrechen und Deine neue Datei hochladen?"; + out.upload_success = "Deine Datei ({0}) wurde erfolgreich hochgeladen und in Deinem CryptDrive hinzugefügt."; + out.upload_notEnoughSpace = "Der verfügbare Speicherplatz auf Deinem CryptDrive reicht leider nicht für diese Datei."; + out.upload_notEnoughSpaceBrief = "Unzureichender Speicherplatz"; out.upload_tooLarge = "Diese Datei ist zu gross, um hochgeladen zu werden."; out.upload_tooLargeBrief = 'Datei zu gross'; out.upload_choose = "Eine Datei wählen"; @@ -613,17 +641,17 @@ out.todo_title = "CryptTodo"; out.todo_newTodoNamePlaceholder = "Die Aufgabe prüfen..."; - out.todo_newTodoNameTitle = "Diese Aufgabe zu deiner ToDo-Liste hinzufügen"; + out.todo_newTodoNameTitle = "Diese Aufgabe zu Deiner ToDo-Liste hinzufügen"; out.todo_markAsCompleteTitle = "Diese Aufgabe als erledigt markieren"; out.todo_markAsIncompleteTitle = "Diese Aufgabe als nicht erledigt markieren"; - out.todo_removeTaskTitle = "Diese Aufgabe aus deiner ToDo-Liste entfernen"; + out.todo_removeTaskTitle = "Diese Aufgabe aus Deiner ToDo-Liste entfernen"; // pad out.pad_showToolbar = "Werkzeugsleiste anzeigen"; out.pad_hideToolbar = "Werkzeugsleiste verbergen"; // markdown toolbar - out.mdToolbar_button = "Die Markdown Werkzeugsleiste anzeigen oder verbergen"; + out.mdToolbar_button = "Die Markdown-Werkzeugsleiste anzeigen oder verbergen"; out.mdToolbar_defaultText = "Dein Text hier"; out.mdToolbar_help = "Hilfe"; out.mdToolbar_tutorial = "http://www.markdowntutorial.com/"; @@ -634,49 +662,32 @@ out.mdToolbar_link = "Link"; out.mdToolbar_quote = "Zitat"; out.mdToolbar_nlist = "Nummerierte Liste"; - out.mdToolbar_list = "Aufählung"; + out.mdToolbar_list = "Aufzählung"; out.mdToolbar_check = "Aufgabenliste"; out.mdToolbar_code = "Code"; - // index.html + // index.html //about.html - out.main_about_p2 = 'Dieses Projekt verwendet CKEditor WYSIWYG Editor, CodeMirror, sowie das ChainPad echtzeit Engine.'; - - out.main_howitworks_p1 = 'CryptPad verwendet ein alternative Operational transformation Algorithmus, der verteilt Konsens mit einem Nakamoto Blockchain erreicht, eine Informationskonstrukt, was für Bitcoin bekannt wurde. Damit kann der Algorithmus ohne die Mitarbeit eines zentrales Server die Konflikte von Operational Transform lösen; dadurch kann der Server auch ohne Kenntnisse des Inhalts der Dokumente bleiben.'; + out.about_intro = 'CryptPad wurde erstellt im Research Team von XWiki SAS, einem kleinen Unternehmen in Paris, Frankreich, und Iasi, Rumänien. Das kernteam hat 3 Mitglieder, die an CryptPad arbeiten, sowie einige Mitwirkende innerhalb von XWiki SAS und außerhalb.'; + out.about_core = 'Core Developers'; + out.about_contributors = 'Key Contributors'; // contact.html - out.main_about_p2 = 'Wenn du Fragen oder Kommentare hast, hören wir sie gern!
          Du kannst uns antweeten, ein Issue öffnen on GitHub. Komm und sag hallo auf our der Matrix Kanal or IRC (#cryptpad on irc.freenode.net), or schick uns ein Email.'; out.main_about_p22 = 'Uns antweeten'; - out.main_about_p23 = 'ein Issue auf GitHub aufnehmen'; + out.main_about_p23 = 'Eine Issue auf GitHub erstellen'; out.main_about_p24 = 'Hallo sagen (Matrix)'; out.main_about_p25 = 'uns ein Email schicken'; - out.main_about_p26 = 'Wenn du Fragen oder Kommentare hast, freuen wir davon zu hören!'; - - out.main_info = "

          Vertrauenswürdige Kollaboration

          Lass deine Ideen wachsen während die ohne Preisgabe deiner Informationen Technologie deinen Datenschutz sogar gegenüber uns sichert."; - out.main_catch_phrase = "Das Cloud ohne Preisgabe deiner Informationen"; - - out.main_howitworks = 'Wie fukntioniert es'; - out.main_zeroKnowledge = 'Ohne Preisgabe deiner Informationen'; - out.main_zeroKnowledge_p = "Du brauchst nicht uns dein Vertrauen geben, dass wir deine Dokumente nicht angucken werden: Mit der Technologie können wir das einfach nicht. Erfahre mehr, wie wir dein Datenschutz und Sicherheit sichern."; - - out.main_writeItDown = 'Runterschreiben'; - - out.main_writeItDown_p = "Die grösste Projekte stammen aus den kleinsten Ideen. Schreibe runter deine Inspirationsmomente und unerwartete Ideen, da du nie weisst, welche ein Durchbruch sein wird."; - out.main_share = 'Teile das Link, teile das Dokument'; - out.main_share_p = "Lasse deine Ideen gemeinsam wachsen: Führe effektive Treffen, kooperiere auf ToDo-Listen und mache kurze Vorträge mit alle deinen Bekannten und mit alle deinen Geräten."; - out.main_organize = 'Organisiere dich'; - out.main_organize_p = "Mit CryptPad Drive kannst du deinen Übersicht auf das Wichtiges behalten. Ordnern erlauben, deine Projekte zu organisieren und einen Übersicht behalten, über was geht wo."; - out.tryIt = 'Versuche es!'; - out.main_richText = 'Rich Text Editor'; - out.main_richText_p = 'Bearbeite Rich-Text kollaborativ mit unserem echtzeit CkEditor ohne Preisgabe deiner Informationen app.'; - out.main_code = 'Code Editor'; - out.main_code_p = 'Bearbeite Code kollaborativ mit unseren echtzeit CodeMirror app ohne Preisgabe deiner Informationen.'; - out.main_slide = 'Präsentationeneditor'; - out.main_slide_p = 'Gestalte Präsentationen mit der Markdown Syntax und zeige sid im Browser an.'; + out.main_about_p26 = 'Wenn Du Fragen oder Kommentare hast, freuen wir uns, von Dir zu hören!'; + + out.main_info = "

          Vertrauenswürdige Kollaboration

          Lass Deine Ideen gemeinsam wachsen, während die Zero Knowledge-Technologie Deinen Datenschutz sogar uns gegenüber sichert."; + out.main_catch_phrase = "Die Cloud ohne Preisgabe Deiner Daten"; + + out.main_richText = 'Text-Editor'; + out.main_code = 'Code-Editor'; + out.main_slide = 'Präsentations-Editor'; out.main_poll = 'Umfragen'; - out.main_poll_p = 'Plane ein Treffen oder ein Event, und lass die beste Wahl online treffen.'; out.main_drive = 'CryptDrive'; out.main_richTextPad = 'Rich Text Dokument'; @@ -684,9 +695,10 @@ out.main_slidePad = 'Markdown Präsentation'; out.main_pollPad = 'Umfrage oder Terminabstimmung'; out.main_whiteboardPad = 'Whiteboard'; + out.main_kanbanPad = 'Kanban-Bord'; out.main_localPads = 'Lokale Dokumente'; out.main_yourCryptDrive = 'Dein CryptDrive'; - out.main_footerText = "Mit CryptPad, du kannst schnell kollaborative Dokumente erstellen, um Notizzen oder Ideen zusammen runterzuschreiben."; + out.main_footerText = "Mit CryptPad kannst Du schnell kollaborative Dokumente erstellen, um Notizen oder Ideen zusammen mit anderen zu bearbeiten."; out.footer_applications = "Apps"; out.footer_contact = "Kontakt"; @@ -695,52 +707,49 @@ out.about = "Über uns"; out.privacy = "Datenschutz"; out.contact = "Kontakt"; - out.terms = "Servicebendingungen"; + out.terms = "Nutzungsbedingungen"; out.blog = "Blog"; out.topbar_whatIsCryptpad = "Was ist CryptPad"; // what-is-cryptpad.html - out.whatis_title = 'Was ist CryptPad'; - out.whatis_collaboration = 'Effektive und und leichte Kollaboration'; - out.whatis_collaboration_p1 = 'Mit CryptPad kannst du kollaborative Dokumente erstellen, um Notizzen und Ideen zusammen runterzuschreiben. Wenn du dich registrierst und loggst dich ein, kriegst die Möglichkeit Dateien hochzuladen, und Ordnern um alle deine Dokumente zu organisieren.'; - out.whatis_collaboration_p2 = 'Du kannst Zugang zu einem CryptPad teilen, indem du das Link teilst. Du kannst auch einen schreibgeschützten Zugang, um die Ergebnisse deiner kollaborativen Arbeit zu veröffentlichen, während du sie noch bearbeiten kannst.'; - out.whatis_collaboration_p3 = 'Du kannst Rich-Text Dokumente mit dem CKEditor sowie Markdown Dokumente, die in Echtzeit angezeigt werden, während du tipps. Du kannst auch die Umfrage App verwenden, um Ereignisse unter mehrere Teilnehmern zu synchroniseren.'; - out.whatis_zeroknowledge = 'Ohne Preisgabe von Informationen'; - out.whatis_zeroknowledge_p1 = "Wir wollen nicht wissen, was du gerade tippst. Und mit modernen Verschlüsselungstechnologie, du kannst sicher sein, dass wir nicht es nicht können. CryptPad verwendet 100% Clientseitige Verschlüsselung, um den Inhalt von uns zu schützen, wir die Personen die das Website hosten."; - out.whatis_zeroknowledge_p2 = 'Wenn du dich registrierst und logge dich ein, dein Benutzername und Passwort sind in einem Schlüssel umgerechnet mit einer Scrypt Ableitungsfunktion. Weder ist dieser Schlüssel noch der Benutzername oder Passwort sind zum Server geschickt. Anstatt dessen sind sie benutzt clientseitig, um den Inhalt deinese CryptDrives zu entschlüsseln. Dieses beinhaltet alle Dokumente, die die zugänglich sind.'; - out.whatis_zeroknowledge_p3 = 'Wenn du ein Dokument teilst, teilst auch den kryptografischen Schlüssel, der Zugang zu diesem Dokument gibt. Da dieser Schlüssel im fragment identifier ist, ist das nie direkt zum Server geschickt. Bitte lese unsere Blogeintrag über Datenschutz um mehr zu erfahren, welche Typen von Kontextinformation wir zugänglich und nicht zugänglich haben.'; + out.whatis_collaboration = 'Effektive und und leichte Zusammenarbeit'; + out.whatis_collaboration_p1 = 'Mit CryptPad kannst Du kollaborative Dokumente erstellen, um Notizen und Ideen gemeinsam zu bearbeiten. Wenn Du Dich registrierst und Dich einloggst, bekommst Du die Möglichkeit, Dateien hochzuladen und Ordner einzurichten, um alle Deine Dokumente zu organisieren.'; + out.whatis_collaboration_p2 = 'Du kannst Zugang zu einem CryptPad teilen, indem Du den Link teilst. Du kannst auch einen schreibgeschützten Zugang erstellen, um die Ergebnisse Deiner Arbeit zu teilen, während Du sie noch bearbeitest.'; + out.whatis_collaboration_p3 = 'Du kannst Rich-Text Dokumente mit dem CKEditor sowie Markdown Dokumente erstellen, die in Echtzeit angezeigt werden, während Du tippst. Du kannst auch die Umfrage-App verwenden, um Termine unter mehrere Teilnehmern zu abzustimmen.'; + out.whatis_zeroknowledge = 'Zero Knowledge - Ohne Preisgabe von Daten'; + out.whatis_zeroknowledge_p1 = "Wir wollen nicht wissen, was Du gerade tippst. Und mit moderner Verschlüsselungstechnologie, kannst Du sicher sein, dass wir es auch nicht können. CryptPad verwendet 100% Clientseitige Verschlüsselung, um den Inhalt vor uns, den Hostern dieser Website, zu schützen."; + out.whatis_zeroknowledge_p2 = 'Wenn Du Dich registrierst und Dich einloggst, werden Dein Benutzername und Passwort in einen Schlüssel umgerechnet mit einer Scrypt Sclüssel-Ableitungsfunktion. Weder dieser Schlüssel noch der Benutzername oder das Passwort werden zum Server geschickt. Stattdessen werden sie clientseitig benutzt, um den Inhalt Deines CryptDrives zu entschlüsseln. Dieses beinhaltet alle Dokumente, die Dir zugänglich sind.'; + out.whatis_zeroknowledge_p3 = 'Wenn Du ein Dokument teilst, teilst Du auch den kryptografischen Schlüssel, der Zugang zu diesem Dokument gibt. Da dieser Schlüssel im fragment identifier liegt, wird er nie direkt zum Server geschickt. Bitte lese unsere Blogeintrag über Datenschutz um mehr zu erfahren, welche Typen von Kontextinformation wir zugänglich und nicht zugänglich haben.'; out.whatis_drive = 'Organisieren mit CryptDrive'; - out.whatis_drive_p1 = 'Sobald ein Dokument mit CryptPad zugegriffen wird, ist deses automatisch zu deinem CryptDrive hinzugefügt, im Stamm Ordner. Später kannst du diese Dokumente in Ordnern organisieren oder du kannst es im Papierkorb verschieben. CryptDrive erlaubt die Suche durch deine Dokumente, wie und wann du willst.'; - out.whatis_drive_p2 = 'Mit dem einfachsten Ziehen und Schieben Gesten kannst du die Dokumente herum von deinem Drive umplatzieren. Die Links zu diesen Dokumenten bleiben erhalten damit Kollaboratoren nie Zugang verlieren.'; - out.whatis_drive_p3 = 'Du kannst auch Dateien in dein CryptDrive hochladen und mit deinen Kollegen teilen. Hochgeladene Dateien können genau so wie kollaborative Dokumente organisiert werden.'; + out.whatis_drive_p1 = 'Sobald auf ein Dokument mit CryptPad zugegriffen wird, wird deses automatisch zu Deinem CryptDrive hinzugefügt, im Stamm-Ordner. Später kannst Du diese Dokumente in eigenen Ordnern organisieren oder Du kannst es in den Papierkorb verschieben. CryptDrive erlaubt die Suche durch Deine Dokumente, wie und wann Du willst.'; + out.whatis_drive_p2 = 'Mit dem einfachem Ziehen und Ablegen kannst Du die Dokumente auf Deinem CryptDrive umplatzieren. Die Links zu diesen Dokumenten bleiben erhalten, damit Kollaboratoren nie Zugang verlieren.'; + out.whatis_drive_p3 = 'Du kannst auch Dateien in Dein CryptDrive hochladen und mit Deinen Kollegen teilen. Hochgeladene Dateien können genau so wie kollaborative Dokumente organisiert werden.'; out.whatis_business = 'CryptPad im Business'; - out.whatis_business_p1 = 'Der Grundprinzip von CryptPad (Verschlüsselung ohne Preisgabe der Information) ist ausgezeichnet, um die Effektivität von existierenden Protokolle, indem die Zugangsberechtigungen des Unternehmens in die Kryptografie umgesetzt werden. Weil hochsensible Medien nur mit Angestelltenzugang entschlüsselt werden kann, kann CryptPad das Jackpot der Hackers wegnehmen, was in der Natur von tradionellen IT Servers liegt. Lese das CryptPad Whitepaper, um mehr zu erfahren, wir CryptPad dein Unternehmen helfen kann.'; - out.whatis_business_p2 = 'CryptPad kann auf eigenen Rechnern installiert werden. CryptPad Entwicklers at XWiki SAS können kommerzielle Unterstützung, Customisierung und Entwicklung anbieten. Bitte schicke ein Email zu sales@cryptpad.fr, um mehr zu erfahren.'; - - // privacy.html - - out.policy_title = 'Cryptpad Datenschutzbestimmungen'; - out.policy_whatweknow = 'Was wir über dich wissen'; - out.policy_whatweknow_p1 = 'Als Programm, das im Web gehostet wird, hat Cryptpad Zugriff auf die Metadaten, die vom HTTP-Protokoll exponiert werden. Inbegriffen ist deine IP-Adresse und diverse andere HTTP-Header, die es ermöglichen deinen Browser zu identifizieren. Um zu sehen welche Daten dein Browser preis gibt kanst du die Seite WhatIsMyBrowser.com besuchen.'; - out.policy_whatweknow_p2 = 'Wir nutzen Piwik, eine open source Analyseplatform um mehr über unsere Nutzer*innen zu lernen. Piwik teilt uns mit, wie du Cryptpad gefunden hast — durch direkten Zugriff, mit Hilfe eine Suchmaschine oder über einen Link auf einer anderen Seite wie z.B. Reddit oder Twitter. Außerdem lernen wir mehr über deinen Besuch, welchen Link du auf den Informationsseiten klickst und wie lange du auf diesen Seiten verweilst.'; - out.policy_howweuse = 'Wie wir das Wissen anwenden'; - out.policy_howweuse_p1 = 'Wir nutzen diese Informationen um besser entscheiden zu können wie Cryptpad beworben werden kann und um genutzte Strategien zu evaluieren. Informationen über deinen Standort helfen uns abzuschätzen welche Sprachen wir besser unterstützen sollten.'; - out.policy_howweuse_p2 = "Informationen zu deinem Browser (ob du auf einem Desktop oder Smartphone arbeitest) hilft uns außerdem dabei zu entscheiden, welche Features priorisiert werden sollen. Unser Entwicklerteam ist klein, deshalb ist es uns wichtig Entscheidungen derart zu treffen, dass die Erfahrung der größten Zahl von Nutzer*innen verbessert wird."; - out.policy_whatwetell = 'Was wir anderen über die erzählen'; - out.policy_whatwetell_p1 = 'Wir reichen keine von uns gesammelten Daten weiter, außer im Falle einer gerichtlichen Anordnung.'; - out.policy_links = 'Links zu anderen Seiten'; - out.policy_links_p1 = 'Diese Seite beinhaltet Links zu anderen Seiten, teilweise werden diese von anderen Organisationen verwaltet. Wir sind nicht für den Umgang mit der Privatsphäre und die Inhalte der anderen Seiten verantwortlich. Generell werden Links zu externen Seiten in einem neuem Fenster geöffnet, um zu verdeutlichen, dass du Cryptpad.fr verlässt.'; - out.policy_ads = 'Werbung'; - out.policy_ads_p1 = 'Wir zeigen keine Onlinewerbung, können aber zu Organisationen verlinken, die unsere Forschung finanzieren.'; - out.policy_choices = 'Deine Möglichkeiten'; - out.policy_choices_open = 'Unser Code ist open source, deshalb kannst du jederzeit deine eigene Cryptpad-Instanz hosten.'; - out.policy_choices_vpn = 'Wenn du unsere gehostete Instanz nutzen möchtest bitten wir dich darum IP-Adresse zu verschleiern, das geht zum Beispiel mit dem Tor browser bundle, oder einem VPN-Zugang.'; - out.policy_choices_ads = 'Wenn du unsere Analysesoftware blockieren möchtest kannst du Adblock-Software wie Privacy Badger verwenden.'; + out.whatis_business_p1 = 'CryptPad\'s Zero Knowledge Verschlüsselung ohne Preisgabe der Daten ist ausgezeichnet, um die Effektivität von existierenden sicherheitsverfahren zu verbessern, indem die Zugangsberechtigungen des Unternehmens in der Kryptografie gespiegelt werden. Weil hochsensible Medien nur mit Angestelltenzugang entschlüsselt werden können, kann CryptPad das Jackpot der Hackers wegnehmen, was in der Natur von tradioneller IT liegt. Lese das CryptPad Whitepaper, um mehr zu erfahren, wie CryptPad Deinem Unternehmen helfen kann.'; + out.whatis_business_p2 = 'CryptPad kann auf eigenen Rechnern installiert werden. CryptPad\'s Entwickler von XWiki SAS können kommerzielle Unterstützung, Customisierung und Entwicklung anbieten. Bitte schicke eine Email an sales@cryptpad.fr, um mehr zu erfahren.'; + + // privacy.html + out.policy_title = 'Cryptpad Datenschutzbestimmungen'; + out.policy_whatweknow = 'Was wir über Dich wissen'; + out.policy_whatweknow_p1 = 'Als Programm, das im Web gehostet wird, hat Cryptpad Zugriff auf die Metadaten, die vom HTTP-Protokoll übertragen werden. Inbegriffen ist Deine IP-Adresse und diverse andere HTTP-Header, die es ermöglichen Deinen Browser zu identifizieren. Um zu sehen welche Daten Dein Browser preisgibt, kannst Du die Seite WhatIsMyBrowser.com besuchen.'; + out.policy_whatweknow_p2 = 'Wir nutzen Piwik, eine Open-Source Analyseplattform, um mehr über unsere Nutzer*innen zu erfahren. Piwik teilt uns mit, wie Du Cryptpad gefunden hast — durch direkten Zugriff, mit Hilfe einer Suchmaschine oder über einen Link auf einer anderen Seite wie z.B. Reddit oder Twitter. Außerdem lernen wir mehr über Deinen Besuch, welchen Link Du auf den Informationsseiten klickst und wie lange Du auf diesen Seiten verweilst.'; + out.policy_howweuse = 'Wie wir das Wissen anwenden'; + out.policy_howweuse_p1 = 'Wir nutzen diese Informationen um besser entscheiden zu können, wie Cryptpad beworben werden kann und um derzeit genutzte Strategien zu evaluieren. Informationen über Deinen Standort helfen uns, abzuschätzen welche Sprachen wir besser unterstützen sollten.'; + out.policy_howweuse_p2 = "Informationen zu Deinem Browser (ob Du auf einem Desktop oder Smartphone arbeitest) helfen uns außerdem dabei, zu entscheiden, welche Features priorisiert werden sollen. Unser Entwicklerteam ist klein, deshalb ist es uns wichtig, Entscheidungen derart zu treffen, dass möglichst viele Nutzer*innen davon profitieren."; + out.policy_whatwetell = 'Was wir anderen über Dich (nicht) erzählen'; + out.policy_whatwetell_p1 = 'Wir reichen keine von uns gesammelten Daten weiter, außer im Falle einer gerichtlichen Anordnung.'; + out.policy_links = 'Links zu anderen Seiten'; + out.policy_links_p1 = 'Diese Seite beinhaltet Links zu anderen Seiten, teilweise werden diese von anderen Organisationen verwaltet. Wir sind nicht für den Umgang mit der Privatsphäre und die Inhalte der anderen Seiten verantwortlich. Generell werden Links zu externen Seiten in einem neuem Fenster geöffnet, um zu verdeutlichen, dass Du Cryptpad.fr verlässt.'; + out.policy_ads = 'Werbung'; + out.policy_ads_p1 = 'Wir zeigen keine Onlinewerbung, können aber zu Organisationen verlinken, die unsere Forschung finanzieren.'; + out.policy_choices = 'Deine Möglichkeiten'; + out.policy_choices_open = 'Unser Code ist frei und offengelegt, deshalb kannst Du jederzeit Deine eigene Cryptpad-Instanz hosten.'; + out.policy_choices_vpn = 'Wenn Du unsere gehostete Instanz nutzen möchtest ohne Deine IP-Adresse zu offenbaren, bitten wir Dich darum, Deine IP-Adresse zu verschleiern, das geht zum Beispiel mit dem Tor browser bundle, oder einem VPN-Zugang.'; + out.policy_choices_ads = 'Wenn Du unsere Analysesoftware blockieren möchtest kannst Du Block-Software wie Privacy Badger verwenden.'; // features.html - out.features = "Funktionen"; out.features_title = "Tabelle der Funktionen"; out.features_feature = "Funktion"; @@ -750,7 +759,7 @@ out.features_f_pad = "Ein Dokument erstellen/bearbeiten/ansehen"; out.features_f_pad_notes = "Rich Text, Code, Präsentation, Umfrage und Whiteboard Apps"; out.features_f_history = "Verlauf"; - out.features_f_history_notes = "Jegliche Version deines Dokuments ansehen und zurückbringen"; + out.features_f_history_notes = "Jegliche Version Deines Dokuments ansehen und zurückbringen"; out.features_f_todo = "Eine ToDo-Liste erstellen"; out.features_f_drive = "CryptDrive"; out.features_f_drive_notes = "Einfache Funktionen für anonyme Benutzer"; @@ -761,7 +770,7 @@ out.features_f_embedFiles = "Dateien einbetten"; out.features_f_embedFiles_notes = "Eine Datei in ein Dokument einbetten, die im CryptDrive steht"; out.features_f_multiple = "Verwendung auf mehrere Geräte"; - out.features_f_multiple_notes = "Eine leichte Methode, deine Dokumente von jeglichem Gerät zu verwenden"; + out.features_f_multiple_notes = "Eine leichte Methode, Deine Dokumente von jeglichem Gerät zu verwenden"; out.features_f_logoutEverywhere = "Auf allen Geräten ausloggen"; out.features_f_logoutEverywhere_notes = ""; // Used in the French translation to explain out.features_f_templates = "Vorlagen verwenden"; @@ -769,180 +778,181 @@ out.features_f_profile = "Ein Profil erstellen"; out.features_f_profile_notes = "Persönliche Seite, mit ein Benutzerbild und eine Beschreibung"; out.features_f_tags = "Tags anwenden"; - out.features_f_tags_notes = "Erlaubt dich in CryptDrive anhand Tags zu suchen"; + out.features_f_tags_notes = "Erlaubt Dich in CryptDrive anhand Tags zu suchen"; out.features_f_contacts = "Kontakte App"; out.features_f_contacts_notes = "Kontakte hinzufügen und mit den in einer verschlüsselte Sitzung chatten"; out.features_f_storage = "Speicherplatz"; out.features_f_storage_anon = "Dokumente sind nach 3 Monate gelöscht"; out.features_f_storage_registered = "Frei: 50MB
          Premium: 5GB/20GB/50GB"; + out.features_f_register = "Kostenlose Anmeldung"; // faq.html - out.faq_link = "FAQ"; - out.faq_title = "Häufigste Fragen"; + out.faq_title = "Häufige Fragen"; out.faq_whatis = "Was ist CryptPad?"; out.faq = {}; out.faq.keywords = { title: 'Schlüsselkonzepte', pad: { q: "Was ist ein CryptPad Dokument?", - a: "Ein CryptPad Dokument ist manchmal als Pad genannt. Diese Bennung wurde von Etherpad bekannt gemacht, ein kollaboratives Editor in Echtzeit\n"+ - "Es beschreibt ein Dokument, das du in deinem Browser bearbeiten kannst, normalerweise mit der Möglichkeit für andere Personen, die Veränderungen nah zu direkt zu sehen." + a: "Ein CryptPad Dokument wird manchmal einfach Pad genannt, übernommen von Etherpad, einem kollaborativen Echtzeit-Editor\n"+ + "Es beschreibt ein Dokument, das Du in Deinem Browser bearbeiten kannst, normalerweise mit der Möglichkeit für andere Personen, die Veränderungen gleichzeiti direkt zu sehen." }, owned: { q: "What ist ein eigenes Dokument?", - a: "Ein eigenes Dokument ist ein Dokument mit einem definierten Eigentümer, der anhand ein einer Unterschrift mit öffentlichen Schlüssel erkannt wird." + - "Der Eigentümer eines Dokuments kann entscheiden, das Dokument zu löschen. In diesem Fall macht er das Dokument unverfügbar für weitere Kollaboration, egal ob das Dokument in deinem CryptDrive war oder nicht." + a: "Ein eigenes Dokument ist ein Dokument mit einem definierten Eigentümer, der anhand einer Unterschrift mit öffentlichen Schlüssel erkannt wird." + + "Der Eigentümer eines Dokuments kann entscheiden, das Dokument zu löschen. In diesem Fall macht er das Dokument unverfügbar für weitere Kollaboration, egal ob das Dokument in Deinem CryptDrive war oder nicht." }, expiring: { - q: "What is der Ablaufsdatum eines Dokuments?", + q: "Was ist das Ablaufsdatum eines Dokuments?", a: "Ein Dokument kann mit einem Ablaufsdatum versehen werden. Nach diesem Datum wird es automatisch vom Server gelöscht" + - " Das Ablaufdatum kann sowohl sehr nah (ein Paar Stunden) als sehr weit sein (hunterte Monate)." + - " Das Dokument und sein gesamter Verlauf wird dauerhaut unverfügbar werden, auch wenn er gerade noch bearbeitet wird.

          " + - " Wenn ein Dokument ein Ablaufsadtum hat, kann mann dieses Datum in der Eigenschaften lesen: Entweder mit einem Recht-klick in CryptDrive oder mit der Properties Ansicht, wenn das Dokument geöffnet ist." + " Das Ablaufdatum kann sowohl sehr nah (ein Paar Stunden) als sehr weit sein (hunderte Monate)." + + " Das Dokument und sein gesamter Verlauf wird nach dem Ablaufdatum dauerhauft unverfügbar, auch wenn es gerade noch bearbeitet wird.

          " + + " Wenn ein Dokument ein Ablaufsadtum hat, kann mann dieses Datum in den Eigenschaften sehen: Entweder mit einem Rechtklick in CryptDrive oder mit der Eigenschaften-Ansicht, wenn das Dokument geöffnet ist." }, tag: { q: "Wie kann ich Tags verwenden?", - a: "Du kannst Dokumente und CryptDrive-hochgeladene Dateien taggen. Das heisst mit einem Tag zu versehen. In Bearbeitung ist es durch das tag Knopf (" + - " Suche die Dokumente und Dateien in deinem CryptDrive mithilfe der Suchfunktion mit Suchterme, die mit einem Hashtag starten, zB #crypto." + a: "Du kannst Dokumente und auf CryptDrive hochgeladene Dateien taggen, das heisst mit einem Stichwort (Tag) versehen. Während der Bearbeitung gibt es dafür den Tag Knopf ()" + + " Wenn Du die Dokumente und Dateien in Deinem CryptDrive nach einem Tag durchsuchen willst, beginne den Suchbegriff mit einem Hashtag, zB #crypto." }, template: { q: "Was ist eine Vorlage?", - a: "Eine Vorlage ist ein Dokument, dass du benutzen kannst, um der Anfangsinhalt für zukünftige Dokumente zu definieren." + - " Jedes existes existierende Dokument kan eine Vorlage werden, indem es zum Vorlagen Abschnitt des CryptDrives geschoben wird." + - " Du kannst auch eine Kopie eines Dokuments erstellen, die ales Vorlage wird, indem du auf der Vorlagen Knop () des Toolbars des Editors druckst." + a: "Eine Vorlage ist ein Dokument, dass Du benutzen kannst, um den Anfangsinhalt für zukünftige Dokumente zu definieren." + + " Jedes existes existierende Dokument kann eine Vorlage werden, indem es in den Vorlagen Abschnitt des CryptDrives geschoben wird." + + " Du kannst auch eine Kopie eines Dokuments erstellen, die zur Vorlage wird, indem Du auf der Vorlagen-Knopf () der Werkzeugleiste des Editors drückst." }, }; out.faq.privacy = { title: 'Privacy', different: { - q: "Wie unterscheidet sich CryptPad von anderen online kollaborative Editoren?", - a: "CryptPad verschlüsselt Veränderungen deiner Dokumente, bevor diese Information zum Server geschickt wird. Somit können wir nicht lesen, was du getippt hast." + q: "Wie unterscheidet sich CryptPad von anderen online kollaborativen Editoren?", + a: "CryptPad verschlüsselt Veränderungen Deiner Dokumente, bevor diese Information zum Server geschickt wird. Somit können wir nicht lesen, was Du getippt hast." }, me: { - q: "Welche Information kennt der Server über mich?", + q: "Welche Informationen erhält der Server über mich?", a: "Die Administratoren des Servers können die IP-Adresse der Personen sehen, die CryptPad besuchen." + - " Wir speichern nicht welche Adresse besucht welches Dokument, aber wir konnten es tun, auch ohne Zugang zu den Inhalt des Dokuments zu kennen." + - " Wenn du besorgt bist, dass wir diese Information analysieren, ist es am sichersten davon auszugehen, dass wir es tun, da wir nicht beweisen können, dass wir es nicht tun.

          " + + " Wir speichern nicht, welche Adresse welches Dokument besucht, aber wir könnten es tun, aber immer nur ohne den Inhalt des Dokuments zu kennen." + + " Wenn Du besorgt bist, dass wir diese Information analysieren, ist es am sichersten davon auszugehen, dass wir es tun, da wir nicht beweisen können, dass wir es nicht tun.

          " + - " Wir sammeln elementare technische Informationen über wie CryptPad benutzt wird, wie die Grösse des Bildschirms auf der Gerät und welche Knöpfe werden meist geklickt." + - " Das hilft uns, unser Software besser zu machen. Aber du kannst die diese Sammlung für dich vermeiden, in dem du Rückmeldung aktivieren kein Haken setzt.

          " + + " Wir sammeln elementare technische Informationen darüber, wie CryptPad benutzt wird, wie die Grösse des Bildschirms auf dem Gerät und welche Knöpfe am meisten geklickt werden." + + " Das hilft uns, unsere Software besser zu machen. Aber diese Sammlung unterbleibt, solange Du bei Rückmeldung aktivieren keinen Haken setzt.

          " + - " Die Speicherungsgrössen und deren Grenzen sind mit dem öffentlichen Schlüssel eines Benutzers verbunden, aber wir verbinden nicht Namen oder Emailadressen mit dieser öffentlichen Schlüsseln.

          " + + " Die Speicherungsgrössen und deren Grenzen sind mit dem öffentlichen Schlüssel eines Benutzers verbunden, aber wir verbinden nicht Namen oder Emailadressen mit diesen öffentlichen Schlüsseln.

          " + - " Du kannst mehr Informationen darüber auf diesem Blogeintrag lesen." + " Du kannst mehr Informationen darüber in diesem Blogeintrag lesen." }, register: { q: "Weisst der Server mehr über mich, wenn ich registriere?", - a: "Wir verlangen nicht deine Emailadresse zu bestätigen und der Server kennt der Benutzername und Passwort nicht, wenn du dich regstriests. " + - " Anstatt dessen, der Registrierungs- und Anmeldeformular generiert ein Schlüsselpaar mit deiner Eingabe. Nur der öffentliche Schlüssel dieses Schlüsselpaars wird zum Server geschickt." + - " Mit diesem öffentlichen Schlüssel könenn wir Informationen kontrollieren wie die Menge der Daten, die du benutzt; damit können wir den Verbrauch von jedem Benutzer im Quota beschränken.

          " + + a: "Wir verlangen nicht Deine Emailadresse und der Server kennt Benutzername und Passwort auch dann nicht, wenn Du Dich registrierst. " + + " Statt dessen generiert das Registrierungs- und Anmeldeformular ein Schlüsselpaar mit Deiner Eingabe. Nur der öffentliche Schlüssel dieses Schlüsselpaars wird zum Server geschickt." + + " Mit diesem öffentlichen Schlüssel könenn wir z.B. die Menge der Daten, die Du benutzt, kontrollieren, denn jeder Benutzer hat eine beschränkte Quota.

          " + - " Wir benutzen die Rückmeldung Funktion, um den Server zu informieren, dass jemand mit deinem IP ein Konto registriert hat." + - " Damit können wir messen, wie viele Benutzer CryptPad Konten registrieren registrieren, und von welchen Regionen. Somit können wir wissen, welche Sprache braucht ein besseres Support.

          " + + " Wir benutzen die Rückmeldungs-Funktion, um den Server zu informieren, dass jemand mit Deiner IP ein Konto registriert hat." + + " Damit können wir messen, wie viele Benutzer CryptPad Konten registrieren, und aus welchen Regionen. Somit können wir erfahren, welche Sprache besseren Support braucht.

          " + - " Wenn du registrierst, du erstellest einen öffentlichen Schlüssel, das benutzt wird, um den Server zu informieren, dass die Dokumente nicht löschen sollte, wenn sie nicht aktiv benutzt werden." + - " Diese Information zeigt mehr zum Server, über wie du CryptPad benutzt, aber das System erlaubt uns, die Dokumente zu löschen, wofür keine sich die Mühe gegeben hat, was zu tun, um sie zu behalten." + " Wenn Du registrierst, erstellst Du einen öffentlichen Schlüssel, der benutzt wird, um den Server zu informieren, dass er Dokumente auch dann nicht löschen sollte, wenn sie nicht aktiv benutzt werden." + + " Diese Information zeigt dem Server, wie Du CryptPad benutzt, und dieses System erlaubt uns, die Dokumente zu löschen, wofür sich keiner mehr interessiert." }, other: { q: "Was können andere Benutzer über micht erfahren?", - a: "Wenn die ein Dokument jemanden anderen bearbeitest, du kommunizierst mit dem Server. Nur wir kennen deine IP-Adresse. " + - " Andere Benutzern können dein Benutzername, dein Benutzerbild, das Link deines Profils (wenn du ein hast), und deinen öffentlichen Schlüssel (um die Nachrichten zu den Benutzern zu verschlüsseln)." + a: "Wenn Du ein Dokument von jemand anderen bearbeitest, kommunizierst Du mit dem Server. Nur wir kennen Deine IP-Adresse. " + + " Andere Benutzern sehen Deinen Benutzernamen, Dein Benutzerbild, das Link Deines Profils (wenn Du eins hast), und Deinen öffentlichen Schlüssel (um die Nachrichten zu diesen Benutzern zu verschlüsseln)." }, anonymous: { q: "Macht mich CryptPad anonym?", - a: "Auch wenn CryptPad so konzipiert wurde, dass es so wenig wie möglich über dicht kenn, es liefert keine strenge Anonymität" + - " Unsere Servers haben einen Zugang zu deiner IP-Adresse, allerdings kannst du diese Information verbergen, indem du Tor verwendets." + - " Einfach Tor zu verwenden, ohne dein Verhältnis zu ändern, garnatiert auch nicht deine Anonymität, da der Server Benutzern noch mit deren einzige öffentlichen Schlüsseln identifizeren kann." + - " Wenn du denselben Schlüssel benutzt, wenn du nicht Tor benutzt. Es wird möglich, deine Sitzung zu de-anonimisieren.

          " + + a: "Auch wenn CryptPad so konzipiert wurde, dass es so wenig wie möglich über Dich kennt, es liefert keine strenge Anonymität" + + " Unsere Server haben einen Zugang zu Deiner IP-Adresse, allerdings kannst Du diese Information verbergen, indem Du Tor verwendest." + + " Einfach Tor zu verwenden, ohne Dein Verhalten zu ändern, garantiert auch keine Anonymität, da der Server Benutzer noch mit deren öffentlichen Schlüsseln identifizeren kann." + + " Wenn Du denselben Schlüssel mit und ohne Tor benutzt, wird es möglich, Deine Sitzung zu de-anonimisieren.

          " + - " Für Benutzer die einen niedrigeren Grad Datenschutz brauchen, CryptPad, im Gegenteil zu anderen Onlinservers, verlangt sein Benutzer nicht, sich mit Namen, Telefonnummer oder Emailadressen zu identifizieren." + " Für Benutzer, die Datenschutz im normalen Umfang brauchen, ist wichtig, daß CryptPad, im Gegenteil zu anderen Onlinediensten, nicht verlangt, daß der Benutzer sich mit Namen, Telefonnummer oder Emailadressen identifiziert." }, policy: { q: "Habt ihr eine Datenschutzerklärung?", - a: "Ja! Es ist hier verfügbar." + a: "Ja! Sie ist hier verfügbar." } }; out.faq.security = { title: 'Sicherheit', proof: { q: "Wie benutzt ihr Zero Knowledge Beweise?", - a: "Wir benutzen das Term Ohne Preisgabe von Informationen (Zero knowledge) nicht im Sinn eines Zero knowledge Beweis aber im Sinn eines Zero Knowledge Webdienst " + - " Zero Knowledge Webdienst verschlüsseln die Benutzerdaten im Browser, ohne dass der Server je Zugang zu den unverschlüsselten Daten oder zu dem Verschlüsselungschlüsseln hat.

          " + - " Wir haben eine kurze Liste von Zero-Knowledge Webdienste hier gesammelt." + a: "Wir benutzen den Begriff Zero Knowledge (Ohne Preisgabe von Daten) nicht im Sinn eines Zero Knowledge Beweises aber im Sinn eines Zero Knowledge Webdienstes " + + " Ein Zero Knowledge Webdienst verschlüsselt die Benutzerdaten im Browser, ohne dass der Server je Zugang zu den unverschlüsselten Daten oder zu den Verschlüsselungschlüsseln hat.

          " + + " Wir haben hier eine kurze Liste von Zero-Knowledge Webdiensten erstellt." }, why: { - q: "Wieso soll ich CryptPad verwenden?", - a: "Unsere Position ist, dass Clouddienst nicht Zugang zu deinen Daten verlangen sollten, damit du sie zu deinen Kontakten und Mitarbeitern teilen kannst. " + - " Wenn du ein Webdienst benutzt, der nicht explizit eine Ankündigung macht, dass die keinen Zugang zu deinen Information haben, ist es sehr wahrscheinlich, dass sie diese Information für andere Zwecke verwerten." + q: "Wieso sollte ich CryptPad verwenden?", + a: "Unsere Position ist, dass Clouddienste nicht Zugang zu Deinen Daten verlangen sollten, damit Du sie mit Deinen Kontakten und Mitarbeitern teilen kannst. " + + " Wenn Du einen Webdienst benutzt, der nicht explizit eine Ankündigung macht, dass die keinen Zugang zu Deinen Information haben, ist es sehr wahrscheinlich, dass sie diese Information für andere Zwecke verwerten." }, compromised: { - q: "Liefert mich CryptPad einen Schutz, wenn mein Gerät zugegriffen wird?", - a: "Im Fall, dass dein Gerät gestolen wird, erlaubt CryptPad ein Knopf zu drucken, damit alle Geräte, ausser das wo du gerade geloggt bist, ausgeloggt wird. " + - " Alle andere Geräten, die mit diesem Konto verbunden sind, werden auch ausgeloggt. " + - " Alle früher verbundene Geräte, werden ausgeloggt, sobald sie CryptPad besuchen.

          " + - - " Die Fernlogout Funktion, wie oben beschrieben, ist im Browser implementiert und nicht im Server. " + - " Somit schützt diese nicht von Regierungsagenturen. Aber es sollte ausreichend sein, wenn du ein Logout vergessen hast, wenn du auf einem geteiltes Rechner warst." + q: "Liefert mir CryptPad einen Schutz, wenn auf mein Gerät zugegriffen wird?", + a: "Für den Fall, dass ein Gerät gestohlen wird, ermöglicht CryptPad, das Ausloggen aller Geräte - ausser dem, wo Du gerade eingeloggt bist, zu erzwingen. " + + " Dafür gehe auf die Seite mit Deinen Einstellungen and drücke Überall ausloggen." + + " Alle andere Geräte, die mit diesem Konto verbunden sind, werden dann ausgeloggt. " + + " Alle früher verbundenen Geräte werden ausgeloggt, sobald sie CryptPad besuchen.

          " + + + " Die Fernlogout Funktion, wie oben beschrieben, ist im Browser implementiert und nicht im Server. " + + " Somit schützt diese nicht von Regierungsagenturen. Aber es sollte ausreichend sein, wenn Du ein Logout vergessen hast, wenn Du auf einem mit anderen Benutzern geteilten Rechner warst." }, crypto: { q: "Welche Kryptografie benutzt ihr?", - a: "CryptPad basiert auf zwei open-source Kryptografiebibliotheken: " + + a: "CryptPad basiert auf zwei quelloffenen Kryptografiebibliotheken: " + " tweetnacl.js und scrypt-async.js.

          " + - " Scrypt ist ein Passwort-basiert Schlüsselableitungsalgorithmus. Wir benutzen es, um dein Benutzername und Kennwort in einem Schlüsselpaar umzuwandeln, das deinen Zugang zum CryptDrive, und daher deine gesamte Dokumente, sichert.

          " + + " Scrypt ist ein Passwort-basierter Schlüsselableitungsalgorithmus. Wir benutzen es, um Deinen Benutzernamen und Kennwort in einem Schlüsselpaar umzuwandeln, das Deinen Zugang zum CryptDrive, und daher Deine gesamten Dokumente, sichert.

          " + - " Wir verwenden die Verschlüsselung xsalsa20-poly1305 und x25519-xsalsa20-poly1305 von tweetnacl, um, bzw, Dokumente und Chat-Historie zu verschlüsseln." + " Wir verwenden die Verschlüsselung xsalsa20-poly1305 und x25519-xsalsa20-poly1305 von tweetnacl, um Dokumente und Chat-Historie zu verschlüsseln." } }; out.faq.usability = { title: 'Usability', register: { q: "Was kriege ich, wenn ich registriere?", - a: "Registrierte Benutzer können eine Menge Funktionen verwenden, die unregistrierten nicht verwenden können. Es gibt eine Tabelle hier." + a: "Registrierte Benutzer können eine Menge Funktionen verwenden, die unregistrierte nicht nutzen können. Es gibt hier eine Tabelle." }, share: { - q: "Wie kann ich Zugang zu einem verschlüsselten Dokument mit Freunden teilen?", - a: "CryptPad macht den Verschlüsselungsschlüssel zu deinem Pad nach dem # Buchstabe in dem URL." + - " Alles was nach diesem Buchstabe kommt, ist nicht zum Server geschickt; also haben wir nie Zugang zu deinem Verschlüsselungsschlüssel." + - " Wenn du das Link deines Dokuments teilst, teilst du auch die Fähigkeit zum Lesen und zum Bearbeiten." + q: "Wie kann ich den Zugang zu einem verschlüsselten Dokument mit Freunden teilen?", + a: "CryptPad legt den Verschlüsselungsschlüssel zu Deinem Pad nach dem # Buchstabe in dem URL." + + " Alles was nach diesem Buchstaben kommt, wird nicht zum Server geschickt; also haben wir nie Zugang zu Deinem Verschlüsselungsschlüssel." + + " Wenn Du den Link Deines Dokuments teilst, teilst Du auch die Fähigkeit zum Lesen und zum Bearbeiten." }, remove: { - q: "Ich habe ein Dokument aus meinem CryptDrive gelöst, aber den Inhalt ist noch verfügbar. Wie kann ich es entfernen?", - a: "Nur eigene Dokumente, die erst in Februar 2018 eingeführt wurden, können gelöscht werden. Dazu können diese Dokument nur von deren Eigentümer gelöscht werden" + - " (der Benutzer, der das Dokument original gestaltet hat). Wenn du nicht der Eigentümer eines Dokuments bist, musst du noch den Eigentümer bitten, dass er dieses löscht." + - " Für ein Dokument, wovon du den Eigentümer bist, kannst du auf dem Dokument in CryptDrive rechtsklicken und Vom Server löschen wählen. " + q: "Ich habe ein Dokument aus meinem CryptDrive gelöscht, aber der Inhalt ist noch verfügbar. Wie kann ich es entfernen?", + a: "Nur eigene Dokumente, die erst in Februar 2018 eingeführt wurden, können gelöscht werden und zwar nur von deren Eigentümer" + + " (der Benutzer, der das Dokument original gestaltet hat). Wenn Du nicht der Eigentümer eines Dokuments bist, musst Du den Eigentümer bitten, dass er dieses löscht." + + " Für ein Dokument, dessen Eigentümer Du bist, kannst Du auf dem Dokument in CryptDrive rechtsklicken und Vom Server löschen wählen. " }, forget: { q: "Was passiert, wenn ich mein Passwort vergesse?", - a: " Leider: Wenn wir dein Passwort zurückerstellen könnten, könnten wir auch Zugang zu deinen Daten selber haben. " + - " Wenn du dein Passwort nicht registriert hast, und kann es auch nicht erinnern, kannst du vielleicht die vergangene Dokumente von deinem Browserverlauf zurück gewinnen. " + a: " Leider: Wenn wir Dein Passwort zurückerstellen könnten, könnten wir auch Zugang zu Deinen Daten selber haben. " + + " Wenn Du Dein Passwort nicht aufgeschrieben und vergessen hast, kannst Du vielleicht die vergangenen Dokumente aus Deinem Browserverlauf zurückgewinnen. " }, change: { q: "Was ist, wenn ich mein Passwort wechseln möchte?", - a: "Es ist aktuell nicht möglich, dein CryptPad Passwort zu wechseln, obwohl wir diese Funktion bald planen." + a: "Es ist aktuell nicht möglich, Dein CryptPad Passwort zu wechseln, obwohl wir diese Funktion bald planen." }, devices: { - q: "Ich bin auf zwei Geräte eingeloggt und sehe zwei unterschiedliche CryptDrives. Wie ist das möglich?", - a: "Es ist möglich, dass du zweimal derselben Name registriert hast, mit unterschiedlichen Passwörter." + - " Weil der CyrptPad Server dicht mit deinem kryptografische Unterschrift identifiziert, es kann nicht dich verhindern, mit demselben Name einzuloggen." + - " Somit hat jede Benutzerkonto ein einzigartiges Beutzername und Passwortkombination. " + - " Angemeldete Benutzer können ihre Benutzername im oberen Teil der Einstellungsseite sehen." + q: "Ich bin auf zwei Geräten eingeloggt und sehe zwei unterschiedliche CryptDrives. Wie ist das möglich?", + a: "Es ist möglich, dass Du zweimal denselben Namen registriert hast, mit unterschiedlichen Passwörtern." + + " Weil der CyrptPad Server Dich mit Deiner kryptografischen Unterschrift und nicht mit Deinem Namen identifiziert, kann er nicht verhindern, daß derselbe Name von mehreren verwendet wird." + + " Somit hat jede Benutzerkonto eine einzigartige Beutzername- und Passwortkombination. " + + " Angemeldete Benutzer können ihren Benutzernamen im oberen Teil der Einstellungsseite sehen." }, folder: { - q: "Kann ich meine ganze Ordnern in CryptDrive teilen?", - a: "Wir arbeiten daran, eine Arbeitgruppenfunktion anzubieten, die Mitglieder erlauben würde, ganze Ordnern sowie alle Dokumente darin, zu teilen." + q: "Kann ich ganze Ordner in CryptDrive teilen?", + a: "Wir arbeiten daran, eine Arbeitgruppenfunktion anzubieten, die Mitgliedern erlauben würde, ganze Ordnern sowie alle Dokumente darin zu teilen." }, feature: { - q: "Könnt ihr diese Funktion hinzufügen, das ich brauche?", - a: "Viele Funktionen existieren in CryptPad, weil Benutzern haben dafür gebeten." + - " Unsere Kontaktseite gibt eine Liste de Methoden, um mit uns in Kontakt zu treten.

          " + + q: "Könnt ihr diese eine Funktion hinzufügen, die ich brauche?", + a: "Viele Funktionen existieren in CryptPad, weil Benutzern darum gebeten haben." + + " Unsere Kontaktseite hat eine Liste der Möglichkeiten, wie man mit uns in Kontakt treten kann.

          " + - "Leider können wir aber nicht garantieren, dass wir alle Funktionen entwickeln, die Benutzern bitten." + - " Wenn eine Funktion kritisch für ihre Organisation ist, kannst du Sponsor der Entwicklung dieser Funktion werden, und somit deren Realisierung sichern." + + "Leider können wir aber nicht garantieren, dass wir alle Funktionen entwickeln, um die Benutzer bitten." + + " Wenn eine Funktion kritisch für Deine Organisation ist, kannst Du Sponsor der Entwicklung dieser Funktion werden, und somit deren Realisierung sichern." + " Bitte kontaktiere sales@cryptpad.fr für mehr Informationen.

          " + - "Auch wenn du nicht die Entwicklung einer Funktion sponsorieren kannst, sind wir zu Rückmeldungen interessiert, damit es uns hilft CryptPad zu verbessern." + - " Du bist willkommen, mit uns in Kontakt zu treten, mit eine der Methoden oben." + "Auch wenn Du nicht die Entwicklung einer Funktion sponsorn kannst, sind wir an Rückmeldungen interessiert, damit es uns hilft CryptPad zu verbessern." + + " Kontaktiere uns jederzeit mit einer der oben angegebenen Methoden." } }; @@ -950,206 +960,224 @@ title: "Andere Fragen?", pay: { q: "Wieso soll ich zahlen, wenn so viele Funktionen sowieso kostenfrei sind?", - a: "Wir geben Sponsoren zusätzliche Speicherplatzmöglichkeiten sowie die Möglichkeit, die Speicherplatzgrenzen ihrer Freunde zu erhören (lese mehr).

          " + + a: "Wir geben Sponsoren zusätzlichen Speicherplatz sowie die Möglichkeit, die Speicherplatzgrenzen ihrer Freunde zu erhöhen (lese mehr).

          " + - " Weiter als diese kurzfristige Vorteile kannst du, wenn du ein Premiumangebot annimmst, die aktive Weiterentwicklung von CryptPad. Dieses beinhaltet Bugs reparieren, neue Funktionen gestalten, und es leichter für andere zu machen, dass sie CryptPad auf eigenen Servers installieren." + - " Zusätzlich hilfst du das den Anderen zu beweisen, dass Leute datenschutzschonende Technologien verbessern wollen. Wir hoffen, dass am Ende Geschäftmodelle ein Aspekt der vergangene Geschichte ist.

          " + + " Über diese diese kurzfristigen Vorteile hinaus kannst Du, wenn Du ein Premiumangebot annimmst, die aktive Weiterentwicklung von CryptPad fördern. Dieses beinhaltet Fehler zu beseitigen, neue Funktionen zu gestalten, und es erleichtern, CryptPad auf eigenen Servern zu installieren." + + " Zusätzlich hilfst Du, anderen Anbiertern zu beweisen, dass Leute datenschutzschonende Technologien unterstützen. Wir hoffen, dass am Ende Geschäftmodelle, die auf dem Verkauf von Benutzerdaten basieren, Vergangenheit werden.

          " + - " Am Ende glauben wir, dass es gut ist, die Funktionen von CryptPad kostenfrei anzubieten, weil jeder persönlichen Datenschutz braucht, nicht nur diejenige mit Extraeinkommen." + - " Durch ihre Unterstützung hilfst du uns, zu ermöglichen, dass Bevölkerung mit weniger Einkommen diese grundlegende Funktionen geniessen können, ohne dass ein Preisetikette daran klebt." + " Außerdem glauben wir, dass es gut ist, die Funktionen von CryptPad kostenfrei anzubieten, weil jeder persönlichen Datenschutz braucht, nicht nur diejenige mit Extraeinkommen." + + " Durch Deine Unterstützung hilfst Du uns, zu ermöglichen, dass auch Menschen mit weniger Einkommen diese grundlegenden Funktionen geniessen können, ohne dass ein Preisetikett daran klebt." }, goal: { - q: "Was ist ihr Ziel?", - a: "Durch die Verbesserung von Datenschutzschonende Technologie möchten wir die Erwartungen der Benutzern erhöhen, was der Datenschutz auf Cloudplattformen angeht." + - "Wir hoffen, dass unsere Arbeit andere Dienstanbietern in allen Domänen ähnliche oder bessere Dienste anbieten können. " + - "Trotz unser Optimismu wissen wir, dass vieles vom Web aus gezielte Werbung gesponsert wird. " + - "Es gibt viel mehr Arbeit in der Richtung zu tun, als wir selber schaffen, und wir erkennen die Unterstützung der Gemeinschaft für Promotion, Support und andere Beiträge für dieses Zweck." + q: "Was ist Euer Ziel?", + a: "Durch die Verbesserung von datenschutzschonenden Technologien möchten wir die Erwartungen der Benutzer an den Datenschutz auf Cloudplattformen erhöhen." + + "Wir hoffen, dass unsere Arbeit andere Dienstanbieter in allen Bereichen anspornt, ähnliche oder bessere Dienste anzubieten. " + + "Trotz unser Optimismus wissen wir, dass ein grosser Teil des Netztes durch gezielte Werbung finanziert wird. " + + "Es gibt viel mehr Arbeit in der Richtung, als wir jemals schaffen können, und wir freuen uns über die Förderung, Unterstützung und Beiträge aus unserer Community." }, jobs: { - q: "Stellt ihr an?", - a: "Ja! Bitte schicke eine kurze Einführung zu dir auf jobs@xwiki.com." + q: "Sucht Ihr Mitarbeiter*innen?", + a: "Ja! Bitte schicke eine kurze Vorstellung an jobs@xwiki.com." }, host: { - q: "Könnt ihr mich helfen, meine eigene Installation von CryptPad zu erledigen?", - a: "Wir sind froh, dich zu unterstützen, das interne CryptPad deiner Firma zu installieren. Setze dich bitte mit sales@cryptpad.fr in Kontakt für mehr Information.", + q: "Könnt ihr mir helfen, meine eigene Installation von CryptPad aufzubauen?", + a: "Wir bieten gerne Support für das Aufsetzen eines internen CryptPads für Deine Organisation. Setze Dich bitte mit sales@cryptpad.fr in Kontakt für mehr Information.", }, revenue: { - q: "Wie kann ich ein geteilttes Einkommen Modell erreichen?", - a: " Wenn du deine eigene Installation von CrytPad betreibst, und du möchtests die Einkommen für deine bezahlte Konten mit Entwicklern teilen, wird dein Server als Partnerservice konfugriert werden müssen.

          " + + q: "Wie kann ich meine Einnahmen mit den Entwicklern teilen?", + a: " Wenn Du Deine eigene Installation von CrytPad betreibst und die Einnahmen für Deine bezahlten Konten mit Entwicklern teilen möchtest, muß Dein Server als Partnerservice konfiguriert werden.

          " + - "In deinem CryptPad Verzeichnis befinden sich config.example.js, die eine Erklärung liefert, wie du dein Server dafür konfigurieren muss. "+ - "Danakch solltest du sales@cryptpad.fr ein Email schicken, damit es geprüft wird, dass dein Server richtig mit HTTPS konfiguriert wird und damit die Bezahlungsmethoden diskutiert werden. " + "In Deinem CryptPad Verzeichnis befindet sich config.example.js, die erklärt, wie Du Deinen Server dafür konfigurieren musst. "+ + "Danach solltest Du sales@cryptpad.fr kontaktieren, damit geprüft wird, dass Dein Server richtig mit HTTPS konfiguriert ist und die Bezahlungsmethoden abgesprochen werden können. " }, }; - - - - // terms.html - - out.tos_title = "Cryptpad Nutzungsbedingungen"; - out.tos_legal = "Sei nicht bösartig, missbrauchend und mach nichts illegales."; - out.tos_availability = "Wir hoffen, dass dir dieser Service nützt, aber Erreichbarkeit und Performanz können nicht garantiert werden. Bitte exportiere deine Daten regelmäßig."; - out.tos_e2ee = "Cryptpad Dokumente können von allen gelesen oder bearbeitet werden, die den \"fragment identifier\" des Dokuments erraten oder auf eine andere Art davon erfahren. Wir empfehlen dir Ende-Zu-Ende verschlüsselte Nachrichtentechnik (e2ee) zum Versenden der URLs zu nutzen. Wir übernehmen keine Haftung falls eine URL erschlichen oder abgegriffen wird."; - out.tos_logs = "Metadaten, die dein Browser bereitstellt, können geloggt werden, um den Service aufrechtzuerahlten."; - out.tos_3rdparties = "Wir geben keine Individualdaten an dritte Weiter, außer auf richterliche Anordnung."; + + // terms.html 995 + out.tos_title = "Cryptpad Nutzungsbedingungen"; + out.tos_legal = "Sei nicht bösartig oder missbrauchend und mach nichts illegales."; + out.tos_availability = "Wir hoffen, dass Dir dieser Service nützt, aber Erreichbarkeit und Performanz können nicht garantiert werden. Bitte exportiere Deine Daten regelmäßig."; + out.tos_e2ee = "Cryptpad Dokumente können von allen gelesen oder bearbeitet werden, die den \"fragment identifier\" des Dokuments erraten oder auf eine andere Art davon erfahren. Wir empfehlen Dir Ende-Zu-Ende verschlüsselte Nachrichtentechnik (e2ee) zum Versenden der URLs zu nutzen. Wir übernehmen keine Haftung, falls eine URL erschlichen oder abgegriffen wird."; + out.tos_logs = "Metadaten, die Dein Browser übermittelt, können geloggt werden, um den Service aufrechtzuerhalten."; + out.tos_3rdparties = "Wir geben keine Individualdaten an Dritte Weiter, außer auf richterliche Anordnung."; // 404 page - out.four04_pageNotFound = "Wir konnten nicht die Seite finden, die du angefordert hast."; + out.four04_pageNotFound = "Wir konnten die Seite, die Du angefordert hast, nicht finden."; // BottomBar.html - // out.bottom_france = 'Mit in gemacht'; // out.bottom_support = 'Ein XWiki SAS Labs Project mit Hilfe von OpenPaaS-ng'; - // Header.html - - out.updated_0_header_logoTitle = 'Zu deinem CryptDrive'; + // Header.html + out.updated_0_header_logoTitle = 'Zu Deinem CryptDrive'; out.header_logoTitle = out.updated_0_header_logoTitle; out.header_homeTitle = 'Zu der CryptPad Homeseite'; // Initial states - out.help = {}; - out.help.title = "Mit CryptPad anfängen"; + out.help.title = "Mit CryptPad anfangen"; out.help.generic = { - more: 'Erfahre mehr wie CryptPad für dich arbeiten kann, indem du unsere FAQ liest.', - share: 'Benutze das Teilen Menü (), um Links zu schicken, die zu Kooperationen im Lesen oder Bearbeiten einladen.', - stored: 'Jedes Dokument, dass du besuchst, ist automatisch in deinem CryptDrive gespeichert.', + more: 'Erfahre mehr wie CryptPad für Dich arbeiten kann, indem Du unsere FAQ liest.', + share: 'Benutze das Teilen-Menü (), um Links zu schicken, die zur Mitarbeit beim Lesen oder Bearbeiten einladen.', + stored: 'Jedes Dokument, dass Du besuchst, ist automatisch in Deinem CryptDrive gespeichert.', }; out.help.text = { - formatting: 'Du kannst das Toolbar anzeigen oder verbergen indem du auf oder klickst.', - embed: 'Registrierte Benutzern können mit Bilder oder Dateien einbetten, die in deren CryptDrive gespeichert sind.', + formatting: 'Du kannst die Werkzeugleiste anzeigen oder verbergen indem Du auf oder klickst.', + embed: 'Registrierte Benutzer können mit Bilder oder Dateien einbetten, die in deren CryptDrive gespeichert sind.', history: 'Du kannst das Menü Verlauf benutzen, um frühere Version anzusehen oder zurückbringen.', }; out.help.pad = { - export: 'Du kannst export als PDF benutzen, indem du auf dem Knopf in dem Formattierungstoolbar druckst.', + export: 'Du kannst den Export als PDF benutzen, indem Du auf dem Knopf in dem Formatierungs-Werkzeugleiste drückst.', }; out.help.code = { - modes: 'Benutze das Dropdown Menü im Submenü , um die Syntaxherhorhebung oder das Farbschema zu wechseln.', + modes: 'Benutze das Dropdown Menü im Untermenü , um die Syntaxhervorhebung oder das Farbschema zu wechseln.', }; out.help.slide = { markdown: 'Schreibe Folien in Markdown and separiere sie mit der Zeile ---.', - present: 'Starte die Präsentation mit dem Knopf .', - settings: 'Verändere die Präsentationseinstellung (Hintergrund, Transition, Anzeige der Seitenummer, etc) mit dem Knopf in dem Submenü .', + present: 'Starte die Präsentation mit dem Knopf .', + settings: 'Verändere die Präsentationseinstellungen (Hintergrund, Transition, Anzeige der Seitenummer, etc) mit dem Knopf in dem Submenü .', colors: 'Verändere Text- und Hintergrundfarbe mit den Knöpfen und .', }; out.help.poll = { - decisions: 'Treffen Entscheidung privat, unter Bekannte', - options: 'Schlage zuätzliche Optionen, und mache deine bevorzugte Optionen laut', - choices: 'Klicke Zellen in deiner Spalte, um zwischen ja (), viellecht (~), oder nein () zu wählen', - submit: 'Klicke auf schicken, damit deine Wahlen anderen Sichtbar wird', + decisions: 'Treffe Entscheidungen gemeinsam mit Deinen Bekannten', + options: 'Mache Vorschläge und teile Deine Präferenzen mit', + choices: 'Klicke die Zellen in Deiner Spalte, um zwischen ja (), viellecht (~), oder nein () zu wählen', + submit: 'Klicke auf Schicken, damit Deine Entscheidung für andere sichtbar wird', }; out.help.whiteboard = { - colors: 'Ein Doppelklick auf Farben erlaubt die Palette zu verändern', - mode: 'Deaktiviere das Zeichenmodus, um die Strichen zu ziehen und verlängern', - embed: 'Einbette Bilder von deiner Festplatte oder von deinem CryptDrive und exportiere sie als PNG zu deiner Festplatte oder zu deinem CryptDrive oder von Deinem CryptDrive und exportiere sie als PNG zu Deiner Festplatte oder zu Deinem CryptDrive Knopf in der rechten oberen Ecke', + task: 'Verschiebe Items von einem Bord zum anderen durch Ziehen und Ablegen', + color: 'Ändere die Farben durch Klicken auf den farbigen Teil neben dem Bordtitel', + }; out.initialState = [ '

          ', - 'Hier ist is CryptPad, das Echtzeit kollaboratives Editor ohne Preisgabe deiner Informationen. Alles wird beim Tippen direkt gespeichert.', + 'Dies ist is CryptPad, der Zero Knowledge Echtzeit-Kollaborativ-Editor ohne Preisgabe Deiner Daten. Alles wird beim Tippen direkt gespeichert.', '
          ', - 'Teile das Link zu diesem, um mit Bekannten zu kooperieren, oder verwende den Knopf , um ein schreibgeschütztes Link  zu teilen. Es erlaubt der Ansicht ohne die Bearbeitung.', + 'Teile den Link zu diesem Pad, um mit Bekannten zusammen zu arbeiten, oder verwende den Knopf , um einen schreibgeschützten Link  zu teilen, der die Ansicht, aber nicht die Bearbeitung erlaubt.', '

          ', ].join(''); out.codeInitialState = [ - '# CryptPad: Kollaboratives Code Editor ohne Preisgabe deiner Information\n', + '# CryptPad\'s Zero Knowledge Kollaborativer Code Editor ohne Preisgabe Deiner Daten\n', '\n', - '* Was du hier tippst, ist Verschlüsselt. Nur Personen die das vollen Link haben können es zugreifen.\n', + '* Was Du hier tippst, ist verschlüsselt. Nur Personen, die den vollen Link haben, können darauf zugreifen.\n', '* Du kannst die Programmierungsprache für die Syntaxhervorhebung sowie das Farbschema oben rechts wählen.' ].join(''); out.slideInitialState = [ '# CryptSlide\n', - '1. SChreibe deine Präsentation mit der Markdown Syntax\n', - ' - Mehr über Markdwon [hier](http://www.markdowntutorial.com/) erfahren\n', - '2. Trenne deine Folien mit ---\n', - '3. Klicke auf dem "Abspielen" Knopf, um das Ergebnis zu sehen.', - ' - Deine Folien sind in Echtzeit aktualisiert' + '1. SChreibe Deine Präsentation mit der Markdown Syntax\n', + ' - Mehr über Markdown [hier](http://www.markdowntutorial.com/) erfahren\n', + '2. Trenne Deine Folien mit ---\n', + '3. Klicke auf den "Abspielen" Knopf, um das Ergebnis zu sehen.', + ' - Deine Folien werden in Echtzeit aktualisiert' ].join(''); // Readme - out.driveReadmeTitle = "Was ist CryptPad?"; out.readme_welcome = "Willkommen zu CryptPad !"; - out.readme_p1 = "Willkommen zu CryptPad, hier kannst du deine Notizzen runterschreiben, allein oder mit Bekannten."; - out.readme_p2 = "Dieses Dokument gibt dir einen kurzen Durchblick, wie du CryptPad verwenden kann, um Notizzen zu schreiben und zusammen zu arbeiten."; - out.readme_cat1 = "Kenne CryptDrive lernen"; - out.readme_cat1_l1 = "Ein Dokument erstellen: In deinem CryptDrive, klicke {0} dann {1} und kannst ein ein Dokuemnt erstellen."; // 0: New, 1: Rich Text - out.readme_cat1_l2 = "Ein Dokument deines CryptDrives öffnen: Doppelklick auf der Ikone eines Dokument, um es zu öffnen."; - out.readme_cat1_l3 = "Deine Dokumente organisieren: Wenn du eingeloggst bist, wird jedes Dokument, das du beuuchst in {0} Abschnitt deines CryptDrive"; - out.readme_cat1_l3_l1 = "Du kannst Dateien zwischen Ordnern Ziehen und Schieben in dem Abschnitt {0} deines CryptDrives oder neue Ordnern gestalten."; // 0: Documents - out.readme_cat1_l3_l2 = "Erinnere dich daran, ein Rechtklick auf Ikonen zu geben, da es zusätzlichen Menüfunktionen gibt."; - out.readme_cat1_l4 = "Verschiebe deine alte Dokumente zum Papierkorb: Du kannst deine Dokumente zu {0} verschieben, genauso, wie du es zu einem Ordner machst."; // 0: Trash + out.readme_p1 = "Willkommen zu CryptPad, hier kannst Du Deine Notizen aufschreiben, allein oder mit Bekannten."; + out.readme_p2 = "Dieses Dokument gibt Dir einen kurzen Überblick, wie Du CryptPad verwenden kann, um Notizen zu schreiben und und mit anderen zusammen zu arbeiten."; + out.readme_cat1 = "Lerne CryptDrive kennen"; + out.readme_cat1_l1 = "Ein Dokument erstellen: Klicke in Deinem CryptDrive {0}, dann {1} und Du kannst ein Dokuemnt erstellen."; // 0: New, 1: Rich Text + out.readme_cat1_l2 = "Ein Dokument Deines CryptDrives öffnen: Doppelklicke auf das Symbol eines Dokument, um es zu öffnen."; + out.readme_cat1_l3 = "Deine Dokumente organisieren: Wenn Du eingeloggst bist, wird jedes Dokument, das Du besuchst, im {0} Bereich Deines CryptDrives angezeigt"; + out.readme_cat1_l3_l1 = "Im Abschnitt {0} Deines CryptDrives kannst Du Dateien zwischen Ordnern ziehen und ablegen oder neue Ordner anlegen."; // 0: Documents + out.readme_cat1_l3_l2 = "Ein Rechtklick auf Symbole kann zusätzliche Menüfunktionen anbieten."; + out.readme_cat1_l4 = "Verschiebe Deine alten Dokumente in den Papierkorb: Du kannst Deine Dokumente zu {0} verschieben, genauso, wie Du es zu einem Ordner machst."; // 0: Trash out.readme_cat2 = "Dokumente wie ein Profi gestalten"; out.edit = "bearbeiten"; out.view = "ansehen"; - out.readme_cat2_l1 = "Der Knopf {0} in deinem Dokument erlaubt dich, anderen eine Mitarbeitzugang zu geben (entweder zu {1} oder {2})."; - out.readme_cat2_l2 = "Der Titel eines Dokuments kann mit einem Klick auf dem Stift verändert werden."; - out.readme_cat3 = "Entdecke CryptPad apps"; - out.readme_cat3_l1 = "Mit dem CryptPad Codeeditor kannst du auf Code wie JavaScript, Markdown, oder HTML"; - out.readme_cat3_l2 = "Mit dem CryptPad Präsentationseditor kannst du schnelle Vorträge mithilfe von Markdwon gestalten"; - out.readme_cat3_l3 = "Mit der CryptPad Umfrage kannst du schnell Abstrimmungen treffen, insbesonders, um Meetings zu planen, die dem Kalender von allen passen."; + out.readme_cat2_l1 = "Der Knopf {0} in Deinem Dokument erlaubt Dir, anderen einen Mitbearbeitungszugang zu geben (entweder zu {1} oder {2})."; + out.readme_cat2_l2 = "Der Titel eines Dokuments kann mit einem Klick auf den Stift geändert werden."; + out.readme_cat3 = "Entdecke CryptPad Apps"; + out.readme_cat3_l1 = "Mit dem CryptPad Codeeditor kannst Du Code wie JavaScript, Markdown, oder HTML bearbeiten"; + out.readme_cat3_l2 = "Mit dem CryptPad Präsentationseditor kannst Du schnell Vorträge mit Hilfe von Markdwon gestalten"; + out.readme_cat3_l3 = "Mit der CryptPad Umfrage kannst Du schnell Abstimmungen durchführen, insbesondere, um Meetings zu planen, die in den Kalender von allen passen."; // Tips out.tips = {}; out.tips.shortcuts = "`ctrl+b`, `ctrl+i` and `ctrl+u` sind Tatstenkürzeln um fett, kurziv, oder unterschrieben zu markieren."; - out.tips.indent = "In gezifferten oder einfache Listen kannst du TAB und SHIFT-TAB benutzen, um die Identierung zu erhöhen oder reduzieren."; - out.tips.store = "Jedes Mal, dass du ein Dokument besuchsts, und eingeloggt bist, wird es in deinem CryptDrive gespeichert."; + out.tips.indent = "In bezifferten oder einfache Listen kannst Du TAB und SHIFT-TAB benutzen, um den Einzug zu erhöhen oder reduzieren."; + out.tips.store = "Jedes Mal, wenn Du ein Dokument besuchst und eingeloggt bist, wird es in Deinem CryptDrive gespeichert."; out.tips.marker = "Du kannst Text in einem Dokument mit \"Marker\" Menü in dem Stilmenü markieren."; - out.tips.driveUpload = "Registrierte Benutzer können verschlüsselte Dateien aus ihrer Festplatten hochladen, indem sie einfach Schieben und in ihrem CryptDrive ablegen."; - out.tips.filenames = "Du kannst Dateien in deinem CryptDrive neubenennen. Dieser Name ist nur für dich."; - out.tips.drive = "Eingeloggte Benutzern können ihre Dateien in ihrem CryptDrive organisieren. Dieses ist mit einem Klick auf der CryptPad Ikone oben links erreichbar, wenn mann in einem Dokument ist."; - out.tips.profile = "Registrierte Benuzter können ein Profil gestalten mit dem Benutzer Menü oben rechts."; - out.tips.avatars = "Du kannst ein Benutzerbild in deinem Profil hochladen. Andere sehen es, wenn die in einem Dokument zusammenarbeiten."; - out.tips.tags = "Bringe Tags auf deinen Dokumenten und starte eine Suche-bei-Tags mit dem # Zeichen in dem CryptDrive Suche."; + out.tips.driveUpload = "Registrierte Benutzer können verschlüsselte Dateien aus ihrer Festplatte hochladen, indem sie sie einfach verschieben und in ihrem CryptDrive ablegen."; + out.tips.filenames = "Du kannst Dateien in Deinem CryptDrive neubenennen. Dieser Name ist nur für Dich."; + out.tips.drive = "Eingeloggte Benutzern können ihre Dateien in ihrem CryptDrive organisieren. Dieses ist mit einem Klick auf das CryptPad Symbol oben links erreichbar, wenn man in einem Dokument ist."; + out.tips.profile = "Registrierte Benutzer können ihr Profil mit dem Benutzer Menü oben rechts bearbeiten."; + out.tips.avatars = "Du kannst ein Benutzerbild in Dein Profil hochladen. Andere sehen es, wenn sie in einem Dokument zusammenarbeiten."; + out.tips.tags = "Bringe Tags auf Deinen Dokumenten an und starte eine Suche-nach-Tags mit dem # Zeichen in dem CryptDrive Suche."; - out.feedback_about = "Wenn du das liest, fragst du dich weshalb Anfragen an Webseiten schickt, wenn manche Aktionen geführt werden."; - out.feedback_privacy = "Wir wollen deinen Datenschutz schonen, aber gleichzeitig wollen wir, dass die Benutzung von CryptPad sehr leicht ist, zB indem wir erfahren, welche UI-Funktion am wichtigsten für unsere Benutzen ist. Dieses wird nachgefragt mit einer genauen Parameterbeschreibung, welche Aktion war gemacht."; - out.feedback_optout = "Wenn du es aber nicht möchtest. besuche deine Einstellungen, dort findest du ein Haken, wo du es deaktivieren kannst."; + out.feedback_about = "Wenn Du das liest, fragst Du Dich, weshalb Dein Browser Anfragen an Webseiten schickt, wenn manche Aktionen ausgeführt werden."; + out.feedback_privacy = "Wir kümmern uns um Deinen Datenschutz, aber gleichzeitig wollen wir, dass die Benutzung von CryptPad sehr leicht ist. Deshalb wollen wir erfahren, welche UI-Funktion am wichtigsten für unsere Benutzer ist, indem wir diese mit einer genauen Parameterbeschreibung anfordern."; + out.feedback_optout = "Wenn Du das aber nicht möchtest. besuche Deine Einstellungen, dort findest Du ein Haken, wo Du es deaktivieren kannst."; // Creation page out.creation_404 = "Dieses Dokument existiert nicht mehr. Benutze das folgende Formular, um ein neues Dokument zu gestalten."; out.creation_ownedTitle = "Dokumenttyp"; out.creation_owned = "Eigenes Dokument"; // Creation page out.creation_ownedTrue = "Eigenes Dokument"; // Settings - out.creation_ownedFalse = "Dokument von jemanden anders"; - out.creation_owned1 = "Ein eigenes Dokument kann vom Server gelöscht werden, wenn der Eigentümer es entscheidet. Die Löschung eines eigenes Dokuments verursacht die Löschung aus allen anderen CryptDrives. "; - out.creation_owned2 = "Ein offenes Dokument hat kein Eigentümer, also kann es nicht löschen, ausser es hat sein Auslaufdatum erreicht."; - out.creation_expireTitle = "Lebenszyklus"; - out.creation_expire = "Auslaufende Dokument"; - out.creation_expireTrue = "Ein Lebenszyklus hinzufügen"; - out.creation_expireFalse = "Unbegrenz"; + out.creation_ownedFalse = "Dokument von jemand anderem"; + out.creation_owned1 = "Ein eigenes Dokument kann vom Server gelöscht werden, wenn der Eigentümer so entscheidet. Die Löschung eines eigenes Dokuments bewirkt die Löschung aus allen anderen CryptDrives. "; + out.creation_owned2 = "Ein offenes Dokument hat keinen Eigentümer, also kann es nicht gelöscht werden, ausser es hat sein Ablaufdatum erreicht."; + out.creation_expireTitle = "Ablaufdatum"; + out.creation_expire = "Auslaufendes Dokument"; + out.creation_expireTrue = "Ein Ablaufdatum hinzufügen"; + out.creation_expireFalse = "Unbegrenzt"; out.creation_expireHours = "Stunde(n)"; - out.creation_expireDays = "Tag(en)"; + out.creation_expireDays = "Tag(e)"; out.creation_expireMonths = "Monat(e)"; - out.creation_expire1 = "An unlimited pad will not be removed from the server until its owner deletes it."; - out.creation_expire2 = "An expiring pad has a set lifetime, after which it will be automatically removed from the server and other users' CryptDrives."; + out.creation_expire1 = "Ein unbegrenztes Dokument wird nicht vom Server entfernt solange der Eigentümer es nicht löscht."; + out.creation_expire2 = "Ein auslaufendes Dokument hat eine begrenzte lebensdauer, nach der es automatisch vom Server und aus den CryptDrives anderer Leute entfernt wird."; + out.creation_password = "Passwort hinzufügen"; out.creation_noTemplate = "Keine Vorlage"; out.creation_newTemplate = "Neue Vorlage"; out.creation_create = "Erstellen"; out.creation_saveSettings = "Dieses Dialog nicht mehr anzeigen"; out.creation_settings = "Mehr Einstellungen zeigen"; - out.creation_rememberHelp = "Geh zu deiner Einstellungen, um diese Einstellung wieder vorzunehmen"; + out.creation_rememberHelp = "Geh zu Deiner Einstellungen, um diese Einstellung wieder vorzunehmen"; + // Properties about creation data out.creation_owners = "Eigentümer"; out.creation_ownedByOther = "Eigentum eines anderen Benutzer"; out.creation_noOwner = "Kein Eigentümer"; out.creation_expiration = "Auslaufdatum"; + out.creation_passwordValue = "Passwort"; out.creation_propertiesTitle = "Verfügbarkeit"; out.creation_appMenuName = "Fortgeschrittenes Modus (Ctrl + E)"; - out.creation_newPadModalDescription = "Klicke auf einem Padtyp, um es zu erstellen. Du kannst auch die Tab-Taste benutzen, um zu navigieren, und die Enter-Taste zu bestätigen. "; - out.creation_newPadModalDescriptionAdvanced = "Du kannst das Kästchen ticken (oder auf der Leertaste drucken um den Wert zu ändern), um das Einstellungsdialog bei der Dokumenterstellung anzuzeigen (für eigene oder auslaufende Dokumente)."; - out.creation_newPadModalAdvanced = "Das Einstellungdialog bei der Dokumenterstellung anzeigen"; + out.creation_newPadModalDescription = "Klicke auf einen Padtyp, um es zu erstellen. Du kannst auch die Tab-Taste benutzen, um zu navigieren, und die Enter-Taste zum Bestätigen. "; + out.creation_newPadModalDescriptionAdvanced = "Du kannst das Kästchen markieren (oder auf die Leertaste drücken, um den Wert zu ändern), um den Einstellungsdialog bei der Dokumenterstellung anzuzeigen (für eigene oder auslaufende Dokumente)."; + out.creation_newPadModalAdvanced = "Den Einstellungdialog bei der Dokumenterstellung anzeigen"; + + // Password prompt on the loading screen + out.password_info = "Das Pad, das Du öffnen möchtest, ist mit einem Passowrt geschützt. Gib das richtige Passwort ein, um den Inhalt anzuzeigen."; + out.password_error = "Pad nicht gefunden!
          Dieser Fehler kann zwei Ursachen haben: entweder ist das Passwort ungültig oder das Pad wurde vom Server gelöscht."; + out.password_placeholder = "Gib das Passwort hier ein..."; + out.password_submit = "Abschicken"; + out.password_show = "Anzeigen"; + + // Change password in pad properties + out.properties_addPassword = "Passwort hinzufügen"; + out.properties_changePassword = "Passwort ändern"; + out.properties_confirmNew = "Bist Du sicher? Das Hinzufügen eines Passworts wird die URL dieses Pads ändern und die Chronik entfernen. Benutzer ohne Passwort werden den Zugang zu diesem Pad verlieren."; + out.properties_confirmChange = "Bist Du sicher? Das Ändern des Passworts wird die Chronik entfernen. Benutzer ohne das neue Passwort werden den Zugang zu diesem Pad verlieren."; + out.properties_passwordError = "Ein Fehler ist aufgetreten beim Versuch das Passwort zu ändern. Bitte versuche es nochmal."; + out.properties_passwordWarning = "Das Password wurde erfolgreich geändert, aber Dein CryptDrive konnte nicht aktualisiert werden. Du mußt möglicherweise die alte Version des Pads manuell entfernen.
          Bitte klicke OK um die Seite neu zu laden und die Zugeriffsrechte zu aktualisieren."; + out.properties_passwordSuccess = "Das Password wurde erfolgreich geändert.
          Bitte klicke OK um die Seite neu zu laden und die Zugeriffsrechte zu aktualisieren."; + out.properties_changePasswordButton = "Abschicken"; // New share modal out.share_linkCategory = "Link teilen"; @@ -1157,12 +1185,20 @@ out.share_linkEdit = "Bearbeiten"; out.share_linkView = "Ansehen"; out.share_linkOptions = "Linkoptionen"; - out.share_linkEmbed = "Einbettungsmodus (Toolbar und Benutzerliste sind verborgen)"; - out.share_linkPresent = "Anzeigemodus (Bearbeitbare Abschnuttte sind verborgen)"; + out.share_linkEmbed = "Einbettungsmodus (Werkzeugleiste und Benutzerliste sind verborgen)"; + out.share_linkPresent = "Anzeigemodus (Bearbeitbare Abschnittte sind verborgen)"; out.share_linkOpen = "In einem neuen Tab öffnen"; - out.share_linkCopy = "Zur Zwischenablage kopieren."; + out.share_linkCopy = "In die Zwischenablage kopieren."; out.share_embedCategory = "Einbetten"; - out.share_mediatagCopy = "Mediatag zur Zwischenablage kopieren"; + out.share_mediatagCopy = "Mediatag in die Zwischenablage kopieren"; + + // Loading info + out.loading_pad_1 = "Initialisiere Pad"; + out.loading_pad_2 = "Lade Padinhalt"; + out.loading_drive_1 = "Lade Daten"; + out.loading_drive_2 = "Aktualisiere Datenformat"; + out.loading_drive_3 = "Verifiziere Datenintegrität"; - return out; + return out; }); + From 9787f5304a0d151d782af96fdd55048e47a07a44 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 11 Jul 2018 15:28:24 +0200 Subject: [PATCH 16/86] Don't unpin channels that are still in another proxy --- www/common/proxy-manager.js | 122 +++++++++++++++++++++--------------- 1 file changed, 72 insertions(+), 50 deletions(-) diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index bf43bb94e..de69bdd59 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -50,6 +50,25 @@ define([ return userObjects; }; + var _getUserObjectFromId = function (Env, id) { + var userObjects = _getUserObjects(Env); + var userObject = Env.user.userObject; + userObjects.some(function (uo) { + if (Object.keys(uo.getFileData(id)).length) { + userObject = uo; + return true; + } + }); + return userObject; + }; + + var _getUserObjectPath = function (Env, uo) { + var fId = Number(uo.id); + if (!fId) { return; } + var fPath = Env.user.userObject.findFile(fId)[0]; + return fPath; + }; + // Return files data objects associated to a channel for setPadTitle // All occurences are returned, in drive or shared folders var findChannel = function (Env, channel) { @@ -89,6 +108,31 @@ define([ return ret; }; + // Returns file IDs corresponding to the provided channels + var _findChannels = function (Env, channels, onlyMain) { + if (onlyMain) { + return Env.user.userObject.findChannels(channels); + } + var ret = []; + var userObjects = _getUserObjects(Env); + userObjects.forEach(function (uo) { + var results = uo.findChannels(channels); + Array.prototype.push.apply(ret, results); + }); + ret = Util.deduplicateString(ret); + return ret; + }; + + var _getFileData = function (Env, id) { + var userObjects = _getUserObjects(Env); + var data = {}; + userObjects.some(function (uo) { + data = uo.getFileData(id); + if (Object.keys(data).length) { return true; } + }); + return data; + }; + // Transform an absolute path into a path relative to the correct shared folder var _resolvePath = function (Env, path) { var res = { @@ -278,23 +322,41 @@ define([ if (!resolved.main.length && !Object.keys(resolved.folders).length) { return void cb({error: 'E_NOTFOUND'}); } + + var toUnpin = []; nThen(function (waitFor)  { if (resolved.main.length) { - Env.user.userObject.delete(resolved.main, waitFor(function (err, toUnpin) { + Env.user.userObject.delete(resolved.main, waitFor(function (err, _toUnpin) { if (!Env.unpinPads) { return; } - Env.unpinPads(toUnpin, waitFor(function (response) { - if (response && response.error) { return console.error(response.error); } - })); + Array.prototype.push.apply(toUnpin, _toUnpin); }), data.nocheck, data.isOwnPadRemoved); } Object.keys(resolved.folders).forEach(function (id) { - Env.folders[id].userObject.delete(resolved.folders[id], waitFor(function (err, toUnpin) { + Env.folders[id].userObject.delete(resolved.folders[id], waitFor(function (err, _toUnpin) { if (!Env.unpinPads) { return; } - Env.unpinPads(toUnpin, waitFor(function (response) { - if (response && response.error) { return console.error(response.error); } - })); + Array.prototype.push.apply(toUnpin, _toUnpin); }), data.nocheck, data.isOwnPadRemoved); }); + }).nThen(function (waitFor) { + if (!Env.unpinPads) { return; } + + // Deleted channels + toUnpin = Util.deduplicateString(toUnpin); + // Deleted channels that are still in another proxy + var toKeep = _findChannels(Env, toUnpin).map(function (id) { + return _getFileData(Env, id).channel; + }); + // Compute the unpin list and unpin + var unpinList = []; + toUnpin.forEach(function (chan) { + if (toKeep.indexOf(chan) === -1) { + unpinList.push(chan); + } + }); + + Env.unpinPads(unpinList, waitFor(function (response) { + if (response && response.error) { return console.error(response.error); } + })); }).nThen(function () { cb(); }); @@ -602,34 +664,8 @@ define([ /* Tools */ - var _getUserObjectFromId = function (Env, id) { - var userObjects = _getUserObjects(Env); - var userObject = Env.user.userObject; - userObjects.some(function (uo) { - if (Object.keys(uo.getFileData(id)).length) { - userObject = uo; - return true; - } - }); - return userObject; - }; - - var _getUserObjectPath = function (Env, uo) { - var fId = Number(uo.id); - if (!fId) { return; } - var fPath = Env.user.userObject.findFile(fId)[0]; - return fPath; - }; - - var getFileData = function (Env, id) { - var userObjects = _getUserObjects(Env); - var data = {}; - userObjects.some(function (uo) { - data = uo.getFileData(id); - if (Object.keys(data).length) { return true; } - }); - return data; - }; + var findChannels = _findChannels; + var getFileData = _getFileData; var find = function (Env, path) { var resolved = _resolvePath(Env, path); @@ -694,20 +730,6 @@ define([ return ret; }; - var findChannels = function (Env, channels, onlyMain) { - if (onlyMain) { - return Env.user.userObject.findChannels(channels); - } - var ret = []; - var userObjects = _getUserObjects(Env); - userObjects.forEach(function (uo) { - var results = uo.findChannels(channels); - Array.prototype.push.apply(ret, results); - }); - ret = Util.deduplicateString(ret); - return ret; - }; - var getRecentPads = function (Env) { return Env.user.userObject.getRecentPads(); }; From 8516587ece9133c7ca8f87d7c7715815e01d8e26 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 11 Jul 2018 15:28:34 +0200 Subject: [PATCH 17/86] lint compliance --- www/common/mergeDrive.js | 1 - www/common/outer/async-store.js | 3 +-- www/common/outer/userObject.js | 6 +----- www/common/userObject.js | 1 - www/drive/inner.js | 10 +++++----- www/drive/main.js | 2 +- 6 files changed, 8 insertions(+), 15 deletions(-) diff --git a/www/common/mergeDrive.js b/www/common/mergeDrive.js index 59f4363b3..a633489b2 100644 --- a/www/common/mergeDrive.js +++ b/www/common/mergeDrive.js @@ -33,7 +33,6 @@ define([ var onMigrated = function () { oldFo.fixFiles(true); var manager = proxyData.manager; - var oldRecentPads = parsed.drive[oldFo.FILES_DATA]; var oldFiles = oldFo.getFiles([oldFo.FILES_DATA]); oldFiles.forEach(function (id) { var data = oldFo.getFileData(id); diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index accc5c380..7f3aebb00 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -1185,12 +1185,11 @@ define([ })); }).nThen(function (waitFor) { // 2a. add the shared folder to the path in our drive - console.log('adding'); store.userObject.add(id, path); onSync(waitFor()); // 2b. load the proxy - rt = loadSharedFolder(id, data.folderData, waitFor(function () { + loadSharedFolder(id, data.folderData, waitFor(function (rt) { if (data.metadata) { // Creating a new shared folder rt.proxy.metadata = data.metadata; onSync(waitFor()); diff --git a/www/common/outer/userObject.js b/www/common/outer/userObject.js index 454ba3fc6..703426d56 100644 --- a/www/common/outer/userObject.js +++ b/www/common/outer/userObject.js @@ -92,7 +92,7 @@ define([ var fd = exp.getFileData(id); var channelId = fd.channel; // If trying to remove an owned pad, remove it from server also - if (!isOwnPadRemoved && + if (!isOwnPadRemoved && !sharedFolder && fd.owners && fd.owners.indexOf(edPublic) !== -1 && channelId) { removeOwnedChannel(channelId, function (obj) { if (obj && obj.error) { @@ -113,10 +113,6 @@ define([ }); if (!toClean.length) { return; } cb(null, toClean); - unpinPads(toClean, function (response) { - if (response && response.error) { return console.error(response.error); } - // console.error(response); - }); }; var deleteHrefs = function (ids) { ids.forEach(function (obj) { diff --git a/www/common/userObject.js b/www/common/userObject.js index 2449a2dc5..ce1cfb665 100644 --- a/www/common/userObject.js +++ b/www/common/userObject.js @@ -17,7 +17,6 @@ define([ module.init = function (files, config) { var exp = {}; - var pinPads = config.pinPads; var sframeChan = config.sframeChan; var FILES_DATA = module.FILES_DATA = exp.FILES_DATA = Constants.storageKey; diff --git a/www/drive/inner.js b/www/drive/inner.js index 596924101..d648ed092 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -90,7 +90,7 @@ define([ //var $folderOpenedIcon = $('', {src: "/customize/images/icons/folderOpen.svg", "class": "folder icon"}); var $folderOpenedEmptyIcon = $folderOpenedIcon.clone(); var $sharedFolderIcon = $('', {"class": faSharedFolder + " fa cp-app-drive-icon-folder"}); - var $sharedFolderOpenedIcon = $sharedFolderIcon.clone(); + //var $sharedFolderOpenedIcon = $sharedFolderIcon.clone(); //var $upIcon = $('', {"class": "fa fa-arrow-circle-up"}); var $unsortedIcon = $('', {"class": "fa fa-files-o"}); var $templateIcon = $('', {"class": "fa fa-cubes"}); @@ -1518,14 +1518,14 @@ define([ var skipNext = false; // When encountering a shared folder, skip a key in the path path.forEach(function (p, idx) { - if (skipNext) { return skipNext = false; } + if (skipNext) { skipNext = false; return; } if (isTrash && [2,3].indexOf(idx) !== -1) { return; } var name = p; - var el = manager.find(path.slice(0, idx+1)); - if (manager.isSharedFolder(el)) { - name = manager.getSharedFolderData(el).title; + var currentEl = manager.find(path.slice(0, idx+1)); + if (manager.isSharedFolder(currentEl)) { + name = manager.getSharedFolderData(currentEl).title; skipNext = true; } diff --git a/www/drive/main.js b/www/drive/main.js index 0247f4a4b..21b563da9 100644 --- a/www/drive/main.js +++ b/www/drive/main.js @@ -42,7 +42,7 @@ define([ if (hash) { // Add a shared folder! // XXX password? - Cryptpad.addSharedFolder(secret, function (obj) { + Cryptpad.addSharedFolder(secret, function () { window.location.hash = ""; cb(null, secret); }); From 7d89026d8349f8216533671e77c3256f72ea4279 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 12 Jul 2018 17:27:16 +0200 Subject: [PATCH 18/86] Fix more issues with shared folders --- www/common/outer/async-store.js | 82 ++++++------------------- www/common/outer/userObject.js | 26 ++++++-- www/common/proxy-manager.js | 102 ++++++++++++++++++++++++++++++-- www/common/userObject.js | 9 ++- www/drive/inner.js | 100 ++++++++++++++++++++++++++++--- 5 files changed, 236 insertions(+), 83 deletions(-) diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 7f3aebb00..f746399fa 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -1148,6 +1148,7 @@ define([ var loadSharedFolder = function (id, data, cb) { var parsed = Hash.parsePadUrl(data.href); var secret = Hash.getSecrets('drive', parsed.hash, data.password); + var owners = data.owners; var listmapConfig = { data: {}, websocketURL: NetConfig.getWebsocketURL(), @@ -1159,85 +1160,39 @@ define([ logLevel: 1, ChainPad: ChainPad, classic: true, + owners: owners }; var rt = Listmap.create(listmapConfig); store.sharedFolders[id] = rt; rt.proxy.on('ready', function (info) { store.manager.addProxy(id, rt.proxy, info.leave); - cb(rt); + cb(rt, info.metadata); }); return rt; }; Store.addSharedFolder = function (clientId, data, cb) { - var path = data.path; - var folderData = data.folderData || {}; - var id; - nThen(function (waitFor) { - Store.pinPads(clientId, [folderData.channel], waitFor()); - }).nThen(function (waitFor) { - // 1. add the shared folder to our list of shared folders - store.userObject.pushSharedFolder(folderData, waitFor(function (err, folderId) { - if (err) { - waitFor.abort(); - return void cb(err); - } - id = folderId; - })); - }).nThen(function (waitFor) { - // 2a. add the shared folder to the path in our drive - store.userObject.add(id, path); - onSync(waitFor()); - - // 2b. load the proxy - loadSharedFolder(id, data.folderData, waitFor(function (rt) { - if (data.metadata) { // Creating a new shared folder - rt.proxy.metadata = data.metadata; - onSync(waitFor()); - } - })); - }).nThen(function () { - sendDriveEvent('DRIVE_CHANGE', { - path: ['drive'].concat(path) - }, clientId); - cb(); - }); - }; - store.createSharedFolder = function () { - // XXX - var hash = Hash.createRandomHash('drive'); - var href = '/drive/#' + hash; - var secret = Hash.getSecrets('drive', hash); - Store.addSharedFolder(null, { - path: ['root'], - folderData: { - href: href, - roHref: '/drive/#' + Hash.getViewHashFromKeys(secret), - channel: secret.channel, - ctime: +new Date() - }, - metadata: { - title: "Test" - } - }, function () { - console.log('done'); - }); + Store.userObjectCommand(clientId, { + cmd: 'addSharedFolder', + data: data + }, cb); }; - // Drive Store.userObjectCommand = function (clientId, cmdData, cb) { if (!cmdData || !cmdData.cmd) { return; } - var data = cmdData.data; + //var data = cmdData.data; var cb2 = function (data2) { - var paths = data.paths || [data.path] || []; - paths = paths.concat(data.newPath || []); - paths.forEach(function (p) { + //var paths = data.paths || [data.path] || []; + //paths = paths.concat(data.newPath ? [data.newPath] : []); + //paths.forEach(function (p) { sendDriveEvent('DRIVE_CHANGE', { - //path: ['drive', UserObject.FILES_DATA] - path: ['drive'].concat(p) + path: ['drive', UserObject.FILES_DATA] + //path: ['drive'].concat(p) }, clientId); + //}); + onSync(function () { + cb(data2); }); - cb(data2); }; store.manager.command(cmdData, cb2); }; @@ -1376,9 +1331,10 @@ define([ if (!store.loggedIn) { return void cb(); } Store.pinPads(null, data, cb); }; - var manager = store.manager = ProxyManager.create(proxy.drive, proxy.edPublic, pin, unpin, { + var manager = store.manager = ProxyManager.create(proxy.drive, proxy.edPublic, + pin, unpin, loadSharedFolder, { outer: true, - removeOwnedChannel: function (data, cb) { Store.removeOwnedChannel(null, data, cb); }, + removeOwnedChannel: function (data, cb) { Store.removeOwnedChannel('', data, cb); }, edPublic: store.proxy.edPublic, loggedIn: store.loggedIn, log: function (msg) { diff --git a/www/common/outer/userObject.js b/www/common/outer/userObject.js index 703426d56..defc4dbd9 100644 --- a/www/common/outer/userObject.js +++ b/www/common/outer/userObject.js @@ -83,13 +83,14 @@ define([ // FILES_DATA. If there are owned pads, remove them from server too, unless the flag tells // us they're already removed exp.checkDeletedFiles = function (isOwnPadRemoved, cb) { - if (!loggedIn && !config.testMode) { return; } + if (!loggedIn && !config.testMode) { return void cb(); } var filesList = exp.getFiles([ROOT, 'hrefArray', TRASH]); var toClean = []; - exp.getFiles([FILES_DATA]).forEach(function (id) { + exp.getFiles([FILES_DATA, SHARED_FOLDERS]).forEach(function (id) { + // XXX if (filesList.indexOf(id) === -1) { - var fd = exp.getFileData(id); + var fd = exp.isSharedFolder(id) ? files[SHARED_FOLDERS][id] : exp.getFileData(id); var channelId = fd.channel; // If trying to remove an owned pad, remove it from server also if (!isOwnPadRemoved && !sharedFolder && @@ -108,10 +109,14 @@ define([ }); } if (channelId) { toClean.push(channelId); } - spliceFileData(id); + if (exp.isSharedFolder(id)) { + delete files[SHARED_FOLDERS][id]; + } else { + spliceFileData(id); + } } }); - if (!toClean.length) { return; } + if (!toClean.length) { return void cb(); } cb(null, toClean); }; var deleteHrefs = function (ids) { @@ -672,6 +677,17 @@ define([ var fixSharedFolders = function () { if (sharedFolder) { return; } if (typeof(files[SHARED_FOLDERS]) !== "object") { debug("SHARED_FOLDER was not an object"); files[SHARED_FOLDERS] = {}; } + var sf = files[SHARED_FOLDERS]; + var rootFiles = exp.getFiles([ROOT]); + var root = exp.find([ROOT]); + for (var id in sf) { + id = Number(id); + if (rootFiles.indexOf(id) === -1) { + console.log('missing' + id); + var newName = Hash.createChannelId(); + root[newName] = id; + } + } }; var fixDrive = function () { diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index de69bdd59..ca927cfe3 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -1,8 +1,9 @@ define([ '/common/userObject.js', '/common/common-util.js', + '/common/common-hash.js', '/bower_components/nthen/index.js', -], function (UserObject, Util, nThen) { +], function (UserObject, Util, Hash, nThen) { var getConfig = function (Env) { @@ -315,6 +316,65 @@ define([ cb(obj); }); }; + // Add a folder/subfolder + var _addSharedFolder = function (Env, data, cb) { + console.log(data); + data = data || {}; + var resolved = _resolvePath(Env, data.path); + if (!resolved || !resolved.userObject) { return void cb({error: 'E_NOTFOUND'}); } + if (resolved.id) { return void cb({error: 'EINVAL'}); } + if (!Env.pinPads) { return void cb({error: 'EAUTH'}); } + + var folderData = data.folderData || {}; + + var id; + nThen(function () { + // Check if it is an imported folder or a folder creation + if (data.folderData) { return; } + + // Folder creation + var hash = Hash.createRandomHash('drive'); + var href = '/drive/#' + hash; + var secret = Hash.getSecrets('drive', hash); + folderData = { + href: href, + roHref: '/drive/#' + Hash.getViewHashFromKeys(secret), + channel: secret.channel, + ctime: +new Date() + }; + if (data.password) { folderData.password = data.password; } + if (data.owned) { folderData.owners = [Env.edPublic]; } + }).nThen(function (waitFor) { + Env.pinPads([folderData.channel], waitFor()); + }).nThen(function (waitFor) { + // 1. add the shared folder to our list of shared folders + Env.user.userObject.pushSharedFolder(folderData, waitFor(function (err, folderId) { + if (err) { + waitFor.abort(); + return void cb(err); + } + id = folderId; + })); + }).nThen(function (waitFor) { + // 2a. add the shared folder to the path in our drive + Env.user.userObject.add(id, resolved.path); + + // 2b. load the proxy + Env.loadSharedFolder(id, folderData, waitFor(function (rt, metadata) { + if (data.name && !rt.proxy.metadata) { // Creating a new shared folder + rt.proxy.metadata = {title: data.name}; + } + // If we're importing a folder, check its serverside metadata + if (data.folderData && metadata) { + var fData = Env.user.proxy[UserObject.SHARED_FOLDERS][id]; + if (metadata.owners) { fData.owners = metadata.owners; } + if (metadata.expire) { fData.expire = +metadata.expire; } + } + })); + }).nThen(function () { + cb(id); + }); + }; // Delete permanently some pads or folders var _delete = function (Env, data, cb) { data = data || {}; @@ -327,13 +387,13 @@ define([ nThen(function (waitFor)  { if (resolved.main.length) { Env.user.userObject.delete(resolved.main, waitFor(function (err, _toUnpin) { - if (!Env.unpinPads) { return; } + if (!Env.unpinPads || !_toUnpin) { return; } Array.prototype.push.apply(toUnpin, _toUnpin); }), data.nocheck, data.isOwnPadRemoved); } Object.keys(resolved.folders).forEach(function (id) { Env.folders[id].userObject.delete(resolved.folders[id], waitFor(function (err, _toUnpin) { - if (!Env.unpinPads) { return; } + if (!Env.unpinPads || !_toUnpin) { return; } Array.prototype.push.apply(toUnpin, _toUnpin); }), data.nocheck, data.isOwnPadRemoved); }); @@ -389,6 +449,8 @@ define([ _restore(Env, data, cb); break; case 'addFolder': _addFolder(Env, data, cb); break; + case 'addSharedFolder': + _addSharedFolder(Env, data, cb); break; case 'delete': _delete(Env, data, cb); break; case 'emptyTrash': @@ -483,7 +545,7 @@ define([ // Get the list of channels filtered by a type (expirable channels, owned channels, pin list) var getChannelsList = function (Env, edPublic, type) { - if (!edPublic) { return; } + //if (!edPublic) { return; } var result = []; var addChannel = function (userObject) { if (type === 'expirable') { @@ -492,7 +554,7 @@ define([ // Don't push duplicates if (result.indexOf(data.channel) !== -1) { return; } // Return pads owned by someone else or expired by time - if ((data.owners && data.owners.length && data.owners.indexOf(edPublic) === -1) + if ((data.owners && data.owners.length && (!edPublic || data.owners.indexOf(edPublic) === -1)) || (data.expire && data.expire < (+new Date()))) { result.push(data.channel); } @@ -524,6 +586,9 @@ define([ } }; + if (type === 'owned' && !edPublic) { return result; } + if (type === 'pin' && !edPublic) { return result; } + // Get the list of user objects var userObjects = _getUserObjects(Env); @@ -532,6 +597,17 @@ define([ files.forEach(addChannel(uo)); }); + // NOTE: expirable shared folder should be added here if we ever decide to enable them + if (type === "owned") { + var sfOwned = Object.keys(Env.user.proxy[UserObject.SHARED_FOLDERS]).filter(function (fId) { + var owners = Env.user.proxy[UserObject.SHARED_FOLDERS][fId].owners; + if (Array.isArray(owners) && owners.length && + owners.indexOf(edPublic) !== -1) { return true; } + }).map(function (fId) { + return Env.user.proxy[UserObject.SHARED_FOLDERS][fId].channel; + }); + Array.prototype.push.apply(result, sfOwned); + } if (type === "pin") { var sfChannels = Object.keys(Env.folders).map(function (fId) { return Env.user.proxy[UserObject.SHARED_FOLDERS][fId].channel; @@ -566,10 +642,11 @@ define([ }); }; - var create = function (proxy, edPublic, pinPads, unpinPads, uoConfig) { + var create = function (proxy, edPublic, pinPads, unpinPads, loadSf, uoConfig) { var Env = { pinPads: pinPads, unpinPads: unpinPads, + loadSharedFolder: loadSf, cfg: uoConfig, edPublic: edPublic, user: { @@ -642,6 +719,18 @@ define([ } }, cb); }; + var addSharedFolderInner = function (Env, path, data, cb) { + console.log(data); + return void Env.sframeChan.query("Q_DRIVE_USEROBJECT", { + cmd: "addSharedFolder", + data: { + path: path, + name: data.name, + owned: data.owned, + password: data.password + } + }, cb); + }; var deleteInner = function (Env, paths, cb, nocheck, isOwnPadRemoved, noUnpin) { return void Env.sframeChan.query("Q_DRIVE_USEROBJECT", { cmd: "delete", @@ -822,6 +911,7 @@ define([ move: callWithEnv(moveInner), emptyTrash: callWithEnv(emptyTrashInner), addFolder: callWithEnv(addFolderInner), + addSharedFolder: callWithEnv(addSharedFolderInner), delete: callWithEnv(deleteInner), restore: callWithEnv(restoreInner), // Tools diff --git a/www/common/userObject.js b/www/common/userObject.js index ce1cfb665..7a1576f96 100644 --- a/www/common/userObject.js +++ b/www/common/userObject.js @@ -213,7 +213,7 @@ define([ var getFilesRecursively = exp.getFilesRecursively = function (root, arr) { arr = arr || []; for (var e in root) { - if (isFile(root[e])) { + if (isFile(root[e]) || isSharedFolder(root[e])) { if(arr.indexOf(root[e]) === -1) { arr.push(root[e]); } } else { getFilesRecursively(root[e], arr); @@ -275,10 +275,15 @@ define([ if (!files[FILES_DATA]) { return ret; } return Object.keys(files[FILES_DATA]).map(Number); }; + _getFiles[SHARED_FOLDERS] = function () { + var ret = []; + if (!files[SHARED_FOLDERS]) { return ret; } + return Object.keys(files[SHARED_FOLDERS]).map(Number); + }; var getFiles = exp.getFiles = function (categories) { var ret = []; if (!categories || !categories.length) { - categories = [ROOT, 'hrefArray', TRASH, OLD_FILES_DATA, FILES_DATA]; + categories = [ROOT, 'hrefArray', TRASH, OLD_FILES_DATA, FILES_DATA, SHARED_FOLDERS]; } categories.forEach(function (c) { if (typeof _getFiles[c] === "function") { diff --git a/www/drive/inner.js b/www/drive/inner.js index d648ed092..d74d61d06 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -213,10 +213,11 @@ define([ for (var k in objRef) { delete objRef[k]; } $.extend(true, objRef, objToCopy); }; - var updateSharedFolders = function (sframeChan, drive, folders, cb) { + var updateSharedFolders = function (sframeChan, manager, drive, folders, cb) { if (!drive || !drive.sharedFolders) { return void cb(); } + var oldIds = Object.keys(folders); nThen(function (waitFor) { Object.keys(drive.sharedFolders).forEach(function (fId) { sframeChan.query('Q_DRIVE_GETOBJECT', { @@ -224,6 +225,9 @@ define([ }, waitFor(function (err, newObj) { folders[fId] = folders[fId] || {}; copyObjectValue(folders[fId], newObj); + if (manager && oldIds.indexOf(fId) === -1) { + manager.addProxy(fId, folders[fId]); + } })); }); }).nThen(function () { @@ -260,6 +264,10 @@ define([ 'tabindex': '-1', 'data-icon': faFolder, }, Messages.fc_newfolder)), + h('li', h('a.cp-app-drive-context-newsharedfolder.dropdown-item.cp-app-drive-context-editable', { + 'tabindex': '-1', + 'data-icon': faSharedFolder, + }, 'New SF')), // XXX h('li', h('a.cp-app-drive-context-hashtag.dropdown-item.cp-app-drive-context-editable', { 'tabindex': '-1', 'data-icon': faTags, @@ -786,6 +794,7 @@ define([ if (type === "content") { filter = function ($el, className) { if (className === 'newfolder') { return; } + if (className === 'newsharedfolder') { return; } return AppConfig.availablePadTypes.indexOf($el.attr('data-type')) === -1; }; } else { @@ -869,7 +878,7 @@ define([ switch(type) { case 'content': - show = ['newfolder', 'newdoc']; + show = ['newfolder', 'newsharedfolder', 'newdoc']; break; case 'tree': show = ['open', 'openro', 'rename', 'delete', 'deleteowned', 'removesf', @@ -1648,6 +1657,52 @@ define([ $container.append($button); }; + // Get the upload options + var addSharedFolderModal = function (cb) { + var createHelper = function (href, text) { + var q = h('a.fa.fa-question-circle', { + style: 'text-decoration: none !important;', + title: text, + href: APP.origin + href, + target: "_blank", + 'data-tippy-placement': "right" + }); + return q; + }; + + // Ask for name, password and owner + // XXX + var content = h('div', [ + h('h4', "NEW SF TITLE"), + h('label', {for: 'cp-app-drive-sf-name'}, 'SF NAME'), + h('input#cp-app-drive-sf-name', {type: 'text', placeholder: "NEW FOLDER NAME"}), + //h('label', {for: 'cp-app-drive-sf-password'}, 'SF PASSWORD'), + //UI.passwordInput({id: 'cp-app-drive-sf-password'}), + h('span', { + style: 'display:flex;align-items:center;justify-content:space-between' + }, [ + UI.createCheckbox('cp-app-drive-sf-owned', "OWNED?", true), + createHelper('/faq.html#keywords-owned', Messages.creation_owned1) // TODO + ]), + ]); + + UI.confirm(content, function (yes) { + if (!yes) { return void cb(); } + + // Get the values + var newName = $(content).find('#cp-app-drive-sf-name').val(); + //var password = $(content).find('#cp-app-drive-sf-password').val() || undefined; + var password; + var owned = $(content).find('#cp-app-drive-sf-owned').is(':checked'); + + cb({ + name: newName, + password: password, + owned: owned + }); + }); + }; + var getNewPadTypes = function () { var arr = []; AppConfig.availablePadTypes.forEach(function (type) { @@ -1680,6 +1735,12 @@ define([ .click(function () { manager.addFolder(currentPath, null, onCreated); }); + $block.find('a.cp-app-drive-new-shared-folder, li.cp-app-drive-new-shared-folder') + .click(function () { + addSharedFolderModal(function (obj) { + manager.addSharedFolder(currentPath, obj, refresh); + }); + }); $block.find('a.cp-app-drive-new-upload, li.cp-app-drive-new-upload') .click(function () { var $input = $('', { @@ -1719,6 +1780,11 @@ define([ attributes: {'class': 'cp-app-drive-new-folder'}, content: $('
          ').append($folderIcon.clone()).html() + Messages.fm_folder }); + options.push({ + tag: 'a', + attributes: {'class': 'cp-app-drive-new-shared-folder'}, + content: $('
          ').append($folderIcon.clone()).html() + "NEW SF" // XXX + }); options.push({tag: 'hr'}); options.push({ tag: 'a', @@ -1967,6 +2033,13 @@ define([ }).prepend($folderIcon.clone()).appendTo($container); $element1.append($('', { 'class': 'cp-app-drive-new-name' }) .text(Messages.fm_folder)); + // Shared Folder + var $element3 = $('
        • ', { + 'class': 'cp-app-drive-new-shared-folder cp-app-drive-element-row ' + + 'cp-app-drive-element-grid' + }).prepend($folderIcon.clone()).appendTo($container); + $element3.append($('', { 'class': 'cp-app-drive-new-name' }) + .text("SF")); // XXX // File var $element2 = $('
        • ', { 'class': 'cp-app-drive-new-upload cp-app-drive-element-row ' + @@ -2510,7 +2583,7 @@ define([ } updateObject(sframeChan, proxy, function () { copyObjectValue(files, proxy.drive); - updateSharedFolders(sframeChan, files, folders, function () { + updateSharedFolders(sframeChan, manager, files, folders, function () { _displayDirectory(path, force); }); }); @@ -2590,7 +2663,14 @@ define([ // Display root content var $list = $('
            ').appendTo($container); - var keys = Object.keys(root).sort(); + var keys = Object.keys(root).sort(function (a, b) { + var newA = manager.isSharedFolder(root[a]) ? + manager.getSharedFolderData(root[a]).title : a; + var newB = manager.isSharedFolder(root[b]) ? + manager.getSharedFolderData(root[b]).title : b; + return newA < newB ? -1 : + (newA === newB ? 0 : 1); + }); keys.forEach(function (key) { // Do not display files in the menu if (!manager.isFolder(root[key])) { return; } @@ -2604,8 +2684,8 @@ define([ newPath.push(manager.user.userObject.ROOT); isCurrentFolder = manager.comparePath(newPath, currentPath); // Subfolders? - root = manager.folders[fId].proxy[manager.user.userObject.ROOT]; - subfolder = manager.hasSubfolder(root); + var newRoot = manager.folders[fId].proxy[manager.user.userObject.ROOT]; + subfolder = manager.hasSubfolder(newRoot); // Fix name key = manager.getSharedFolderData(fId).title; // Fix icon @@ -2893,6 +2973,12 @@ define([ }; manager.addFolder(paths[0].path, null, onFolderCreated); } + else if ($(this).hasClass('cp-app-drive-context-newsharedfolder')) { + if (paths.length !== 1) { return; } + addSharedFolderModal(function (obj) { + manager.addSharedFolder(paths[0].path, obj, refresh); + }); + } else if ($(this).hasClass("cp-app-drive-context-newdoc")) { var ntype = $(this).data('type') || 'pad'; var path2 = manager.isPathIn(currentPath, [TRASH]) ? '' : currentPath; @@ -3165,7 +3251,7 @@ define([ var sframeChan = common.getSframeChannel(); updateObject(sframeChan, proxy, waitFor(function () { - updateSharedFolders(sframeChan, proxy.drive, folders, waitFor()); + updateSharedFolders(sframeChan, null, proxy.drive, folders, waitFor()); })); }).nThen(function () { var sframeChan = common.getSframeChannel(); From 4a352f2ed8f60fd5456c75900e9b94a4f0fb7503 Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Thu, 12 Jul 2018 18:43:17 +0200 Subject: [PATCH 19/86] Use import (reference) whenever the less file supposedly emits no CSS --- customize.dist/src/less2/404.less | 6 ++--- .../src/less2/include/alertify.less | 6 ++--- customize.dist/src/less2/include/avatar.less | 2 +- .../src/less2/include/checkmark.less | 2 +- .../src/less2/include/colortheme-all.less | 4 ++-- .../src/less2/include/creation.less | 6 ++--- .../src/less2/include/dropdown.less | 4 ++-- .../src/less2/include/fileupload.less | 2 +- .../src/less2/include/framework.less | 14 ++++++------ customize.dist/src/less2/include/help.less | 2 +- .../src/less2/include/icon-colors.less | 2 +- .../src/less2/include/infopages.less | 2 +- .../src/less2/include/leftside-menu.less | 6 ++--- .../src/less2/include/limit-bar.less | 2 +- .../src/less2/include/markdown-toolbar.less | 2 +- customize.dist/src/less2/include/modal.less | 4 ++-- .../src/less2/include/sidebar-layout.less | 4 ++-- customize.dist/src/less2/include/tippy.less | 2 +- .../src/less2/include/tokenfield.less | 2 +- .../src/less2/include/toolbar-history.less | 2 +- customize.dist/src/less2/include/toolbar.less | 22 +++++++++---------- customize.dist/src/less2/main.less | 6 ++--- customize.dist/src/less2/pages/page-404.less | 4 ++-- .../src/less2/pages/page-about.less | 2 +- .../src/less2/pages/page-contact.less | 2 +- customize.dist/src/less2/pages/page-faq.less | 2 +- .../src/less2/pages/page-features.less | 2 +- .../src/less2/pages/page-index.less | 2 +- .../src/less2/pages/page-login.less | 6 ++--- .../src/less2/pages/page-privacy.less | 2 +- .../src/less2/pages/page-register.less | 6 ++--- .../src/less2/pages/page-terms.less | 2 +- .../less2/pages/page-what-is-cryptpad.less | 2 +- www/code/app-code.less | 4 ++-- www/common/file-dialog.less | 4 ++-- www/contacts/app-contacts.less | 6 ++--- www/debug/app-debug.less | 8 +++---- www/drive/app-drive.less | 12 +++++----- www/file/app-file.less | 6 ++--- www/filepicker/app-filepicker.less | 12 +++++----- www/kanban/app-kanban.less | 4 ++-- www/poll/app-poll.less | 8 +++---- www/profile/app-profile.less | 8 +++---- www/settings/app-settings.less | 10 ++++----- www/slide/app-slide.less | 6 ++--- www/todo/app-todo.less | 6 ++--- www/whiteboard/app-whiteboard.less | 6 ++--- www/worker/app-worker.less | 6 ++--- 48 files changed, 121 insertions(+), 121 deletions(-) diff --git a/customize.dist/src/less2/404.less b/customize.dist/src/less2/404.less index 33a852cd0..1aabf463b 100644 --- a/customize.dist/src/less2/404.less +++ b/customize.dist/src/less2/404.less @@ -1,4 +1,4 @@ -@import (once) './include/font.less'; +@import (reference) './include/font.less'; .font_neuropolitical(); .font_open-sans(); @@ -13,12 +13,12 @@ body.cp-page-terms { @import "./pages/page-terms.less"; } // Set the HTML style for the apps which shouldn't have a body scrollbar html.cp-app-noscroll { - @import "./include/app-noscroll.less"; + @import (reference) "./include/app-noscroll.less"; .app-noscroll_main(); } // Set the HTML style for printing slides html.cp-app-print { - @import "./include/app-print.less"; + @import (reference) "./include/app-print.less"; .app-print_main(); } diff --git a/customize.dist/src/less2/include/alertify.less b/customize.dist/src/less2/include/alertify.less index fd340f8d2..c35c46a98 100644 --- a/customize.dist/src/less2/include/alertify.less +++ b/customize.dist/src/less2/include/alertify.less @@ -1,6 +1,6 @@ -@import (once) "./colortheme-all.less"; -@import (once) "./browser.less"; -@import (once) "./variables.less"; +@import (reference) "./colortheme-all.less"; +@import (reference) "./browser.less"; +@import (reference) "./variables.less"; .alertify_main () { @max-z-index: 2147483647; diff --git a/customize.dist/src/less2/include/avatar.less b/customize.dist/src/less2/include/avatar.less index b935db786..93d3f24c6 100644 --- a/customize.dist/src/less2/include/avatar.less +++ b/customize.dist/src/less2/include/avatar.less @@ -1,4 +1,4 @@ -@import (once) "./tools.less"; +@import (reference) "./tools.less"; .avatar_main (@width) { &.cp-avatar { diff --git a/customize.dist/src/less2/include/checkmark.less b/customize.dist/src/less2/include/checkmark.less index adbc70750..fe80ddfcd 100644 --- a/customize.dist/src/less2/include/checkmark.less +++ b/customize.dist/src/less2/include/checkmark.less @@ -1,4 +1,4 @@ -@import (once) "./colortheme-all.less"; +@import (reference) "./colortheme-all.less"; .checkmark_main(@size) { diff --git a/customize.dist/src/less2/include/colortheme-all.less b/customize.dist/src/less2/include/colortheme-all.less index 4544da76e..be048d7bc 100644 --- a/customize.dist/src/less2/include/colortheme-all.less +++ b/customize.dist/src/less2/include/colortheme-all.less @@ -2,5 +2,5 @@ // create a file: customize/src/less2/include/colortheme.less // override whatever colors you want. When you update, the new colors will be // added ok because the original file is pulled in first. -@import (once) "/customize.dist/src/less2/include/colortheme.less"; -@import (once) "/customize/src/less2/include/colortheme.less"; +@import (reference) "/customize.dist/src/less2/include/colortheme.less"; +@import (reference) "/customize/src/less2/include/colortheme.less"; diff --git a/customize.dist/src/less2/include/creation.less b/customize.dist/src/less2/include/creation.less index e2115288a..b860d0b91 100644 --- a/customize.dist/src/less2/include/creation.less +++ b/customize.dist/src/less2/include/creation.less @@ -1,6 +1,6 @@ -@import (once) "./colortheme-all.less"; -@import (once) "./tools.less"; -@import (once) './icon-colors.less'; +@import (reference) "./colortheme-all.less"; +@import (reference) "./tools.less"; +@import (reference) './icon-colors.less'; .creation_main( @color: @colortheme_default-color, // Color of the text for the toolbar diff --git a/customize.dist/src/less2/include/dropdown.less b/customize.dist/src/less2/include/dropdown.less index 0d3552450..8524e2b7d 100644 --- a/customize.dist/src/less2/include/dropdown.less +++ b/customize.dist/src/less2/include/dropdown.less @@ -1,5 +1,5 @@ -@import (once) "./colortheme-all.less"; -@import (once) "./tools.less"; +@import (reference) "./colortheme-all.less"; +@import (reference) "./tools.less"; /* The container
            - needed to position the dropdown content */ .dropdown_main () { diff --git a/customize.dist/src/less2/include/fileupload.less b/customize.dist/src/less2/include/fileupload.less index 3ed3e793e..5fc357357 100644 --- a/customize.dist/src/less2/include/fileupload.less +++ b/customize.dist/src/less2/include/fileupload.less @@ -1,4 +1,4 @@ -@import (once) './colortheme-all.less'; +@import (reference) './colortheme-all.less'; @import (once) './modal.less'; .fileupload_main () { diff --git a/customize.dist/src/less2/include/framework.less b/customize.dist/src/less2/include/framework.less index 286870991..930a710d1 100644 --- a/customize.dist/src/less2/include/framework.less +++ b/customize.dist/src/less2/include/framework.less @@ -1,12 +1,12 @@ -@import (once) "./colortheme-all.less"; +@import (reference) "./colortheme-all.less"; @import (once) "./toolbar.less"; @import (once) './fileupload.less'; -@import (once) './alertify.less'; -@import (once) './tokenfield.less'; -@import (once) './creation.less'; -@import (once) './tippy.less'; -@import (once) "./checkmark.less"; -@import (once) "./password-input.less"; +@import (reference) './alertify.less'; +@import (reference) './tokenfield.less'; +@import (reference) './creation.less'; +@import (reference) './tippy.less'; +@import (reference) "./checkmark.less"; +@import (reference) "./password-input.less"; .framework_main(@bg-color, @warn-color, @color) { .toolbar_main( diff --git a/customize.dist/src/less2/include/help.less b/customize.dist/src/less2/include/help.less index 0e6e90d87..097c74f79 100644 --- a/customize.dist/src/less2/include/help.less +++ b/customize.dist/src/less2/include/help.less @@ -1,4 +1,4 @@ -@import (once) "./colortheme-all.less"; +@import (reference) "./colortheme-all.less"; .help_main (@color, @bg-color) { .cp-help-container { diff --git a/customize.dist/src/less2/include/icon-colors.less b/customize.dist/src/less2/include/icon-colors.less index 283626cfd..b7a7935c6 100644 --- a/customize.dist/src/less2/include/icon-colors.less +++ b/customize.dist/src/less2/include/icon-colors.less @@ -1,4 +1,4 @@ -@import (once) "./colortheme-all.less"; +@import (reference) "./colortheme-all.less"; .iconColors_main () { // Classes used in common-interface.js .cp-icon-color-pad { color: @colortheme_pad-bg; } diff --git a/customize.dist/src/less2/include/infopages.less b/customize.dist/src/less2/include/infopages.less index 4f3f6d0ad..b824e8cfb 100644 --- a/customize.dist/src/less2/include/infopages.less +++ b/customize.dist/src/less2/include/infopages.less @@ -1,4 +1,4 @@ -@import (once) "./colortheme-all.less"; +@import (reference) "./colortheme-all.less"; @infopages_infobar-height: 64px; @infopages_padding: 32px; diff --git a/customize.dist/src/less2/include/leftside-menu.less b/customize.dist/src/less2/include/leftside-menu.less index 28ae57af4..baca3ac4d 100644 --- a/customize.dist/src/less2/include/leftside-menu.less +++ b/customize.dist/src/less2/include/leftside-menu.less @@ -1,6 +1,6 @@ -@import (once) "./unselectable.less"; -@import (once) "./variables.less"; -@import (once) "./colortheme-all.less"; +@import (reference) "./unselectable.less"; +@import (reference) "./variables.less"; +@import (reference) "./colortheme-all.less"; .leftside-menu_main() { } diff --git a/customize.dist/src/less2/include/limit-bar.less b/customize.dist/src/less2/include/limit-bar.less index b2ea5f230..5f61219c2 100644 --- a/customize.dist/src/less2/include/limit-bar.less +++ b/customize.dist/src/less2/include/limit-bar.less @@ -1,4 +1,4 @@ -@import (once) "./colortheme-all.less"; +@import (reference) "./colortheme-all.less"; .limit-bar_main () { .cp-limit-container { diff --git a/customize.dist/src/less2/include/markdown-toolbar.less b/customize.dist/src/less2/include/markdown-toolbar.less index 4fb466525..fbdaaa4a2 100644 --- a/customize.dist/src/less2/include/markdown-toolbar.less +++ b/customize.dist/src/less2/include/markdown-toolbar.less @@ -1,4 +1,4 @@ -@import (once) "./colortheme-all.less"; +@import (reference) "./colortheme-all.less"; .markdownToolbar_main (@color, @bg-color) { .cp-markdown-toolbar { diff --git a/customize.dist/src/less2/include/modal.less b/customize.dist/src/less2/include/modal.less index e7e39ad96..76e006bf9 100644 --- a/customize.dist/src/less2/include/modal.less +++ b/customize.dist/src/less2/include/modal.less @@ -1,5 +1,5 @@ -@import (once) "./colortheme-all.less"; -@import (once) "./variables.less"; +@import (reference) "./colortheme-all.less"; +@import (reference) "./variables.less"; .modal_base() { font-family: @colortheme_font; diff --git a/customize.dist/src/less2/include/sidebar-layout.less b/customize.dist/src/less2/include/sidebar-layout.less index ef6e1189a..9a038ffe6 100644 --- a/customize.dist/src/less2/include/sidebar-layout.less +++ b/customize.dist/src/less2/include/sidebar-layout.less @@ -1,5 +1,5 @@ -@import (once) "/customize/src/less2/include/colortheme-all.less"; -@import (once) "/customize/src/less2/include/leftside-menu.less"; +@import (reference) "/customize/src/less2/include/colortheme-all.less"; +@import (reference) "/customize/src/less2/include/leftside-menu.less"; @leftside-bg: @colortheme_sidebar-left-bg; @leftside-color: @colortheme_sidebar-left-fg; diff --git a/customize.dist/src/less2/include/tippy.less b/customize.dist/src/less2/include/tippy.less index 7f38af30f..d873b98d8 100644 --- a/customize.dist/src/less2/include/tippy.less +++ b/customize.dist/src/less2/include/tippy.less @@ -1,4 +1,4 @@ -@import (once) './colortheme-all.less'; +@import (reference) './colortheme-all.less'; .tippy_main() { .tippy-tooltip.cryptpad-theme { diff --git a/customize.dist/src/less2/include/tokenfield.less b/customize.dist/src/less2/include/tokenfield.less index 5e518f08c..ad435ad31 100644 --- a/customize.dist/src/less2/include/tokenfield.less +++ b/customize.dist/src/less2/include/tokenfield.less @@ -1,4 +1,4 @@ -@import (once) "./tools.less"; +@import (reference) "./tools.less"; .tokenfield_main () { .ui-autocomplete { diff --git a/customize.dist/src/less2/include/toolbar-history.less b/customize.dist/src/less2/include/toolbar-history.less index 54a3bb0a0..7bee5c0fc 100644 --- a/customize.dist/src/less2/include/toolbar-history.less +++ b/customize.dist/src/less2/include/toolbar-history.less @@ -1,4 +1,4 @@ -@import (once) "./colortheme-all.less"; +@import (reference) "./colortheme-all.less"; .history_main () { .cp-toolbar-history { diff --git a/customize.dist/src/less2/include/toolbar.less b/customize.dist/src/less2/include/toolbar.less index ad696382f..8d3b017e4 100644 --- a/customize.dist/src/less2/include/toolbar.less +++ b/customize.dist/src/less2/include/toolbar.less @@ -1,15 +1,15 @@ -@import (once) "./dropdown.less"; -@import (once) "./colortheme-all.less"; -@import (once) "./browser.less"; -@import (once) "./ckeditor-fix.less"; -@import (once) "./avatar.less"; -@import (once) "./toolbar-history.less"; -@import (once) "./icon-colors.less"; -@import (once) "./tools.less"; -@import (once) "./icons.less"; +@import (reference) "./dropdown.less"; +@import (reference) "./colortheme-all.less"; +@import (reference) "./browser.less"; +@import (reference) "./ckeditor-fix.less"; +@import (reference) "./avatar.less"; +@import (reference) "./toolbar-history.less"; +@import (reference) "./icon-colors.less"; +@import (reference) "./tools.less"; +@import (reference) "./icons.less"; @import (once) "./modal.less"; -@import (once) "./markdown-toolbar.less"; -@import (once) "./help.less"; +@import (reference) "./markdown-toolbar.less"; +@import (reference) "./help.less"; .toolbar_main ( @color: @colortheme_default-color, // Color of the text for the toolbar diff --git a/customize.dist/src/less2/main.less b/customize.dist/src/less2/main.less index 1186465da..d14045194 100644 --- a/customize.dist/src/less2/main.less +++ b/customize.dist/src/less2/main.less @@ -1,4 +1,4 @@ -@import (once) './include/font.less'; +@import (reference) './include/font.less'; .font_neuropolitical(); .font_open-sans(); @@ -15,12 +15,12 @@ body.cp-page-terms { @import "./pages/page-terms.less"; } // Set the HTML style for the apps which shouldn't have a body scrollbar html.cp-app-noscroll { - @import "./include/app-noscroll.less"; + @import (reference) "./include/app-noscroll.less"; .app-noscroll_main(); } // Set the HTML style for printing slides html.cp-app-print { - @import "./include/app-print.less"; + @import (reference) "./include/app-print.less"; .app-print_main(); } diff --git a/customize.dist/src/less2/pages/page-404.less b/customize.dist/src/less2/pages/page-404.less index c6afae5b0..4e26951a1 100644 --- a/customize.dist/src/less2/pages/page-404.less +++ b/customize.dist/src/less2/pages/page-404.less @@ -1,5 +1,5 @@ -@import (once) "../include/colortheme-all.less"; -@import (once) "../include/font.less"; +@import (reference) "../include/colortheme-all.less"; +@import (reference) "../include/font.less"; .font_neuropolitical(); .font_open-sans(); diff --git a/customize.dist/src/less2/pages/page-about.less b/customize.dist/src/less2/pages/page-about.less index 9850b9621..350ffee4a 100644 --- a/customize.dist/src/less2/pages/page-about.less +++ b/customize.dist/src/less2/pages/page-about.less @@ -1,5 +1,5 @@ @import (once) "../include/infopages.less"; -@import (once) "../include/colortheme-all.less"; +@import (reference) "../include/colortheme-all.less"; .infopages_main(); .infopages_topbar(); diff --git a/customize.dist/src/less2/pages/page-contact.less b/customize.dist/src/less2/pages/page-contact.less index 5cfe5245b..4cab7b742 100644 --- a/customize.dist/src/less2/pages/page-contact.less +++ b/customize.dist/src/less2/pages/page-contact.less @@ -1,5 +1,5 @@ @import (once) "../include/infopages.less"; -@import (once) "../include/colortheme-all.less"; +@import (reference) "../include/colortheme-all.less"; .infopages_main(); .infopages_topbar(); diff --git a/customize.dist/src/less2/pages/page-faq.less b/customize.dist/src/less2/pages/page-faq.less index f0861a40d..e08fc42ed 100644 --- a/customize.dist/src/less2/pages/page-faq.less +++ b/customize.dist/src/less2/pages/page-faq.less @@ -1,5 +1,5 @@ @import (once) "../include/infopages.less"; -@import (once) "../include/colortheme-all.less"; +@import (reference) "../include/colortheme-all.less"; .infopages_main(); .infopages_topbar(); diff --git a/customize.dist/src/less2/pages/page-features.less b/customize.dist/src/less2/pages/page-features.less index a65eed039..57c1335cf 100644 --- a/customize.dist/src/less2/pages/page-features.less +++ b/customize.dist/src/less2/pages/page-features.less @@ -1,5 +1,5 @@ @import (once) "../include/infopages.less"; -@import (once) "../include/colortheme-all.less"; +@import (reference) "../include/colortheme-all.less"; .infopages_main(); .infopages_topbar(); diff --git a/customize.dist/src/less2/pages/page-index.less b/customize.dist/src/less2/pages/page-index.less index 75518f5f8..54f8c6275 100644 --- a/customize.dist/src/less2/pages/page-index.less +++ b/customize.dist/src/less2/pages/page-index.less @@ -1,5 +1,5 @@ @import (once) "../include/infopages.less"; -@import (once) "../include/colortheme-all.less"; +@import (reference) "../include/colortheme-all.less"; .infopages_main(); .infopages_topbar(); diff --git a/customize.dist/src/less2/pages/page-login.less b/customize.dist/src/less2/pages/page-login.less index 2f77e74f4..8eec31f67 100644 --- a/customize.dist/src/less2/pages/page-login.less +++ b/customize.dist/src/less2/pages/page-login.less @@ -1,7 +1,7 @@ @import (once) "../include/infopages.less"; -@import (once) "../include/colortheme-all.less"; -@import (once) "../include/alertify.less"; -@import (once) "../include/checkmark.less"; +@import (reference) "../include/colortheme-all.less"; +@import (reference) "../include/alertify.less"; +@import (reference) "../include/checkmark.less"; .infopages_main(); .infopages_topbar(); diff --git a/customize.dist/src/less2/pages/page-privacy.less b/customize.dist/src/less2/pages/page-privacy.less index cfd575173..3abbc43c3 100644 --- a/customize.dist/src/less2/pages/page-privacy.less +++ b/customize.dist/src/less2/pages/page-privacy.less @@ -1,5 +1,5 @@ @import (once) "../include/infopages.less"; -@import (once) "../include/colortheme-all.less"; +@import (reference) "../include/colortheme-all.less"; .infopages_main(); .infopages_topbar(); diff --git a/customize.dist/src/less2/pages/page-register.less b/customize.dist/src/less2/pages/page-register.less index 84944f4df..26c8b0f1f 100644 --- a/customize.dist/src/less2/pages/page-register.less +++ b/customize.dist/src/less2/pages/page-register.less @@ -1,7 +1,7 @@ @import (once) "../include/infopages.less"; -@import (once) "../include/colortheme-all.less"; -@import (once) "../include/alertify.less"; -@import (once) "../include/checkmark.less"; +@import (reference) "../include/colortheme-all.less"; +@import (reference) "../include/alertify.less"; +@import (reference) "../include/checkmark.less"; .infopages_main(); .infopages_topbar(); diff --git a/customize.dist/src/less2/pages/page-terms.less b/customize.dist/src/less2/pages/page-terms.less index a1f8b2955..d16a7d589 100644 --- a/customize.dist/src/less2/pages/page-terms.less +++ b/customize.dist/src/less2/pages/page-terms.less @@ -1,5 +1,5 @@ @import (once) "../include/infopages.less"; -@import (once) "../include/colortheme-all.less"; +@import (reference) "../include/colortheme-all.less"; .infopages_main(); .infopages_topbar(); diff --git a/customize.dist/src/less2/pages/page-what-is-cryptpad.less b/customize.dist/src/less2/pages/page-what-is-cryptpad.less index f08655b9c..0e26f91ed 100644 --- a/customize.dist/src/less2/pages/page-what-is-cryptpad.less +++ b/customize.dist/src/less2/pages/page-what-is-cryptpad.less @@ -1,5 +1,5 @@ @import (once) "../include/infopages.less"; -@import (once) "../include/colortheme-all.less"; +@import (reference) "../include/colortheme-all.less"; .infopages_main(); .infopages_topbar(); diff --git a/www/code/app-code.less b/www/code/app-code.less index f4153e95d..7572cd030 100644 --- a/www/code/app-code.less +++ b/www/code/app-code.less @@ -1,5 +1,5 @@ -@import (once) "../../customize/src/less2/include/browser.less"; -@import (once) "../../customize/src/less2/include/markdown.less"; +@import (reference) "../../customize/src/less2/include/browser.less"; +@import (reference) "../../customize/src/less2/include/markdown.less"; @import (once) "../../customize/src/less2/include/framework.less"; diff --git a/www/common/file-dialog.less b/www/common/file-dialog.less index c27b6a377..be0efab90 100644 --- a/www/common/file-dialog.less +++ b/www/common/file-dialog.less @@ -1,5 +1,5 @@ -@import (once) '../customize/src/less2/include/colortheme-all.less'; -@import '../customize/src/less2/include/modal.less'; +@import (reference) '../customize/src/less2/include/colortheme-all.less'; +@import (once) '../customize/src/less2/include/modal.less'; .fileDialog_main () { #fileDialog { diff --git a/www/contacts/app-contacts.less b/www/contacts/app-contacts.less index 34702d6a3..82254b9a9 100644 --- a/www/contacts/app-contacts.less +++ b/www/contacts/app-contacts.less @@ -1,6 +1,6 @@ -@import (once) "../../customize/src/less2/include/browser.less"; -@import (once) "../../customize/src/less2/include/markdown.less"; -@import (once) '../../customize/src/less2/include/avatar.less'; +@import (reference) "../../customize/src/less2/include/browser.less"; +@import (reference) "../../customize/src/less2/include/markdown.less"; +@import (reference) '../../customize/src/less2/include/avatar.less'; @import (once) '../../customize/src/less2/include/framework.less'; .framework_min_main( diff --git a/www/debug/app-debug.less b/www/debug/app-debug.less index 2a4af9c37..f34dc6264 100644 --- a/www/debug/app-debug.less +++ b/www/debug/app-debug.less @@ -1,7 +1,7 @@ -@import (once) "../../customize/src/less2/include/browser.less"; -@import (once) "../../customize/src/less2/include/markdown.less"; -@import (once) '../../customize/src/less2/include/tools.less'; -@import (once) '../../customize/src/less2/include/tokenfield.less'; +@import (reference) "../../customize/src/less2/include/browser.less"; +@import (reference) "../../customize/src/less2/include/markdown.less"; +@import (reference) '../../customize/src/less2/include/tools.less'; +@import (reference) '../../customize/src/less2/include/tokenfield.less'; @import (once) '../../customize/src/less2/include/framework.less'; .tokenfield_main(); diff --git a/www/drive/app-drive.less b/www/drive/app-drive.less index 8c1ea1fa4..44ac90014 100644 --- a/www/drive/app-drive.less +++ b/www/drive/app-drive.less @@ -1,9 +1,9 @@ -@import (once) "../../customize/src/less2/include/browser.less"; -@import (once) "../../customize/src/less2/include/markdown.less"; -@import (once) '../../customize/src/less2/include/leftside-menu.less'; -@import (once) "../../customize/src/less2/include/tools.less"; -@import (once) "../../customize/src/less2/include/limit-bar.less"; -@import (once) "../../customize/src/less2/include/tokenfield.less"; +@import (reference) "../../customize/src/less2/include/browser.less"; +@import (reference) "../../customize/src/less2/include/markdown.less"; +@import (reference) '../../customize/src/less2/include/leftside-menu.less'; +@import (reference) "../../customize/src/less2/include/tools.less"; +@import (reference) "../../customize/src/less2/include/limit-bar.less"; +@import (reference) "../../customize/src/less2/include/tokenfield.less"; @import (once) '../../customize/src/less2/include/framework.less'; .framework_min_main( diff --git a/www/file/app-file.less b/www/file/app-file.less index a0141293b..963a3e247 100644 --- a/www/file/app-file.less +++ b/www/file/app-file.less @@ -1,6 +1,6 @@ -@import (once) "../../customize/src/less2/include/browser.less"; -@import (once) "../../customize/src/less2/include/markdown.less"; -@import (once) '../../customize/src/less2/include/tokenfield.less'; +@import (reference) "../../customize/src/less2/include/browser.less"; +@import (reference) "../../customize/src/less2/include/markdown.less"; +@import (reference) '../../customize/src/less2/include/tokenfield.less'; @import (once) '../../customize/src/less2/include/framework.less'; .framework_min_main( diff --git a/www/filepicker/app-filepicker.less b/www/filepicker/app-filepicker.less index 5a80661cf..9dbb508df 100644 --- a/www/filepicker/app-filepicker.less +++ b/www/filepicker/app-filepicker.less @@ -1,11 +1,11 @@ -@import (once) '../../customize/src/less2/include/colortheme-all.less'; +@import (reference) '../../customize/src/less2/include/colortheme-all.less'; @import (once) '../../customize/src/less2/include/modal.less'; -@import (once) '../../customize/src/less2/include/icon-colors.less'; +@import (reference) '../../customize/src/less2/include/icon-colors.less'; @import (once) '../../customize/src/less2/include/fileupload.less'; -@import (once) '../../customize/src/less2/include/alertify.less'; -@import (once) '../../customize/src/less2/include/tippy.less'; -@import (once) '../../customize/src/less2/include/checkmark.less'; -@import (once) '../../customize/src/less2/include/password-input.less'; +@import (reference) '../../customize/src/less2/include/alertify.less'; +@import (reference) '../../customize/src/less2/include/tippy.less'; +@import (reference) '../../customize/src/less2/include/checkmark.less'; +@import (reference) '../../customize/src/less2/include/password-input.less'; .iconColors_main(); .fileupload_main(); diff --git a/www/kanban/app-kanban.less b/www/kanban/app-kanban.less index ab49cfda5..24962d232 100644 --- a/www/kanban/app-kanban.less +++ b/www/kanban/app-kanban.less @@ -1,6 +1,6 @@ -@import (once) "../../customize/src/less2/include/browser.less"; +@import (reference) "../../customize/src/less2/include/browser.less"; @import (once) "../../customize/src/less2/include/framework.less"; -@import (once) "../../customize/src/less2/include/tools.less"; +@import (reference) "../../customize/src/less2/include/tools.less"; .framework_main( @bg-color: @colortheme_kanban-bg, @warn-color: @colortheme_kanban-warn, diff --git a/www/poll/app-poll.less b/www/poll/app-poll.less index 0c594395b..31f48523b 100644 --- a/www/poll/app-poll.less +++ b/www/poll/app-poll.less @@ -1,7 +1,7 @@ -@import (once) "../../customize/src/less2/include/browser.less"; -@import (once) "../../customize/src/less2/include/markdown.less"; -@import (once) '../../customize/src/less2/include/tools.less'; -@import (once) '../../customize/src/less2/include/avatar.less'; +@import (reference) "../../customize/src/less2/include/browser.less"; +@import (reference) "../../customize/src/less2/include/markdown.less"; +@import (reference) '../../customize/src/less2/include/tools.less'; +@import (reference) '../../customize/src/less2/include/avatar.less'; @import (once) "../../customize/src/less2/include/framework.less"; diff --git a/www/profile/app-profile.less b/www/profile/app-profile.less index 4bbc377e4..a4eb4735d 100644 --- a/www/profile/app-profile.less +++ b/www/profile/app-profile.less @@ -1,9 +1,9 @@ -@import (once) "../../customize/src/less2/include/browser.less"; -@import (once) "../../customize/src/less2/include/markdown.less"; +@import (reference) "../../customize/src/less2/include/browser.less"; +@import (reference) "../../customize/src/less2/include/markdown.less"; @import (once) '../../customize/src/less2/include/framework.less'; -@import (once) '../../customize/src/less2/include/avatar.less'; -@import (once) '../../customize/src/less2/include/sidebar-layout.less'; +@import (reference) '../../customize/src/less2/include/avatar.less'; +@import (reference) '../../customize/src/less2/include/sidebar-layout.less'; .framework_min_main( @bg-color: @colortheme_profile-bg, diff --git a/www/settings/app-settings.less b/www/settings/app-settings.less index 2cfd48a65..a494a1b80 100644 --- a/www/settings/app-settings.less +++ b/www/settings/app-settings.less @@ -1,8 +1,8 @@ -@import (once) "../../customize/src/less2/include/browser.less"; -@import (once) "../../customize/src/less2/include/markdown.less"; -@import (once) '../../customize/src/less2/include/sidebar-layout.less'; -@import (once) "../../customize/src/less2/include/limit-bar.less"; -@import (once) "../../customize/src/less2/include/creation.less"; +@import (reference) "../../customize/src/less2/include/browser.less"; +@import (reference) "../../customize/src/less2/include/markdown.less"; +@import (reference) '../../customize/src/less2/include/sidebar-layout.less'; +@import (reference) "../../customize/src/less2/include/limit-bar.less"; +@import (reference) "../../customize/src/less2/include/creation.less"; @import (once) '../../customize/src/less2/include/framework.less'; .framework_min_main( diff --git a/www/slide/app-slide.less b/www/slide/app-slide.less index 14090e9bc..bfb470845 100644 --- a/www/slide/app-slide.less +++ b/www/slide/app-slide.less @@ -1,6 +1,6 @@ -@import (once) "../../customize/src/less2/include/browser.less"; -@import (once) "../../customize/src/less2/include/markdown.less"; -@import (once) "../../customize/src/less2/include/mediatag.less"; +@import (reference) "../../customize/src/less2/include/browser.less"; +@import (reference) "../../customize/src/less2/include/markdown.less"; +@import (reference) "../../customize/src/less2/include/mediatag.less"; @import (once) "../../customize/src/less2/include/framework.less"; .mediatag_base(); diff --git a/www/todo/app-todo.less b/www/todo/app-todo.less index 1c3d8ed97..582ea6d44 100644 --- a/www/todo/app-todo.less +++ b/www/todo/app-todo.less @@ -1,6 +1,6 @@ -@import (once) "../../customize/src/less2/include/browser.less"; -@import (once) "../../customize/src/less2/include/markdown.less"; -@import (once) '../../customize/src/less2/include/avatar.less'; +@import (reference) "../../customize/src/less2/include/browser.less"; +@import (reference) "../../customize/src/less2/include/markdown.less"; +@import (reference) '../../customize/src/less2/include/avatar.less'; @import (once) '../../customize/src/less2/include/framework.less'; .framework_min_main( diff --git a/www/whiteboard/app-whiteboard.less b/www/whiteboard/app-whiteboard.less index 1874c7fd3..3b1022655 100644 --- a/www/whiteboard/app-whiteboard.less +++ b/www/whiteboard/app-whiteboard.less @@ -1,6 +1,6 @@ -@import (once) "../../customize/src/less2/include/browser.less"; -@import (once) "../../customize/src/less2/include/markdown.less"; -@import (once) '../../customize/src/less2/include/tools.less'; +@import (reference) "../../customize/src/less2/include/browser.less"; +@import (reference) "../../customize/src/less2/include/markdown.less"; +@import (reference) '../../customize/src/less2/include/tools.less'; @import (once) "../../customize/src/less2/include/framework.less"; .framework_main( diff --git a/www/worker/app-worker.less b/www/worker/app-worker.less index 2e0a9f94e..2efdc8a2f 100644 --- a/www/worker/app-worker.less +++ b/www/worker/app-worker.less @@ -1,6 +1,6 @@ -@import (once) "../../customize/src/less2/include/browser.less"; -@import (once) "../../customize/src/less2/include/markdown.less"; -@import (once) '../../customize/src/less2/include/avatar.less'; +@import (reference) "../../customize/src/less2/include/browser.less"; +@import (reference) "../../customize/src/less2/include/markdown.less"; +@import (reference) '../../customize/src/less2/include/avatar.less'; @import (once) '../../customize/src/less2/include/framework.less'; .framework_min_main(); From a6d3dbf94fb58f05ec303c4a9cae3b69bf4c3581 Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Thu, 12 Jul 2018 19:13:04 +0200 Subject: [PATCH 20/86] Wrapped modal.less into a mixin which gets rid of the last file which emitted CSS --- .../src/less2/include/fileupload.less | 3 +- .../src/less2/include/framework.less | 4 +- customize.dist/src/less2/include/modal.less | 104 +++++++++--------- customize.dist/src/less2/include/toolbar.less | 3 +- www/code/app-code.less | 2 +- www/common/file-dialog.less | 3 +- www/contacts/app-contacts.less | 2 +- www/debug/app-debug.less | 2 +- www/drive/app-drive.less | 2 +- www/file/app-file.less | 2 +- www/filepicker/app-filepicker.less | 5 +- www/kanban/app-kanban.less | 2 +- www/pad/app-pad.less | 2 +- www/poll/app-poll.less | 2 +- www/profile/app-profile.less | 3 +- www/settings/app-settings.less | 2 +- www/slide/app-slide.less | 2 +- www/todo/app-todo.less | 2 +- www/whiteboard/app-whiteboard.less | 2 +- www/worker/app-worker.less | 2 +- 20 files changed, 78 insertions(+), 73 deletions(-) diff --git a/customize.dist/src/less2/include/fileupload.less b/customize.dist/src/less2/include/fileupload.less index 5fc357357..bc4787869 100644 --- a/customize.dist/src/less2/include/fileupload.less +++ b/customize.dist/src/less2/include/fileupload.less @@ -1,8 +1,9 @@ @import (reference) './colortheme-all.less'; -@import (once) './modal.less'; +@import (reference) './modal.less'; .fileupload_main () { /* Upload status table */ + modal_main(); #cp-fileupload { .modal_base(); position: absolute; diff --git a/customize.dist/src/less2/include/framework.less b/customize.dist/src/less2/include/framework.less index 930a710d1..af2ccf3b8 100644 --- a/customize.dist/src/less2/include/framework.less +++ b/customize.dist/src/less2/include/framework.less @@ -1,6 +1,6 @@ @import (reference) "./colortheme-all.less"; -@import (once) "./toolbar.less"; -@import (once) './fileupload.less'; +@import (reference) "./toolbar.less"; +@import (reference) './fileupload.less'; @import (reference) './alertify.less'; @import (reference) './tokenfield.less'; @import (reference) './creation.less'; diff --git a/customize.dist/src/less2/include/modal.less b/customize.dist/src/less2/include/modal.less index 76e006bf9..154c8d1ad 100644 --- a/customize.dist/src/less2/include/modal.less +++ b/customize.dist/src/less2/include/modal.less @@ -17,62 +17,64 @@ } } -.cp-modal-container { - display: none; - - z-index: 100000; //Z modal container - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - background-color: @colortheme_modal-dim; - - .cp-modal { - background-color: @colortheme_modal-bg; - color: @colortheme_modal-fg; - box-shadow: @variables_shadow; - - padding: @variables_padding; +.modal_main() { + .cp-modal-container { + display: none; + z-index: 100000; //Z modal container position: absolute; - top: 15vh; bottom: 15vh; - left: 10vw; right: 10vw; + top: 0; + bottom: 0; + left: 0; + right: 0; + background-color: @colortheme_modal-dim; - overflow: auto; + .cp-modal { + background-color: @colortheme_modal-bg; + color: @colortheme_modal-fg; + box-shadow: @variables_shadow; - font-family: @colortheme_font; - text-align: center; - - & > p { - margin-bottom: 1em; - } - - .cp-modal-form { - display: flex; - flex-wrap: wrap; - align-items: center; - justify-content: center; - } - - input { - background-color: @colortheme_modal-input; - color: @colortheme_modal-input-fg; - border: 0; - padding: 8px 12px; - margin: 1em; - width: 300px; - } - - .cp-modal-close { - text-shadow: none; - color: inherit; + padding: @variables_padding; position: absolute; - top: 0; - right: 0; - margin: @variables_padding; - cursor: pointer; + top: 15vh; bottom: 15vh; + left: 10vw; right: 10vw; + + overflow: auto; + + font-family: @colortheme_font; + text-align: center; + + & > p { + margin-bottom: 1em; + } + + .cp-modal-form { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: center; + } + + input { + background-color: @colortheme_modal-input; + color: @colortheme_modal-input-fg; + border: 0; + padding: 8px 12px; + margin: 1em; + width: 300px; + } + + .cp-modal-close { + text-shadow: none; + color: inherit; + + position: absolute; + top: 0; + right: 0; + margin: @variables_padding; + cursor: pointer; + } } } -} +} \ No newline at end of file diff --git a/customize.dist/src/less2/include/toolbar.less b/customize.dist/src/less2/include/toolbar.less index 8d3b017e4..3587b6eaf 100644 --- a/customize.dist/src/less2/include/toolbar.less +++ b/customize.dist/src/less2/include/toolbar.less @@ -7,7 +7,7 @@ @import (reference) "./icon-colors.less"; @import (reference) "./tools.less"; @import (reference) "./icons.less"; -@import (once) "./modal.less"; +@import (reference) "./modal.less"; @import (reference) "./markdown-toolbar.less"; @import (reference) "./help.less"; @@ -32,6 +32,7 @@ .iconColors_main(); .markdownToolbar_main(@color, @bg-color); .help_main(@color, @bg-color); + .modal_main(); .cp-toolbar-container { display: flex; diff --git a/www/code/app-code.less b/www/code/app-code.less index 7572cd030..a8c78fc02 100644 --- a/www/code/app-code.less +++ b/www/code/app-code.less @@ -1,6 +1,6 @@ @import (reference) "../../customize/src/less2/include/browser.less"; @import (reference) "../../customize/src/less2/include/markdown.less"; -@import (once) "../../customize/src/less2/include/framework.less"; +@import (reference) "../../customize/src/less2/include/framework.less"; .framework_main( diff --git a/www/common/file-dialog.less b/www/common/file-dialog.less index be0efab90..8f47f6024 100644 --- a/www/common/file-dialog.less +++ b/www/common/file-dialog.less @@ -1,7 +1,8 @@ @import (reference) '../customize/src/less2/include/colortheme-all.less'; -@import (once) '../customize/src/less2/include/modal.less'; +@import (reference) '../customize/src/less2/include/modal.less'; .fileDialog_main () { + .modal_main(); #fileDialog { display: none; .cp-modal { diff --git a/www/contacts/app-contacts.less b/www/contacts/app-contacts.less index 82254b9a9..3dd868eea 100644 --- a/www/contacts/app-contacts.less +++ b/www/contacts/app-contacts.less @@ -1,7 +1,7 @@ @import (reference) "../../customize/src/less2/include/browser.less"; @import (reference) "../../customize/src/less2/include/markdown.less"; @import (reference) '../../customize/src/less2/include/avatar.less'; -@import (once) '../../customize/src/less2/include/framework.less'; +@import (reference) '../../customize/src/less2/include/framework.less'; .framework_min_main( @bg-color: @colortheme_friends-bg, diff --git a/www/debug/app-debug.less b/www/debug/app-debug.less index f34dc6264..35ea42f2a 100644 --- a/www/debug/app-debug.less +++ b/www/debug/app-debug.less @@ -2,7 +2,7 @@ @import (reference) "../../customize/src/less2/include/markdown.less"; @import (reference) '../../customize/src/less2/include/tools.less'; @import (reference) '../../customize/src/less2/include/tokenfield.less'; -@import (once) '../../customize/src/less2/include/framework.less'; +@import (reference) '../../customize/src/less2/include/framework.less'; .tokenfield_main(); .framework_min_main(); diff --git a/www/drive/app-drive.less b/www/drive/app-drive.less index 44ac90014..4137d0dbe 100644 --- a/www/drive/app-drive.less +++ b/www/drive/app-drive.less @@ -4,7 +4,7 @@ @import (reference) "../../customize/src/less2/include/tools.less"; @import (reference) "../../customize/src/less2/include/limit-bar.less"; @import (reference) "../../customize/src/less2/include/tokenfield.less"; -@import (once) '../../customize/src/less2/include/framework.less'; +@import (reference) '../../customize/src/less2/include/framework.less'; .framework_min_main( @bg-color: @colortheme_drive-bg, diff --git a/www/file/app-file.less b/www/file/app-file.less index 963a3e247..41853e847 100644 --- a/www/file/app-file.less +++ b/www/file/app-file.less @@ -1,7 +1,7 @@ @import (reference) "../../customize/src/less2/include/browser.less"; @import (reference) "../../customize/src/less2/include/markdown.less"; @import (reference) '../../customize/src/less2/include/tokenfield.less'; -@import (once) '../../customize/src/less2/include/framework.less'; +@import (reference) '../../customize/src/less2/include/framework.less'; .framework_min_main( @bg-color: @colortheme_file-bg, diff --git a/www/filepicker/app-filepicker.less b/www/filepicker/app-filepicker.less index 9dbb508df..712700451 100644 --- a/www/filepicker/app-filepicker.less +++ b/www/filepicker/app-filepicker.less @@ -1,7 +1,7 @@ @import (reference) '../../customize/src/less2/include/colortheme-all.less'; -@import (once) '../../customize/src/less2/include/modal.less'; +@import (reference) '../../customize/src/less2/include/modal.less'; @import (reference) '../../customize/src/less2/include/icon-colors.less'; -@import (once) '../../customize/src/less2/include/fileupload.less'; +@import (reference) '../../customize/src/less2/include/fileupload.less'; @import (reference) '../../customize/src/less2/include/alertify.less'; @import (reference) '../../customize/src/less2/include/tippy.less'; @import (reference) '../../customize/src/less2/include/checkmark.less'; @@ -13,6 +13,7 @@ .tippy_main(); .checkmark_main(20px); .password_main(); +.modal_main(); #cp-filepicker-dialog { display: none; diff --git a/www/kanban/app-kanban.less b/www/kanban/app-kanban.less index 24962d232..417f4fd14 100644 --- a/www/kanban/app-kanban.less +++ b/www/kanban/app-kanban.less @@ -1,5 +1,5 @@ @import (reference) "../../customize/src/less2/include/browser.less"; -@import (once) "../../customize/src/less2/include/framework.less"; +@import (reference) "../../customize/src/less2/include/framework.less"; @import (reference) "../../customize/src/less2/include/tools.less"; .framework_main( @bg-color: @colortheme_kanban-bg, diff --git a/www/pad/app-pad.less b/www/pad/app-pad.less index fa7d1142a..74862650c 100644 --- a/www/pad/app-pad.less +++ b/www/pad/app-pad.less @@ -1,4 +1,4 @@ -@import (once) "../../customize/src/less2/include/framework.less"; +@import (reference) "../../customize/src/less2/include/framework.less"; .framework_main( @bg-color: @colortheme_pad-bg, diff --git a/www/poll/app-poll.less b/www/poll/app-poll.less index 31f48523b..7ccf11901 100644 --- a/www/poll/app-poll.less +++ b/www/poll/app-poll.less @@ -2,7 +2,7 @@ @import (reference) "../../customize/src/less2/include/markdown.less"; @import (reference) '../../customize/src/less2/include/tools.less'; @import (reference) '../../customize/src/less2/include/avatar.less'; -@import (once) "../../customize/src/less2/include/framework.less"; +@import (reference) "../../customize/src/less2/include/framework.less"; .framework_main( diff --git a/www/profile/app-profile.less b/www/profile/app-profile.less index a4eb4735d..45684abd9 100644 --- a/www/profile/app-profile.less +++ b/www/profile/app-profile.less @@ -1,7 +1,6 @@ @import (reference) "../../customize/src/less2/include/browser.less"; @import (reference) "../../customize/src/less2/include/markdown.less"; -@import (once) '../../customize/src/less2/include/framework.less'; - +@import (reference) '../../customize/src/less2/include/framework.less'; @import (reference) '../../customize/src/less2/include/avatar.less'; @import (reference) '../../customize/src/less2/include/sidebar-layout.less'; diff --git a/www/settings/app-settings.less b/www/settings/app-settings.less index a494a1b80..fce502376 100644 --- a/www/settings/app-settings.less +++ b/www/settings/app-settings.less @@ -3,7 +3,7 @@ @import (reference) '../../customize/src/less2/include/sidebar-layout.less'; @import (reference) "../../customize/src/less2/include/limit-bar.less"; @import (reference) "../../customize/src/less2/include/creation.less"; -@import (once) '../../customize/src/less2/include/framework.less'; +@import (reference) '../../customize/src/less2/include/framework.less'; .framework_min_main( @bg-color: @colortheme_settings-bg, diff --git a/www/slide/app-slide.less b/www/slide/app-slide.less index bfb470845..1126e32a4 100644 --- a/www/slide/app-slide.less +++ b/www/slide/app-slide.less @@ -1,7 +1,7 @@ @import (reference) "../../customize/src/less2/include/browser.less"; @import (reference) "../../customize/src/less2/include/markdown.less"; @import (reference) "../../customize/src/less2/include/mediatag.less"; -@import (once) "../../customize/src/less2/include/framework.less"; +@import (reference) "../../customize/src/less2/include/framework.less"; .mediatag_base(); .framework_main( diff --git a/www/todo/app-todo.less b/www/todo/app-todo.less index 582ea6d44..12d44e950 100644 --- a/www/todo/app-todo.less +++ b/www/todo/app-todo.less @@ -1,7 +1,7 @@ @import (reference) "../../customize/src/less2/include/browser.less"; @import (reference) "../../customize/src/less2/include/markdown.less"; @import (reference) '../../customize/src/less2/include/avatar.less'; -@import (once) '../../customize/src/less2/include/framework.less'; +@import (reference) '../../customize/src/less2/include/framework.less'; .framework_min_main( @bg-color: @colortheme_todo-bg, diff --git a/www/whiteboard/app-whiteboard.less b/www/whiteboard/app-whiteboard.less index 3b1022655..03b5d7ea2 100644 --- a/www/whiteboard/app-whiteboard.less +++ b/www/whiteboard/app-whiteboard.less @@ -1,7 +1,7 @@ @import (reference) "../../customize/src/less2/include/browser.less"; @import (reference) "../../customize/src/less2/include/markdown.less"; @import (reference) '../../customize/src/less2/include/tools.less'; -@import (once) "../../customize/src/less2/include/framework.less"; +@import (reference) "../../customize/src/less2/include/framework.less"; .framework_main( @bg-color: @colortheme_whiteboard-bg, diff --git a/www/worker/app-worker.less b/www/worker/app-worker.less index 2efdc8a2f..769e1235a 100644 --- a/www/worker/app-worker.less +++ b/www/worker/app-worker.less @@ -1,7 +1,7 @@ @import (reference) "../../customize/src/less2/include/browser.less"; @import (reference) "../../customize/src/less2/include/markdown.less"; @import (reference) '../../customize/src/less2/include/avatar.less'; -@import (once) '../../customize/src/less2/include/framework.less'; +@import (reference) '../../customize/src/less2/include/framework.less'; .framework_min_main(); From 507e5b18e983461e54ba4b9fab100344c184b011 Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Thu, 12 Jul 2018 19:22:32 +0200 Subject: [PATCH 21/86] Remove all less includes where no mixin or variable is used after --- www/contacts/app-contacts.less | 2 -- www/debug/app-debug.less | 3 --- www/drive/app-drive.less | 1 - www/file/app-file.less | 2 -- www/poll/app-poll.less | 3 --- www/profile/app-profile.less | 3 --- www/settings/app-settings.less | 2 -- www/slide/app-slide.less | 1 - www/todo/app-todo.less | 3 --- www/whiteboard/app-whiteboard.less | 2 -- www/worker/app-worker.less | 4 +--- 11 files changed, 1 insertion(+), 25 deletions(-) diff --git a/www/contacts/app-contacts.less b/www/contacts/app-contacts.less index 3dd868eea..66fdb7a8b 100644 --- a/www/contacts/app-contacts.less +++ b/www/contacts/app-contacts.less @@ -1,5 +1,3 @@ -@import (reference) "../../customize/src/less2/include/browser.less"; -@import (reference) "../../customize/src/less2/include/markdown.less"; @import (reference) '../../customize/src/less2/include/avatar.less'; @import (reference) '../../customize/src/less2/include/framework.less'; diff --git a/www/debug/app-debug.less b/www/debug/app-debug.less index 35ea42f2a..c1e8a25b3 100644 --- a/www/debug/app-debug.less +++ b/www/debug/app-debug.less @@ -1,6 +1,3 @@ -@import (reference) "../../customize/src/less2/include/browser.less"; -@import (reference) "../../customize/src/less2/include/markdown.less"; -@import (reference) '../../customize/src/less2/include/tools.less'; @import (reference) '../../customize/src/less2/include/tokenfield.less'; @import (reference) '../../customize/src/less2/include/framework.less'; diff --git a/www/drive/app-drive.less b/www/drive/app-drive.less index 4137d0dbe..eabc6df08 100644 --- a/www/drive/app-drive.less +++ b/www/drive/app-drive.less @@ -1,5 +1,4 @@ @import (reference) "../../customize/src/less2/include/browser.less"; -@import (reference) "../../customize/src/less2/include/markdown.less"; @import (reference) '../../customize/src/less2/include/leftside-menu.less'; @import (reference) "../../customize/src/less2/include/tools.less"; @import (reference) "../../customize/src/less2/include/limit-bar.less"; diff --git a/www/file/app-file.less b/www/file/app-file.less index 41853e847..9d78d5ec3 100644 --- a/www/file/app-file.less +++ b/www/file/app-file.less @@ -1,5 +1,3 @@ -@import (reference) "../../customize/src/less2/include/browser.less"; -@import (reference) "../../customize/src/less2/include/markdown.less"; @import (reference) '../../customize/src/less2/include/tokenfield.less'; @import (reference) '../../customize/src/less2/include/framework.less'; diff --git a/www/poll/app-poll.less b/www/poll/app-poll.less index 7ccf11901..69713cce9 100644 --- a/www/poll/app-poll.less +++ b/www/poll/app-poll.less @@ -1,10 +1,7 @@ -@import (reference) "../../customize/src/less2/include/browser.less"; -@import (reference) "../../customize/src/less2/include/markdown.less"; @import (reference) '../../customize/src/less2/include/tools.less'; @import (reference) '../../customize/src/less2/include/avatar.less'; @import (reference) "../../customize/src/less2/include/framework.less"; - .framework_main( @bg-color: @colortheme_poll-bg, @warn-color: @colortheme_poll-warn, diff --git a/www/profile/app-profile.less b/www/profile/app-profile.less index 45684abd9..0fce9ea7b 100644 --- a/www/profile/app-profile.less +++ b/www/profile/app-profile.less @@ -1,7 +1,4 @@ -@import (reference) "../../customize/src/less2/include/browser.less"; -@import (reference) "../../customize/src/less2/include/markdown.less"; @import (reference) '../../customize/src/less2/include/framework.less'; -@import (reference) '../../customize/src/less2/include/avatar.less'; @import (reference) '../../customize/src/less2/include/sidebar-layout.less'; .framework_min_main( diff --git a/www/settings/app-settings.less b/www/settings/app-settings.less index fce502376..3e8f1ed92 100644 --- a/www/settings/app-settings.less +++ b/www/settings/app-settings.less @@ -1,5 +1,3 @@ -@import (reference) "../../customize/src/less2/include/browser.less"; -@import (reference) "../../customize/src/less2/include/markdown.less"; @import (reference) '../../customize/src/less2/include/sidebar-layout.less'; @import (reference) "../../customize/src/less2/include/limit-bar.less"; @import (reference) "../../customize/src/less2/include/creation.less"; diff --git a/www/slide/app-slide.less b/www/slide/app-slide.less index 1126e32a4..8a56db15f 100644 --- a/www/slide/app-slide.less +++ b/www/slide/app-slide.less @@ -1,4 +1,3 @@ -@import (reference) "../../customize/src/less2/include/browser.less"; @import (reference) "../../customize/src/less2/include/markdown.less"; @import (reference) "../../customize/src/less2/include/mediatag.less"; @import (reference) "../../customize/src/less2/include/framework.less"; diff --git a/www/todo/app-todo.less b/www/todo/app-todo.less index 12d44e950..191252f53 100644 --- a/www/todo/app-todo.less +++ b/www/todo/app-todo.less @@ -1,6 +1,3 @@ -@import (reference) "../../customize/src/less2/include/browser.less"; -@import (reference) "../../customize/src/less2/include/markdown.less"; -@import (reference) '../../customize/src/less2/include/avatar.less'; @import (reference) '../../customize/src/less2/include/framework.less'; .framework_min_main( diff --git a/www/whiteboard/app-whiteboard.less b/www/whiteboard/app-whiteboard.less index 03b5d7ea2..c05405fa0 100644 --- a/www/whiteboard/app-whiteboard.less +++ b/www/whiteboard/app-whiteboard.less @@ -1,5 +1,3 @@ -@import (reference) "../../customize/src/less2/include/browser.less"; -@import (reference) "../../customize/src/less2/include/markdown.less"; @import (reference) '../../customize/src/less2/include/tools.less'; @import (reference) "../../customize/src/less2/include/framework.less"; diff --git a/www/worker/app-worker.less b/www/worker/app-worker.less index 769e1235a..47295b0aa 100644 --- a/www/worker/app-worker.less +++ b/www/worker/app-worker.less @@ -1,6 +1,4 @@ -@import (reference) "../../customize/src/less2/include/browser.less"; -@import (reference) "../../customize/src/less2/include/markdown.less"; -@import (reference) '../../customize/src/less2/include/avatar.less'; +@import (reference) "../../customize/src/less2/include/colortheme-all.less"; @import (reference) '../../customize/src/less2/include/framework.less'; .framework_min_main(); From 6a80f49fe06913beb3707d4495c5caa1bae63913 Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 13 Jul 2018 14:47:53 +0200 Subject: [PATCH 22/86] Don't load expired or deleted shared folders --- www/common/outer/async-store.js | 43 ++++++++++++++++++++++++++++++--- www/common/proxy-manager.js | 7 +++--- www/common/userObject.js | 8 +++++- www/drive/inner.js | 1 + 4 files changed, 51 insertions(+), 8 deletions(-) diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index f746399fa..2ada4ecc6 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -366,7 +366,7 @@ define([ Store.getDeletedPads = function (clientId, data, cb) { if (!store.anon_rpc) { return void cb({error: 'ANON_RPC_NOT_READY'}); } - var list = getCanonicalChannelList(true); + var list = (data && data.list) || getCanonicalChannelList(true); if (!Array.isArray(list)) { return void cb({error: 'INVALID_FILE_LIST'}); } @@ -1313,11 +1313,45 @@ define([ ////////////////////////////////////////////////////////////////// var loadSharedFolders = function (waitFor) { + var w = waitFor(); store.sharedFolders = {}; var shared = Util.find(store.proxy, ['drive', UserObject.SHARED_FOLDERS]) || {}; - Object.keys(shared).forEach(function (id) { - var sf = shared[id]; - loadSharedFolder(id, sf, waitFor()); + // Check if any of our shared folder is expired or deleted by its owner. + // If we don't check now, Listmap will create an empty proxy if it no longer exists on + // the server. + nThen(function (waitFor) { + var edPublic = store.proxy.edPublic; + var checkExpired = Object.keys(shared).filter(function (fId) { + var d = shared[fId]; + return (Array.isArray(d.owners) && d.owners.length && + (!edPublic || d.owners.indexOf(edPublic) === -1)) + || (d.expire && d.expire < (+new Date())); + }).map(function (fId) { + return shared[fId].channel; + }); + Store.getDeletedPads(null, {list: checkExpired}, waitFor(function (chans) { + if (chans && chans.error) { return void console.error(chans.error); } + if (!Array.isArray(chans) || !chans.length) { return; } + var toDelete = []; + Object.keys(shared).forEach(function (fId) { + if (chans.indexOf(shared[fId].channel) !== -1 + && toDelete.indexOf(fId) === -1) { + toDelete.push(fId); + } + }); + toDelete.forEach(function (fId) { + var paths = store.userObject.findFile(Number(fId)); + store.userObject.delete(paths, waitFor(), true); + delete shared[fId]; + }); + })); + }).nThen(function () { + Object.keys(shared).forEach(function (id) { + var sf = shared[id]; + loadSharedFolder(id, sf, function () { + w(); + }); + }); }); }; @@ -1355,6 +1389,7 @@ define([ progress: progress }); }); + Store.initAnonRpc(null, null, waitFor()); }).nThen(function (waitFor) { postMessage(clientId, 'LOADING_DRIVE', { state: 3 diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index ca927cfe3..a89dfd206 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -2,8 +2,9 @@ define([ '/common/userObject.js', '/common/common-util.js', '/common/common-hash.js', + '/customize/messages.js', '/bower_components/nthen/index.js', -], function (UserObject, Util, Hash, nThen) { +], function (UserObject, Util, Hash, Messages, nThen) { var getConfig = function (Env) { @@ -361,8 +362,8 @@ define([ // 2b. load the proxy Env.loadSharedFolder(id, folderData, waitFor(function (rt, metadata) { - if (data.name && !rt.proxy.metadata) { // Creating a new shared folder - rt.proxy.metadata = {title: data.name}; + if (!rt.proxy.metadata) { // Creating a new shared folder + rt.proxy.metadata = {title: data.name || Messages.fm_newFolder}; // XXX } // If we're importing a folder, check its serverside metadata if (data.folderData && metadata) { diff --git a/www/common/userObject.js b/www/common/userObject.js index 7a1576f96..d373e89d6 100644 --- a/www/common/userObject.js +++ b/www/common/userObject.js @@ -40,9 +40,12 @@ define([ var log = config.log || logging; var logError = config.logError || logging; var debug = exp.debug = config.debug || logging; + + exp.fixFiles = function () {}; // Overriden by OuterFO + var error = exp.error = function() { - exp.fixFiles(); console.error.apply(console, arguments); + exp.fixFiles(); }; if (config.outer) { @@ -139,6 +142,9 @@ define([ // Data from filesData var getTitle = exp.getTitle = function (file, type) { + if (isSharedFolder(file)) { + return '??'; // XXX + } var data = getFileData(file); if (!file || !data || !(data.href || data.roHref)) { error("getTitle called with a non-existing file id: ", file, data); diff --git a/www/drive/inner.js b/www/drive/inner.js index d74d61d06..1fa7e5eb0 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -3192,6 +3192,7 @@ define([ var title = manager.getTitle(id); titles.push(title); var paths = manager.findFile(id); + console.log(title, id, paths); manager.delete(paths, refresh); }); if (!titles.length) { return; } From 4706b8a9deb1dbe2c9cf60f891ad82ee7d4fc16b Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 13 Jul 2018 15:01:03 +0200 Subject: [PATCH 23/86] Store newly created pads in the correct (shared) folder --- www/common/cryptpad-common.js | 3 ++- www/common/proxy-manager.js | 4 ---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 266402fcc..3011618cd 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -523,7 +523,8 @@ define([ if (common.initialPath) { if (!data.path) { - data.path = common.initialPath; + data.path = Array.isArray(common.initialPath) ? common.initialPath + : decodeURIComponent(common.initialPath).split(','); delete common.initialPath; } } diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index a89dfd206..f7bd3eb85 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -319,7 +319,6 @@ define([ }; // Add a folder/subfolder var _addSharedFolder = function (Env, data, cb) { - console.log(data); data = data || {}; var resolved = _resolvePath(Env, data.path); if (!resolved || !resolved.userObject) { return void cb({error: 'E_NOTFOUND'}); } @@ -628,10 +627,8 @@ define([ p = resolved.path; } var todo = function () { - console.log('here'); uo.pushData(pad, function (e, id) { if (e) { return void cb(e); } - console.log(id, p); uo.add(id, p); cb(); }); @@ -721,7 +718,6 @@ define([ }, cb); }; var addSharedFolderInner = function (Env, path, data, cb) { - console.log(data); return void Env.sframeChan.query("Q_DRIVE_USEROBJECT", { cmd: "addSharedFolder", data: { From b5c2eb8a9c35f8dfc68d5f4a6a8098ce451d6ef9 Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 13 Jul 2018 19:24:49 +0200 Subject: [PATCH 24/86] Automatically refresh the drive when a change occurs in a shared folder --- www/common/outer/async-store.js | 52 ++++++++++++++++++++------------- www/common/proxy-manager.js | 10 +++++-- www/common/userObject.js | 1 + www/drive/inner.js | 43 ++++++++++++++++++++++----- 4 files changed, 74 insertions(+), 32 deletions(-) diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 2ada4ecc6..c009459ab 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -28,6 +28,7 @@ define([ var postMessage = function () {}; var broadcast = function () {}; var sendDriveEvent = function () {}; + var registerProxyEvents = function () {}; var storeHash; @@ -1168,6 +1169,9 @@ define([ store.manager.addProxy(id, rt.proxy, info.leave); cb(rt, info.metadata); }); + if (store.driveEvents) { + registerProxyEvents(rt.proxy, id); + } return rt; }; Store.addSharedFolder = function (clientId, data, cb) { @@ -1231,32 +1235,41 @@ define([ // Special events - var driveEventInit = false; sendDriveEvent = function (q, data, sender) { driveEventClients.forEach(function (cId) { if (cId === sender) { return; } postMessage(cId, q, data); }); }; + registerProxyEvents = function (proxy, fId) { + proxy.on('change', [], function (o, n, p) { + sendDriveEvent('DRIVE_CHANGE', { + id: fId, + old: o, + new: n, + path: p + }); + }); + proxy.on('remove', [], function (o, p) { + sendDriveEvent('DRIVE_REMOVE', { + id: fId, + old: o, + path: p + }); + }); + }; + Store._subscribeToDrive = function (clientId) { if (driveEventClients.indexOf(clientId) === -1) { driveEventClients.push(clientId); } - if (!driveEventInit) { - store.proxy.on('change', [], function (o, n, p) { - sendDriveEvent('DRIVE_CHANGE', { - old: o, - new: n, - path: p - }); - }); - store.proxy.on('remove', [], function (o, p) { - sendDriveEvent(clientId, 'DRIVE_REMOVE', { - old: o, - path: p - }); + if (!store.driveEvents) { + store.driveEvents = true; + registerProxyEvents(store.proxy); + Object.keys(store.manager.folders).forEach(function (fId) { + var proxy = store.manager.folders[fId].proxy; + registerProxyEvents(proxy, fId); }); - driveEventInit = true; } }; @@ -1313,7 +1326,6 @@ define([ ////////////////////////////////////////////////////////////////// var loadSharedFolders = function (waitFor) { - var w = waitFor(); store.sharedFolders = {}; var shared = Util.find(store.proxy, ['drive', UserObject.SHARED_FOLDERS]) || {}; // Check if any of our shared folder is expired or deleted by its owner. @@ -1345,14 +1357,12 @@ define([ delete shared[fId]; }); })); - }).nThen(function () { + }).nThen(function (waitFor) { Object.keys(shared).forEach(function (id) { var sf = shared[id]; - loadSharedFolder(id, sf, function () { - w(); - }); + loadSharedFolder(id, sf, waitFor()); }); - }); + }).nThen(waitFor()); }; var onReady = function (clientId, returned, cb) { diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index f7bd3eb85..bfd3fc89e 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -681,9 +681,11 @@ define([ }; }; - /* - Inner only - */ + /* ============================================================================= + * ============================================================================= + * Inner only + * ============================================================================= + * ============================================================================= */ var renameInner = function (Env, path, newName, cb) { return void Env.sframeChan.query("Q_DRIVE_USEROBJECT", { @@ -752,6 +754,7 @@ define([ var findChannels = _findChannels; var getFileData = _getFileData; + var getUserObjectPath = _getUserObjectPath; var find = function (Env, path) { var resolved = _resolvePath(Env, path); @@ -925,6 +928,7 @@ define([ findChannels: callWithEnv(findChannels), getSharedFolderData: callWithEnv(getSharedFolderData), isInSharedFolder: callWithEnv(isInSharedFolder), + getUserObjectPath: callWithEnv(getUserObjectPath), // Generic isFile: callWithEnv(isFile), isFolder: callWithEnv(isFolder), diff --git a/www/common/userObject.js b/www/common/userObject.js index d373e89d6..9d3cc738a 100644 --- a/www/common/userObject.js +++ b/www/common/userObject.js @@ -237,6 +237,7 @@ define([ }); _getFiles['hrefArray'] = function () { var ret = []; + if (sharedFolder) { return ret; } getHrefArray().forEach(function (c) { ret = ret.concat(_getFiles[c]()); }); diff --git a/www/drive/inner.js b/www/drive/inner.js index 1fa7e5eb0..b8a95d8b0 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -3134,32 +3134,60 @@ define([ sframeChan.on('EV_DRIVE_CHANGE', function (data) { if (history.isHistoryMode) { return; } - var path = data.path; + + var path = data.path.slice(); + var originalPath = data.path.slice(); + + // Fix the path if this is about a shared folder + if (data.id && manager.folders[data.id]) { + var uoPath = manager.getUserObjectPath(manager.folders[data.id].userObject); + if (uoPath) { + Array.prototype.unshift.apply(path, uoPath); + path.unshift('drive'); + } + } + if (path[0] !== 'drive') { return false; } path = path.slice(1); + if (originalPath[0] === 'drive') { originalPath = originalPath.slice(1); } + var cPath = currentPath.slice(); - if ((manager.isPathIn(cPath, ['hrefArray', TRASH]) && cPath[0] === path[0]) || + if (originalPath.length && originalPath[0] === FILES_DATA) { + onRefresh.refresh(); + } else if ((manager.isPathIn(cPath, ['hrefArray', TRASH]) && cPath[0] === path[0]) || (path.length >= cPath.length && manager.isSubpath(path, cPath))) { // Reload after a few ms to make sure all the change events have been received onRefresh.refresh(); - } else if (path.length && path[0] === FILES_DATA) { - onRefresh.refresh(); + } else { + APP.resetTree(); } - APP.resetTree(); return false; }); sframeChan.on('EV_DRIVE_REMOVE', function (data) { if (history.isHistoryMode) { return; } - var path = data.path; + + var path = data.path.slice(); + + // Fix the path if this is about a shared folder + if (data.id && manager.folders[data.id]) { + var uoPath = manager.getUserObjectPath(manager.folders[data.id].userObject); + if (uoPath) { + Array.prototype.unshift.apply(path, uoPath); + path.unshift('drive'); + } + } + if (path[0] !== 'drive') { return false; } path = path.slice(1); + var cPath = currentPath.slice(); if ((manager.isPathIn(cPath, ['hrefArray', TRASH]) && cPath[0] === path[0]) || (path.length >= cPath.length && manager.isSubpath(path, cPath))) { // Reload after a few to make sure all the change events have been received onRefresh.refresh(); + } else { + APP.resetTree(); } - APP.resetTree(); return false; }); @@ -3192,7 +3220,6 @@ define([ var title = manager.getTitle(id); titles.push(title); var paths = manager.findFile(id); - console.log(title, id, paths); manager.delete(paths, refresh); }); if (!titles.length) { return; } From 0d5ac0586620a8d0e93365c55067fafca07a8a4b Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Sat, 14 Jul 2018 15:15:23 +0200 Subject: [PATCH 25/86] refactoring of the less infrastructure --- customize.dist/src/less2/404.less | 40 - .../src/less2/include/alertify.less | 7 +- .../src/less2/include/app-noscroll.less | 29 +- .../src/less2/include/app-print.less | 79 +- customize.dist/src/less2/include/avatar.less | 69 +- .../src/less2/include/checkmark.less | 36 +- .../src/less2/include/creation.less | 16 +- .../src/less2/include/dropdown.less | 3 + .../src/less2/include/fileupload.less | 6 +- customize.dist/src/less2/include/font.less | 16 +- .../src/less2/include/framework.less | 29 +- customize.dist/src/less2/include/help.less | 19 +- .../src/less2/include/icon-colors.less | 3 + customize.dist/src/less2/include/icons.less | 3 +- .../src/less2/include/infopages.less | 159 +- .../src/less2/include/limit-bar.less | 3 + .../src/less2/include/markdown-toolbar.less | 20 - .../src/less2/include/markdown.less | 27 +- customize.dist/src/less2/include/modal.less | 3 + .../src/less2/include/password-input.less | 3 + .../src/less2/include/sidebar-layout.less | 16 +- customize.dist/src/less2/include/tippy.less | 3 + .../src/less2/include/tokenfield.less | 3 + .../src/less2/include/toolbar-history.less | 3 + customize.dist/src/less2/include/toolbar.less | 124 +- customize.dist/src/less2/main.less | 44 - customize.dist/src/less2/pages/page-404.less | 3 +- .../src/less2/pages/page-about.less | 198 +-- .../src/less2/pages/page-contact.less | 155 +- customize.dist/src/less2/pages/page-faq.less | 143 +- .../src/less2/pages/page-features.less | 144 +- .../src/less2/pages/page-index.less | 354 ++-- .../src/less2/pages/page-login.less | 113 +- .../src/less2/pages/page-privacy.less | 84 +- .../src/less2/pages/page-register.less | 224 +-- .../src/less2/pages/page-terms.less | 7 +- .../less2/pages/page-what-is-cryptpad.less | 71 +- customize.dist/src/less2/readme.md | 50 +- customize.dist/template.js | 2 +- www/code/app-code.less | 14 +- www/code/inner.js | 2 + www/common/LessLoader.js | 37 +- www/common/file-dialog.less | 2 +- www/common/sframe-app-framework.js | 1 - www/contacts/app-contacts.less | 12 +- www/contacts/inner.js | 2 +- www/debug/app-debug.less | 6 +- www/debug/inner.js | 2 +- www/drive/app-drive.less | 1433 ++++++++--------- www/drive/inner.js | 2 +- www/file/app-file.less | 261 +-- www/file/inner.js | 2 +- www/filepicker/app-filepicker.less | 121 +- www/filepicker/inner.js | 2 +- www/kanban/app-kanban.less | 10 +- www/kanban/inner.js | 2 + www/pad/app-pad.less | 38 +- www/pad/inner.js | 2 +- www/poll/app-poll.less | 1105 ++++++------- www/poll/inner.js | 2 +- www/profile/app-profile.less | 16 +- www/profile/inner.js | 2 +- www/settings/app-settings.less | 19 +- www/settings/inner.js | 2 +- www/slide/app-slide.less | 716 ++++---- www/slide/inner.js | 2 +- www/todo/app-todo.less | 14 +- www/todo/inner.js | 2 +- www/whiteboard/app-whiteboard.less | 14 +- www/whiteboard/inner.js | 1 + www/worker/app-worker.less | 5 +- www/worker/inner.js | 2 +- 72 files changed, 3128 insertions(+), 3036 deletions(-) delete mode 100644 customize.dist/src/less2/404.less delete mode 100644 customize.dist/src/less2/include/markdown-toolbar.less delete mode 100644 customize.dist/src/less2/main.less diff --git a/customize.dist/src/less2/404.less b/customize.dist/src/less2/404.less deleted file mode 100644 index 1aabf463b..000000000 --- a/customize.dist/src/less2/404.less +++ /dev/null @@ -1,40 +0,0 @@ -@import (reference) './include/font.less'; -.font_neuropolitical(); -.font_open-sans(); - -body.cp-page-index { @import "./pages/page-index.less"; } -body.cp-page-contact { @import "./pages/page-contact.less"; } -body.cp-page-login { @import "./pages/page-login.less"; } -body.cp-page-register { @import "./pages/page-register.less"; } -body.cp-page-what-is-cryptpad { @import "./pages/page-what-is-cryptpad.less"; } -body.cp-page-about { @import "./pages/page-about.less"; } -body.cp-page-privacy { @import "./pages/page-privacy.less"; } -body.cp-page-terms { @import "./pages/page-terms.less"; } - -// Set the HTML style for the apps which shouldn't have a body scrollbar -html.cp-app-noscroll { - @import (reference) "./include/app-noscroll.less"; - .app-noscroll_main(); -} -// Set the HTML style for printing slides -html.cp-app-print { - @import (reference) "./include/app-print.less"; - .app-print_main(); -} - -body.cp-readonly .cp-hidden-if-readonly { display: none !important; } - -body.cp-app-drive { @import "../../../drive/app-drive.less"; } -body.cp-app-pad { @import "../../../pad/app-pad.less"; } -body.cp-app-code { @import "../../../code/app-code.less"; } -body.cp-app-slide { @import "../../../slide/app-slide.less"; } -body.cp-app-file { @import "../../../file/app-file.less"; } -body.cp-app-filepicker { @import "../../../filepicker/app-filepicker.less"; } -body.cp-app-contacts { @import "../../../contacts/app-contacts.less"; } -body.cp-app-poll { @import "../../../poll/app-poll.less"; } -body.cp-app-whiteboard { @import "../../../whiteboard/app-whiteboard.less"; } -body.cp-app-todo { @import "../../../todo/app-todo.less"; } -body.cp-app-profile { @import "../../../profile/app-profile.less"; } -body.cp-app-settings { @import "../../../settings/app-settings.less"; } -body.cp-app-debug { @import "../../../debug/app-debug.less"; } - diff --git a/customize.dist/src/less2/include/alertify.less b/customize.dist/src/less2/include/alertify.less index c35c46a98..61da93d95 100644 --- a/customize.dist/src/less2/include/alertify.less +++ b/customize.dist/src/less2/include/alertify.less @@ -2,7 +2,10 @@ @import (reference) "./browser.less"; @import (reference) "./variables.less"; -.alertify_main () { +.alertify_main() { + --LessLoader_require: LessLoader_currentFile(); +}; +& { @max-z-index: 2147483647; @alertify-fore: @colortheme_modal-fg; @alertify-base: @colortheme_modal-bg; @@ -406,4 +409,4 @@ } } } -} +} \ No newline at end of file diff --git a/customize.dist/src/less2/include/app-noscroll.less b/customize.dist/src/less2/include/app-noscroll.less index f0a760b5f..c9fc59bbf 100644 --- a/customize.dist/src/less2/include/app-noscroll.less +++ b/customize.dist/src/less2/include/app-noscroll.less @@ -1,14 +1,8 @@ -// html -.app-noscroll_main () { - height: 100%; - width: 100%; - padding: 0px; - margin: 0px; - overflow: hidden; - box-sizing: border-box; - position: relative; - border: 0; - body { +.app-noscroll_main() { + --LessLoader_require: LessLoader_currentFile(); +} +& { + .cp-app-noscroll { height: 100%; width: 100%; padding: 0px; @@ -17,6 +11,15 @@ box-sizing: border-box; position: relative; border: 0; + body { + height: 100%; + width: 100%; + padding: 0px; + margin: 0px; + overflow: hidden; + box-sizing: border-box; + position: relative; + border: 0; + } } -} - +} \ No newline at end of file diff --git a/customize.dist/src/less2/include/app-print.less b/customize.dist/src/less2/include/app-print.less index 957170044..a22a10300 100644 --- a/customize.dist/src/less2/include/app-print.less +++ b/customize.dist/src/less2/include/app-print.less @@ -1,46 +1,51 @@ -.app-print_main () { - // Current scope is - @media print { - height: auto; - max-height: none; - overflow: visible; - display: block; - @page { - margin: 0; - size: landscape; - } - // Slide app - body.cp-app-slide { +.app-print_main() { + --LessLoader_require: LessLoader_currentFile(); +} +& { + .cp-app-print { + // Current scope is + @media print { + height: auto; + max-height: none; + overflow: visible; display: block; - .CodeMirror, #cme_toolbox { - display: none; + @page { + margin: 0; + size: landscape; } - * { - visibility: hidden; - height: auto; - max-height: none; - } - .cp-app-slide-viewer #cp-app-slide-print { + // Slide app + body.cp-app-slide { display: block; - visibility: visible; + .CodeMirror, #cme_toolbox { + display: none; + } * { + visibility: hidden; + height: auto; + max-height: none; + } + .cp-app-slide-viewer #cp-app-slide-print { + display: block; visibility: visible; + * { + visibility: visible; + } + } + .cp-app-slide-viewer #cp-app-slide-modal { + display: none !important; + } + .cp-app-slide-viewer { + flex: 1 !important; + overflow: visible !important; + } + .cp-toolbar-userlist-drawer { + display: none !important; + } + #cp-app-slide-editor { + height: auto; + display: block; } - } - .cp-app-slide-viewer #cp-app-slide-modal { - display: none !important; - } - .cp-app-slide-viewer { - flex: 1 !important; - overflow: visible !important; - } - .cp-toolbar-userlist-drawer { - display: none !important; - } - #cp-app-slide-editor { - height: auto; - display: block; } } } -} +} \ No newline at end of file diff --git a/customize.dist/src/less2/include/avatar.less b/customize.dist/src/less2/include/avatar.less index 93d3f24c6..367034972 100644 --- a/customize.dist/src/less2/include/avatar.less +++ b/customize.dist/src/less2/include/avatar.less @@ -1,40 +1,45 @@ @import (reference) "./tools.less"; +.avatar_main(@width) { + --LessLoader_require: LessLoader_currentFile(); -.avatar_main (@width) { + --avatar-width: @width; + --avatar-font-size: @width / 1.2; +} +& { &.cp-avatar { - overflow: hidden; - text-overflow: ellipsis; - font-size: 16px; - display: flex; - align-items: center; - .cp-avatar-default, media-tag { - display: inline-flex; - width: @width; - height: @width; - justify-content: center; - align-items: center; - border-radius: 4px; overflow: hidden; - box-sizing: content-box; - } - .cp-avatar-default { - .tools_unselectable(); - background: white; - color: black; - font-size: @width/1.2; - } - media-tag { - min-height: @width; - min-width: @width; - max-height: @width; - max-width: @width; - img { - min-width: 100%; - min-height: 100%; - max-width: none; - max-height: none; // To override 'media-tag img' in slide.less + text-overflow: ellipsis; + font-size: 16px; + display: flex; + align-items: center; + .cp-avatar-default, media-tag { + display: inline-flex; + width: var(--avatar-width); + height: var(--avatar-width); + justify-content: center; + align-items: center; + border-radius: 4px; + overflow: hidden; + box-sizing: content-box; + } + .cp-avatar-default { + .tools_unselectable(); + background: white; + color: black; + font-size: var(--avatar-font-size); + } + media-tag { + min-height: var(--avatar-width); + min-width: var(--avatar-width); + max-height: var(--avatar-width); + max-width: var(--avatar-width); + img { + min-width: 100%; + min-height: 100%; + max-width: none; + max-height: none; // To override 'media-tag img' in slide.less + } } - } } } diff --git a/customize.dist/src/less2/include/checkmark.less b/customize.dist/src/less2/include/checkmark.less index fe80ddfcd..2f606f7ec 100644 --- a/customize.dist/src/less2/include/checkmark.less +++ b/customize.dist/src/less2/include/checkmark.less @@ -1,11 +1,17 @@ @import (reference) "./colortheme-all.less"; .checkmark_main(@size) { + --LessLoader_require: LessLoader_currentFile(); - @width: round(@size / 8); + --checkmark-size: @size; + --checkmark-width: round(@size / 8); @dim1: round(@size / 3); - @dim2: round(2 * @size / 3); - @top: round(@size / 12) - 1; + --checkmark-dim1: round(@size / 3); + --checkmark-dim2: round(2 * @size / 3); + --checkmark-top: round(@size / 12) - 1; + --checkmark-radio-size: @dim1 * 3; +} +& { // Text .cp-checkmark { margin: 0; @@ -58,8 +64,8 @@ .cp-checkmark-mark { margin-right: 10px; position: relative; - height: @size; - width: @size; + height: var(--checkmark-size); + width: var(--checkmark-size); background-color: @colortheme_checkmark-back0; display: flex; justify-content: center; @@ -68,12 +74,12 @@ &:after { content: ""; display: none; - margin-top: @top; - width: @dim1; - height: @dim2; + margin-top: var(--checkmark-top); + width: var(--checkmark-dim1); + height: var(--checkmark-dim2); transform: rotate(45deg); border: solid @colortheme_checkmark-col1; - border-width: 0 @width @width 0; + border-width: 0 var(--checkmark-width) var(--checkmark-width) 0; position: absolute; } &:focus { @@ -129,12 +135,12 @@ } } - @radio-size: @dim1 * 3; + .cp-radio-mark { margin-right: 10px; position: relative; - height: @radio-size; - width: @radio-size; + height: var(--checkmark-radio-size); + width: var(--checkmark-radio-size); background-color: @colortheme_checkmark-back0; border-radius: 50%; display: flex; @@ -147,12 +153,12 @@ content: ""; border-radius: 50%; background: white; - width: @dim1; - height: @dim1; + width: var(--checkmark-dim1); + height: var(--checkmark-dim1); //transform: rotate(45deg); //border: solid @colortheme_checkmark-col1; - //border-width: 0 @width @width 0; + //border-width: 0 var(--checkmark-width) var(--checkmark-width) 0; } &:focus { //border-color: #FF007C !important; diff --git a/customize.dist/src/less2/include/creation.less b/customize.dist/src/less2/include/creation.less index b860d0b91..bb1d38958 100644 --- a/customize.dist/src/less2/include/creation.less +++ b/customize.dist/src/less2/include/creation.less @@ -1,3 +1,4 @@ +@import (reference) "./browser.less"; @import (reference) "./colortheme-all.less"; @import (reference) "./tools.less"; @import (reference) './icon-colors.less'; @@ -7,6 +8,13 @@ @bg-color: @colortheme_default-bg, // color of the toolbar background @warn-color: @colortheme_default-warn, // color of the warning text in the toolbar ) { + --LessLoader_require: LessLoader_currentFile(); + + --creation-color: @color; + --creation-bg-color: @bg-color; + // --creation-warn-color: @warn-color; // unused +} +& { @colortheme_creation-modal-bg: #fff; @colortheme_creation-modal: #666; @colortheme_creation-modal-title: @colortheme_loading-bg; @@ -259,10 +267,10 @@ border: 1px solid transparent; &.cp-creation-template-selected { - color: @color !important; - background-color: @bg-color !important; + color: var(--creation-color) !important; + background-color: var(--creation-bg-color) !important; .fa { - color: @color; + color: var(--creation-color); } } @@ -293,7 +301,7 @@ max-width: 100%; } .fa { - color: @bg-color; + color: var(--creation-bg-color); cursor: pointer; width: 100px; height: 100px; diff --git a/customize.dist/src/less2/include/dropdown.less b/customize.dist/src/less2/include/dropdown.less index 8524e2b7d..ac393fe3a 100644 --- a/customize.dist/src/less2/include/dropdown.less +++ b/customize.dist/src/less2/include/dropdown.less @@ -3,6 +3,9 @@ /* The container
            - needed to position the dropdown content */ .dropdown_main () { + --LessLoader_require: LessLoader_currentFile(); +} +& { .cp-dropdown-container { @dropdown_font: @colortheme_app-font-size @colortheme_font; position: relative; diff --git a/customize.dist/src/less2/include/fileupload.less b/customize.dist/src/less2/include/fileupload.less index bc4787869..c10abeec4 100644 --- a/customize.dist/src/less2/include/fileupload.less +++ b/customize.dist/src/less2/include/fileupload.less @@ -2,8 +2,11 @@ @import (reference) './modal.less'; .fileupload_main () { + --LessLoader_require: LessLoader_currentFile(); + .modal_main(); +} +& { /* Upload status table */ - modal_main(); #cp-fileupload { .modal_base(); position: absolute; @@ -55,4 +58,3 @@ } } } - diff --git a/customize.dist/src/less2/include/font.less b/customize.dist/src/less2/include/font.less index ec8e77f0f..6dc4dc129 100644 --- a/customize.dist/src/less2/include/font.less +++ b/customize.dist/src/less2/include/font.less @@ -1,9 +1,11 @@ -.font_neuropolitical () { - @font-face { - font-family: Neuropolitical; - src: url("/customize/fonts/neuropolitical.ttf"); - } +.font_main () { + --LessLoader_require: LessLoader_currentFile(); } -.font_open-sans () { - @import (once) '/customize/fonts/open-sans.less'; + +// Fonts need to go on the global scope +@font-face { + font-family: Neuropolitical; + src: url("/customize/fonts/neuropolitical.ttf"); } + +@import (once) '/customize/fonts/open-sans.less'; \ No newline at end of file diff --git a/customize.dist/src/less2/include/framework.less b/customize.dist/src/less2/include/framework.less index af2ccf3b8..36db08a61 100644 --- a/customize.dist/src/less2/include/framework.less +++ b/customize.dist/src/less2/include/framework.less @@ -7,15 +7,27 @@ @import (reference) './tippy.less'; @import (reference) "./checkmark.less"; @import (reference) "./password-input.less"; +@import (reference) './font.less'; +@import (reference) "./app-print.less"; +@import (reference) "./app-noscroll.less"; .framework_main(@bg-color, @warn-color, @color) { + --LessLoader_require: LessLoader_currentFile(); + // Set the HTML style for the apps which shouldn't have a body scrollbar + .app-noscroll_main(); + + // Set the HTML style for printing slides + .app-print_main(); + + .font_main(); + .toolbar_main( @bg-color: @bg-color, @warn-color: @warn-color, @color: @color ); - .fileupload_main(); .alertify_main(); + .fileupload_main(); .tokenfield_main(); .tippy_main(); .checkmark_main(20px); @@ -26,13 +38,22 @@ @color: @color ); font: @colortheme_app-font; -} +}; .framework_min_main( @color: @colortheme_default-color, // Color of the text for the toolbar @bg-color: @colortheme_default-bg, // color of the toolbar background @warn-color: @colortheme_default-warn, // color of the warning text in the toolbar ) { + --LessLoader_require: LessLoader_currentFile(); + // Set the HTML style for the apps which shouldn't have a body scrollbar + .app-noscroll_main(); + + // Set the HTML style for printing slides + .app-print_main(); + + .font_main(); + .toolbar_main( @bg-color: @bg-color, @warn-color: @warn-color, @@ -46,4 +67,6 @@ font: @colortheme_app-font; } - +& { + body.cp-readonly .cp-hidden-if-readonly { display: none !important; } +} \ No newline at end of file diff --git a/customize.dist/src/less2/include/help.less b/customize.dist/src/less2/include/help.less index 097c74f79..cd54aaff2 100644 --- a/customize.dist/src/less2/include/help.less +++ b/customize.dist/src/less2/include/help.less @@ -1,9 +1,17 @@ @import (reference) "./colortheme-all.less"; .help_main (@color, @bg-color) { + --LessLoader_require: LessLoader_currentFile(); + + --help-bg-color-l15: lighten(@bg-color, 15%); + --help-bg-color-spin: spin(@bg-color, 180); + --help-bg-color-spin-d10: darken(spin(@bg-color, 180), 10%); + --help-bg-color-spin-l10: lighten(spin(@bg-color, 180), 10%); +} +& { .cp-help-container { position: relative; - background-color: lighten(@bg-color, 15%); + background-color: var(--help-bg-color-l15); &.cp-help-hidden { display: none; } @@ -14,14 +22,13 @@ right: 5px; } .cp-help-text { - color: contrast(lighten(@bg-color, 15%), #fff, #000); //@color; + color: contrast(var(--help-bg-color-l15), #fff, #000); //@color; margin: 0; padding: 15px; a { //color: darken(@colortheme_link-color, 30%); - @spin: spin(lighten(@bg-color, 15%), 180); - color: contrast(lighten(@bg-color, 15%), lighten(@spin, 10%), darken(@spin, 10%)); - //color: darken(spin(lighten(@bg-color, 15%), 180), 10%); + color: contrast(var(--help-bg-color-l15), var(--help-bg-color-spin-l10), var(--help-bg-color-spin-d10)); + //color: darken(spin(var(--help-bg-color-l15), 180), 10%); } h1 { font-size: 20px; @@ -35,4 +42,4 @@ ul, ol, p { margin: 0; } } } -} +} \ No newline at end of file diff --git a/customize.dist/src/less2/include/icon-colors.less b/customize.dist/src/less2/include/icon-colors.less index b7a7935c6..e18578c6a 100644 --- a/customize.dist/src/less2/include/icon-colors.less +++ b/customize.dist/src/less2/include/icon-colors.less @@ -1,5 +1,8 @@ @import (reference) "./colortheme-all.less"; .iconColors_main () { + --LessLoader_require: LessLoader_currentFile(); +} +& { // Classes used in common-interface.js .cp-icon-color-pad { color: @colortheme_pad-bg; } .cp-icon-color-code { color: @colortheme_code-bg; } diff --git a/customize.dist/src/less2/include/icons.less b/customize.dist/src/less2/include/icons.less index c2ddfef32..1068f59ba 100644 --- a/customize.dist/src/less2/include/icons.less +++ b/customize.dist/src/less2/include/icons.less @@ -38,5 +38,4 @@ } } } -} - +} \ No newline at end of file diff --git a/customize.dist/src/less2/include/infopages.less b/customize.dist/src/less2/include/infopages.less index b824e8cfb..eb600bf52 100644 --- a/customize.dist/src/less2/include/infopages.less +++ b/customize.dist/src/less2/include/infopages.less @@ -1,10 +1,25 @@ @import (reference) "./colortheme-all.less"; +@import (reference) "./font.less"; -@infopages_infobar-height: 64px; -@infopages_padding: 32px; +.infopages_link () { + text-decoration: none; + color: #0275D8; + cursor: pointer; + display: inline-flex; + &:hover { + transform: scale(1.05); + } +} -// Basic setup for info pages, this should be used at the global level .infopages_main () { + --LessLoader_require: LessLoader_currentFile(); +} +body { + .font_main(); + @infopages_infobar-height: 64px; + @infopages_padding: 32px; + + // Basic setup for info pages, this should be used at the global level background-color: @colortheme_info-background; a { color: @cryptpad_color_blue; @@ -100,20 +115,8 @@ border-top: 2px solid #fff; } } -}; -.infopages_link () { - text-decoration: none; - color: #0275D8; - cursor: pointer; - display: inline-flex; - &:hover { - transform: scale(1.05); - } -} - -// Apply this to the top bar div -.infopages_topbar () { + // Apply this to the top bar div .cp-topbar { background: #fff; z-index: 10000; //Z infopage toolbar @@ -149,71 +152,71 @@ margin-right: 0.5em; } } -} -// navigation top bar -.navbar { - background: #fff; - .navbar-brand { - display: block; - background-image: url(/customize/CryptPad_logo_color.svg); - background-repeat: no-repeat; - background-size: contain; - height: 50px; - width: 250px; - @media (max-width: 326px) { - width: 180px; - } - margin-right: 0; - } - a { - border: 2px solid transparent; - white-space: nowrap; - } - .nav-link { - padding: 0.5em 0.7em; - &:hover { - color: @cryptpad_color_light_blue; + // navigation top bar + .navbar { + background: #fff; + .navbar-brand { + display: block; + background-image: url(/customize/CryptPad_logo_color.svg); + background-repeat: no-repeat; + background-size: contain; + height: 50px; + width: 250px; + @media (max-width: 326px) { + width: 180px; + } + margin-right: 0; + } + a { + border: 2px solid transparent; + white-space: nowrap; + } + .nav-link { + padding: 0.5em 0.7em; + &:hover { + color: @cryptpad_color_light_blue; + } + } + .cp-register-btn { + border: 2px solid #4591C4; + display: inline-block; + } + button:focus { + outline: none; + } + .navbar-toggler { + margin-top: 10px; + color: #4591C4; } } - .cp-register-btn { - border: 2px solid #4591C4; - display: inline-block; - } - button:focus { - outline: none; - } - .navbar-toggler { - margin-top: 10px; - color: #4591C4; - } -} -@media (max-width: 1000px) { - #menuCollapse { - text-align: right; -/* @media (min-width: 576px) { - top: 100%; - background: rgba(255,255,255,0.8); - position: absolute; - right: 0px; - padding: 0 20px; - z-index: 1; - } -*/ - } - .navbar-nav a { - text-align: right !important; - } - .cp-register-btn { - margin-right: 13px; - text-align: center; + @media (max-width: 1000px) { + #menuCollapse { + text-align: right; + /* @media (min-width: 576px) { + top: 100%; + background: rgba(255,255,255,0.8); + position: absolute; + right: 0px; + padding: 0 20px; + z-index: 1; + } + */ + } + .navbar-nav a { + text-align: right !important; + } + .cp-register-btn { + margin-right: 13px; + text-align: center; + } } -} -//footer general styles + //footer general styles -.footer-title { - font-weight: bold; - font-size: 1.2em; - color: #1E1F1F; -} + .footer-title { + font-weight: bold; + font-size: 1.2em; + color: #1E1F1F; + } +} \ No newline at end of file diff --git a/customize.dist/src/less2/include/limit-bar.less b/customize.dist/src/less2/include/limit-bar.less index 5f61219c2..3ed7bd454 100644 --- a/customize.dist/src/less2/include/limit-bar.less +++ b/customize.dist/src/less2/include/limit-bar.less @@ -1,6 +1,9 @@ @import (reference) "./colortheme-all.less"; .limit-bar_main () { + --LessLoader_require: LessLoader_currentFile(); +} +& { .cp-limit-container { @colortheme_green: #5cb85c; display: inline-flex; diff --git a/customize.dist/src/less2/include/markdown-toolbar.less b/customize.dist/src/less2/include/markdown-toolbar.less deleted file mode 100644 index fbdaaa4a2..000000000 --- a/customize.dist/src/less2/include/markdown-toolbar.less +++ /dev/null @@ -1,20 +0,0 @@ -@import (reference) "./colortheme-all.less"; - -.markdownToolbar_main (@color, @bg-color) { - .cp-markdown-toolbar { - height: @toolbar_line-height; - background-color: lighten(@bg-color, 20%); - display: none; - button { - height: @toolbar_line-height !important; - outline: 0; - color: @color; - .toolbar_button; - font: normal normal normal 14px/1 FontAwesome; - &:hover { - background-color: lighten(@bg-color, 8%); - } - &.cp-markdown-help { float: right; } - } - } -} diff --git a/customize.dist/src/less2/include/markdown.less b/customize.dist/src/less2/include/markdown.less index 470f81a82..39be15426 100644 --- a/customize.dist/src/less2/include/markdown.less +++ b/customize.dist/src/less2/include/markdown.less @@ -1,3 +1,15 @@ +.markdown_main() { + blockquote { + background: #e5e5e5; + padding: 10px; + border-left: 3px solid #999; + padding-right: 0; + p { margin: 0; } + blockquote { margin: 0; } + } + // todo ul, ol +} + .markdown_preformatted-code (@color: #333) { pre > code { display: block; @@ -21,17 +33,4 @@ } } } -} - -.markdown_main() { - blockquote { - background: #e5e5e5; - padding: 10px; - border-left: 3px solid #999; - padding-right: 0; - p { margin: 0; } - blockquote { margin: 0; } - } -} -// todo ul, ol - +} \ No newline at end of file diff --git a/customize.dist/src/less2/include/modal.less b/customize.dist/src/less2/include/modal.less index 154c8d1ad..3ab463b1d 100644 --- a/customize.dist/src/less2/include/modal.less +++ b/customize.dist/src/less2/include/modal.less @@ -18,6 +18,9 @@ } .modal_main() { + --LessLoader_require: LessLoader_currentFile(); +} +& { .cp-modal-container { display: none; diff --git a/customize.dist/src/less2/include/password-input.less b/customize.dist/src/less2/include/password-input.less index 8836476fd..a2f2fb044 100644 --- a/customize.dist/src/less2/include/password-input.less +++ b/customize.dist/src/less2/include/password-input.less @@ -1,4 +1,7 @@ .password_main() { + --LessLoader_require: LessLoader_currentFile(); +} +& { .cp-password-container { display: flex; align-items: center; diff --git a/customize.dist/src/less2/include/sidebar-layout.less b/customize.dist/src/less2/include/sidebar-layout.less index 9a038ffe6..07471183a 100644 --- a/customize.dist/src/less2/include/sidebar-layout.less +++ b/customize.dist/src/less2/include/sidebar-layout.less @@ -1,18 +1,22 @@ @import (reference) "/customize/src/less2/include/colortheme-all.less"; @import (reference) "/customize/src/less2/include/leftside-menu.less"; -@leftside-bg: @colortheme_sidebar-left-bg; -@leftside-color: @colortheme_sidebar-left-fg; -@rightside-color: @colortheme_sidebar-right-fg; -@description-color: @colortheme_sidebar-description; - @sidebar_button-width: 400px; - .sidebar-layout_main() { + --LessLoader_require: LessLoader_currentFile(); + + // This is way too broad to put in the global scope input[type="text"], input[type="password"] { padding-left: 10px; } +} +& { + @leftside-bg: @colortheme_sidebar-left-bg; + @leftside-color: @colortheme_sidebar-left-fg; + @rightside-color: @colortheme_sidebar-right-fg; + @description-color: @colortheme_sidebar-description; + #cp-sidebarlayout-container { font-size: 16px; display: flex; diff --git a/customize.dist/src/less2/include/tippy.less b/customize.dist/src/less2/include/tippy.less index d873b98d8..794159ba7 100644 --- a/customize.dist/src/less2/include/tippy.less +++ b/customize.dist/src/less2/include/tippy.less @@ -1,6 +1,9 @@ @import (reference) './colortheme-all.less'; .tippy_main() { + --LessLoader_require: LessLoader_currentFile(); +} +& { .tippy-tooltip.cryptpad-theme { /* Your styling here. Example: */ background-color: white; diff --git a/customize.dist/src/less2/include/tokenfield.less b/customize.dist/src/less2/include/tokenfield.less index ad435ad31..faa302b0a 100644 --- a/customize.dist/src/less2/include/tokenfield.less +++ b/customize.dist/src/less2/include/tokenfield.less @@ -1,6 +1,9 @@ @import (reference) "./tools.less"; .tokenfield_main () { + --LessLoader_require: LessLoader_currentFile(); +} +& { .ui-autocomplete { z-index: 100001; // alertify + 1 } diff --git a/customize.dist/src/less2/include/toolbar-history.less b/customize.dist/src/less2/include/toolbar-history.less index 7bee5c0fc..cb41c2112 100644 --- a/customize.dist/src/less2/include/toolbar-history.less +++ b/customize.dist/src/less2/include/toolbar-history.less @@ -1,6 +1,9 @@ @import (reference) "./colortheme-all.less"; .history_main () { + --LessLoader_require: LessLoader_currentFile(); +} +& { .cp-toolbar-history { display: none; text-align: center; diff --git a/customize.dist/src/less2/include/toolbar.less b/customize.dist/src/less2/include/toolbar.less index 3587b6eaf..d3e57981e 100644 --- a/customize.dist/src/less2/include/toolbar.less +++ b/customize.dist/src/less2/include/toolbar.less @@ -8,7 +8,6 @@ @import (reference) "./tools.less"; @import (reference) "./icons.less"; @import (reference) "./modal.less"; -@import (reference) "./markdown-toolbar.less"; @import (reference) "./help.less"; .toolbar_main ( @@ -17,7 +16,37 @@ @warn-color: @colortheme_default-warn, // color of the warning text in the toolbar @barWidth: 600px // width of the toolbar ) { + --LessLoader_require: LessLoader_currentFile(); + --toolbar-color: @color; + --toolbar-color-l20: lighten(@color, 20%); + --toolbar-color-d20: darken(@color, 20%); + --toolbar-color-d15: darken(@color, 15%); + + --toolbar-bg-color: @bg-color; + --toolbar-bg-color-l8: lighten(@bg-color, 8%); + --toolbar-bg-color-l20: lighten(@bg-color, 20%); + --toolbar-bg-color-d5: darken(@bg-color, 5%); + --toolbar-bg-color-d10: darken(@bg-color, 10%); + --toolbar-bg-color-d15: darken(@bg-color, 15%); + + --toolbar-warn-color: @warn-color; + + @media screen and (max-width: @barWidth) { + .cp-toolbar-rightside { + flex-wrap: wrap; + height: auto; + width: 100%; + } + } + + .help_main(@color, @bg-color); + .dropdown_main(); + .history_main(); + .iconColors_main(); + .modal_main(); +}; +& { @toolbar_line-height: 32px; @toolbar_top-height: 64px; @toolbar_button-font: @colortheme_app-font; @@ -26,13 +55,24 @@ // this is a workaround .fa-shhare-alt:before { content: "\f1e0"; } - .dropdown_main(); .ckeditor_fix(); - .history_main(); - .iconColors_main(); - .markdownToolbar_main(@color, @bg-color); - .help_main(@color, @bg-color); - .modal_main(); + + .cp-markdown-toolbar { + height: @toolbar_line-height; + background-color: var(--toolbar-bg-color-l20); + display: none; + button { + height: @toolbar_line-height !important; + outline: 0; + color: var(--toolbar-color); + .toolbar_button; + font: normal normal normal 14px/1 FontAwesome; + &:hover { + background-color: var(--toolbar-bg-color-l8); + } + &.cp-markdown-help { float: right; } + } + } .cp-toolbar-container { display: flex; @@ -66,7 +106,7 @@ } .cp-toolbar-userlist-drawer { - background-color: @bg-color; + background-color: var(--toolbar-bg-color); font: @colortheme_app-font-size @colortheme_font; min-width: 175px; width: 175px; @@ -254,31 +294,31 @@ } .cp-toolbar-userlist-drawer { - background-color: @bg-color; - color: @color; + background-color: var(--toolbar-bg-color); + color: var(--toolbar-color); .cp-toolbar-userlist-drawer-close { - color: @color; + color: var(--toolbar-color); } h2 { - background-color: darken(@bg-color, 10%); - color: @color; + background-color: var(--toolbar-bg-color-d10); + color: var(--toolbar-color); } .cp-toolbar-userlist-name-input { - background-color: darken(@bg-color, 10%); - color: @color; + background-color: var(--toolbar-bg-color-d10); + color: var(--toolbar-color); } .cp-toolbar-userlist-name-edit { - color: contrast(@color, - lighten(@color, 20%), - darken(@color, 20%)); + color: contrast(var(--toolbar-color), + var(--toolbar-color-l20), + var(--toolbar-color-d20)); background: transparent; &:hover { - color: @color; + color: var(--toolbar-color); } } .cp-toolbar-userlist-friend { &:hover { - color: darken(@color, 15%); + color: var(--toolbar-color-d15); } } } @@ -298,8 +338,8 @@ display: flex; flex-wrap: wrap; justify-content: space-between; - background-color: @bg-color; - color: @color; + background-color: var(--toolbar-bg-color); + color: var(--toolbar-color); .fa { font: normal normal normal 14px/1 FontAwesome; @@ -517,42 +557,42 @@ .cp-toolbar-spinner { font-size: @colortheme_app-font-size; - color: @color; + color: var(--toolbar-color); } .cp-toolbar-limit { - text-shadow: -1px 0 @color, 0 1px @color, 1px 0 @color, 0 -1px @color; - color: @warn-color; + text-shadow: -1px 0 var(--toolbar-color), 0 1px var(--toolbar-color), 1px 0 var(--toolbar-color), 0 -1px var(--toolbar-color); + color: var(--toolbar-warn-color); } .cp-toolbar-leftside, .cp-toolbar-rightside { - background-color: lighten(@bg-color, 8%); + background-color: var(--toolbar-bg-color-l8); button:hover, button.cp-toolbar-button-active { - background-color: @bg-color; + background-color: var(--toolbar-bg-color); } } .cp-toolbar-title-hoverable:hover { .cp-toolbar-title-editable, .cp-toolbar-title-edit { cursor: text; - border: 1px solid darken(@bg-color, 15%); - background: darken(@bg-color, 10%); + border: 1px solid var(--toolbar-bg-color-d15); + background: var(--toolbar-bg-color-d10); transition: all 0.15s; - color: @color; + color: var(--toolbar-color); } .cp-toolbar-title-editable { cursor: text; } } .cp-toolbar-title-save { - border: 1px solid darken(@bg-color, 15%); - background: darken(@bg-color, 10%); - color: @color; + border: 1px solid var(--toolbar-bg-color-d15); + background: var(--toolbar-bg-color-d10); + color: var(--toolbar-color); &:hover { - background: darken(@bg-color, 5%); + background: var(--toolbar-bg-color-d5); } } input { - border: 1px solid darken(@bg-color, 15%); - background: darken(@bg-color, 10%); - color: @color; + border: 1px solid var(--toolbar-bg-color-d15); + background: var(--toolbar-bg-color-d10); + color: var(--toolbar-color); } .cp-dropdown-content.cp-dropdown-left a { color: black; @@ -578,7 +618,7 @@ padding: 0; margin: 0 5px; font-size: @colortheme_app-font-size; - color: @warn-color; + color: var(--toolbar-warn-color); .cp-pnp-msg { padding-left: 5px; font-family: @colortheme_font; @@ -587,7 +627,7 @@ font-size: @colortheme_app-font-size; font-family: @colortheme_font; font-weight: bold; - color: @warn-color; + color: var(--toolbar-warn-color); &:hover { text-decoration: underline; } @@ -881,7 +921,7 @@ display: flex; min-height: @toolbar_line-height; overflow: hidden; - @media screen and (max-width: @barWidth) { // 450px + @media screen and (max-width: var(--toolbar-barWidth)) { // 450px flex-wrap: wrap; height: auto; width: 100%; @@ -1004,6 +1044,4 @@ } } } - -} - +}; \ No newline at end of file diff --git a/customize.dist/src/less2/main.less b/customize.dist/src/less2/main.less deleted file mode 100644 index d14045194..000000000 --- a/customize.dist/src/less2/main.less +++ /dev/null @@ -1,44 +0,0 @@ -@import (reference) './include/font.less'; -.font_neuropolitical(); -.font_open-sans(); - -body.cp-page-index { @import "./pages/page-index.less"; } -body.cp-page-contact { @import "./pages/page-contact.less"; } -body.cp-page-login { @import "./pages/page-login.less"; } -body.cp-page-register { @import "./pages/page-register.less"; } -body.cp-page-what-is-cryptpad { @import "./pages/page-what-is-cryptpad.less"; } -body.cp-page-about { @import "./pages/page-about.less"; } -body.cp-page-privacy { @import "./pages/page-privacy.less"; } -body.cp-page-features { @import "./pages/page-features.less"; } -body.cp-page-faq { @import "./pages/page-faq.less"; } -body.cp-page-terms { @import "./pages/page-terms.less"; } - -// Set the HTML style for the apps which shouldn't have a body scrollbar -html.cp-app-noscroll { - @import (reference) "./include/app-noscroll.less"; - .app-noscroll_main(); -} -// Set the HTML style for printing slides -html.cp-app-print { - @import (reference) "./include/app-print.less"; - .app-print_main(); -} - -body.cp-readonly .cp-hidden-if-readonly { display: none !important; } - -body.cp-app-drive { @import "../../../drive/app-drive.less"; } -body.cp-app-pad { @import "../../../pad/app-pad.less"; } -body.cp-app-code { @import "../../../code/app-code.less"; } -body.cp-app-slide { @import "../../../slide/app-slide.less"; } -body.cp-app-file { @import "../../../file/app-file.less"; } -body.cp-app-filepicker { @import "../../../filepicker/app-filepicker.less"; } -body.cp-app-contacts { @import "../../../contacts/app-contacts.less"; } -body.cp-app-poll { @import "../../../poll/app-poll.less"; } -body.cp-app-whiteboard { @import "../../../whiteboard/app-whiteboard.less"; } -body.cp-app-todo { @import "../../../todo/app-todo.less"; } -body.cp-app-profile { @import "../../../profile/app-profile.less"; } -body.cp-app-settings { @import "../../../settings/app-settings.less"; } -body.cp-app-debug { @import "../../../debug/app-debug.less"; } -body.cp-app-worker { @import "../../../worker/app-worker.less"; } -body.cp-app-kanban { @import "../../../kanban/app-kanban.less"; } - diff --git a/customize.dist/src/less2/pages/page-404.less b/customize.dist/src/less2/pages/page-404.less index 4e26951a1..9ff9cdcc3 100644 --- a/customize.dist/src/less2/pages/page-404.less +++ b/customize.dist/src/less2/pages/page-404.less @@ -1,9 +1,8 @@ @import (reference) "../include/colortheme-all.less"; @import (reference) "../include/font.less"; -.font_neuropolitical(); -.font_open-sans(); html, body { + .font_main(); margin: 0px; padding: 0px; #cp-main { diff --git a/customize.dist/src/less2/pages/page-about.less b/customize.dist/src/less2/pages/page-about.less index 350ffee4a..1e23c0b07 100644 --- a/customize.dist/src/less2/pages/page-about.less +++ b/customize.dist/src/less2/pages/page-about.less @@ -1,115 +1,117 @@ -@import (once) "../include/infopages.less"; +@import (reference) "../include/infopages.less"; @import (reference) "../include/colortheme-all.less"; -.infopages_main(); -.infopages_topbar(); -#cp-main { - background: #fff; -} -.cp-about-intro { - padding-top: 3em; - padding-bottom: 3em; - background-image: url(/customize/bkabout.jpg); - background-size: cover; - background-repeat: no-repeat; - background-position: center; - .container { - color: #fff; - font-family: "Open Sans"; - h1 { - font-weight: 700; - } - a { +&.cp-page-about { + .infopages_main(); + + #cp-main { + background: #fff; + } + .cp-about-intro { + padding-top: 3em; + padding-bottom: 3em; + background-image: url(/customize/bkabout.jpg); + background-size: cover; + background-repeat: no-repeat; + background-position: center; + .container { color: #fff; - text-decoration: underline; - } - p { - padding-top: 1em; + font-family: "Open Sans"; + h1 { + font-weight: 700; + } + a { + color: #fff; + text-decoration: underline; + } + p { + padding-top: 1em; + } } } -} -.cp-container { - .row { - background: #fff; - } - .cp-bio-avatar { - padding-right: 0; - @media (max-width: 991px) { - padding-right: 15px; + .cp-container { + .row { + background: #fff; } - img { + .cp-bio-avatar { + padding-right: 0; @media (max-width: 991px) { - margin: 0 auto; - display: block; + padding-right: 15px; + } + img { + @media (max-width: 991px) { + margin: 0 auto; + display: block; + } } } - } - .cp-bio-avatar-right { - padding-right: 15px; - padding-left: 0; - @media (max-width: 991px) { - padding-left: 15px; + .cp-bio-avatar-right { + padding-right: 15px; + padding-left: 0; + @media (max-width: 991px) { + padding-left: 15px; + } } } -} -.cp-develop-about { - .cp-icon-cent { - width: 6rem; - background: #fff; - border-radius: 50%; - height: 6rem; - box-shadow: 0 5px 15px rgba(69,145,196, 0.3); - margin: 0 auto; - background-image: url(/customize/code.svg); - background-repeat: no-repeat; - margin-top: 1em; - margin-bottom: 1.5em; - background-position: 50%; - background-size: 4rem; - } - h2 { - margin-top: 0; - font-weight: 600; - color: #1E1F1F; - margin-bottom: 1.5em; - } -} -.cp-profile-det { - padding-left: 30px; - h3 { - color: #1E1F1F; - font-weight: 700; + .cp-develop-about { + .cp-icon-cent { + width: 6rem; + background: #fff; + border-radius: 50%; + height: 6rem; + box-shadow: 0 5px 15px rgba(69,145,196, 0.3); + margin: 0 auto; + background-image: url(/customize/code.svg); + background-repeat: no-repeat; + margin-top: 1em; + margin-bottom: 1.5em; + background-position: 50%; + background-size: 4rem; + } + h2 { + margin-top: 0; + font-weight: 600; + color: #1E1F1F; + margin-bottom: 1.5em; + } } - p { - color: #3F4141; + .cp-profile-det { + padding-left: 30px; + h3 { + color: #1E1F1F; + font-weight: 700; + } + p { + color: #3F4141; + margin-bottom: 1em; + } + hr { + margin-left: 0; + width: 15rem; + border-top: 2px solid @cryptpad_color_blue; + } margin-bottom: 1em; } - hr { - margin-left: 0; - width: 15rem; - border-top: 2px solid @cryptpad_color_blue; - } - margin-bottom: 1em; -} -.cp-soc-media { - font-size: 1.5em; - color: @cryptpad_color_blue; - padding-right: 1em; - display: inline-block; - &:hover { - transform: scale(1.1); - } - &:visited { + .cp-soc-media { + font-size: 1.5em; color: @cryptpad_color_blue; + padding-right: 1em; + display: inline-block; + &:hover { + transform: scale(1.1); + } + &:visited { + color: @cryptpad_color_blue; + } + } + .cp-contrib { + margin-top: 3em; + .cp-icon-cent { + background-image: url(/customize/source-branch.svg); + background-position: 60%; } -} -.cp-contrib { - margin-top: 3em; - .cp-icon-cent { - background-image: url(/customize/source-branch.svg); - background-position: 60%; } -} -.cp-margin-bot { - margin-bottom: 1.5em; -} + .cp-margin-bot { + margin-bottom: 1.5em; + } +} \ No newline at end of file diff --git a/customize.dist/src/less2/pages/page-contact.less b/customize.dist/src/less2/pages/page-contact.less index 4cab7b742..30cf702df 100644 --- a/customize.dist/src/less2/pages/page-contact.less +++ b/customize.dist/src/less2/pages/page-contact.less @@ -1,90 +1,91 @@ -@import (once) "../include/infopages.less"; +@import (reference) "../include/infopages.less"; @import (reference) "../include/colortheme-all.less"; -.infopages_main(); -.infopages_topbar(); +&.cp-page-contact { + .infopages_main(); -.fa { - padding-right: 0.25em; -} -#cp-main { - background-color: #fff; -} -.cp-container { - background: #fff; - .cp-iconCont { - h4 { - margin-top: 1.5em; - margin-bottom: 1.5em; - } - div { - .card { - padding: 4em 1em 0.5em 1em; - box-shadow: 0 5px 15px rgba(69,145,196, 0.3); - border-color: #fff; - text-align: center; - margin-bottom: 1em; - &:hover, &:focus { - text-decoration: none; - transform: scale(1.05); - } - @media (max-width: 1200px) and (min-width: 769px) { - min-height: 139px; - } - @media (max-width: 768px) and (min-width: 576px) { - min-height: 164px; - } - @media (max-width: 496px) { - min-height: 140px; - } - @media (max-width: 335px) { - min-height: 162px; - } + .fa { + padding-right: 0.25em; + } + #cp-main { + background-color: #fff; + } + .cp-container { + background: #fff; + .cp-iconCont { + h4 { + margin-top: 1.5em; + margin-bottom: 1.5em; } - &:nth-child(2) { + div { .card { - background-image: url(/customize/images/twitter.svg); - background-repeat: no-repeat; - background-position: 50% 10%; - background-size: 3rem; + padding: 4em 1em 0.5em 1em; + box-shadow: 0 5px 15px rgba(69,145,196, 0.3); + border-color: #fff; + text-align: center; + margin-bottom: 1em; + &:hover, &:focus { + text-decoration: none; + transform: scale(1.05); + } + @media (max-width: 1200px) and (min-width: 769px) { + min-height: 139px; + } + @media (max-width: 768px) and (min-width: 576px) { + min-height: 164px; + } + @media (max-width: 496px) { + min-height: 140px; + } + @media (max-width: 335px) { + min-height: 162px; + } } - } - &:nth-child(3) { - .card { - background-image: url(/customize/images/issue.svg); - background-repeat: no-repeat; - background-position: 50% 10%; - background-size: 3rem; + &:nth-child(2) { + .card { + background-image: url(/customize/images/twitter.svg); + background-repeat: no-repeat; + background-position: 50% 10%; + background-size: 3rem; + } } - } - &:nth-child(4) { - .card { - background-image: url(/customize/images/sayhi.svg); - background-repeat: no-repeat; - background-position: 50% 10%; - background-size: 3rem; + &:nth-child(3) { + .card { + background-image: url(/customize/images/issue.svg); + background-repeat: no-repeat; + background-position: 50% 10%; + background-size: 3rem; + } } - } - &:nth-child(5) { - .card { - background-image: url(/customize/images/email.svg); - background-repeat: no-repeat; - background-position: 50% 10%; - background-size: 3rem; + &:nth-child(4) { + .card { + background-image: url(/customize/images/sayhi.svg); + background-repeat: no-repeat; + background-position: 50% 10%; + background-size: 3rem; + } + } + &:nth-child(5) { + .card { + background-image: url(/customize/images/email.svg); + background-repeat: no-repeat; + background-position: 50% 10%; + background-size: 3rem; + } } } } } -} -.cp-contdet { - padding-top: 3em; - padding-bottom: 3em; - background-image: url(/customize/images/bkcontact.jpg); - background-size: cover; - background-repeat: no-repeat; - background-position: center; - h1 { - font-weight: 700; - color: #fff; + .cp-contdet { + padding-top: 3em; + padding-bottom: 3em; + background-image: url(/customize/images/bkcontact.jpg); + background-size: cover; + background-repeat: no-repeat; + background-position: center; + h1 { + font-weight: 700; + color: #fff; + } } -} +} \ No newline at end of file diff --git a/customize.dist/src/less2/pages/page-faq.less b/customize.dist/src/less2/pages/page-faq.less index e08fc42ed..01e360a29 100644 --- a/customize.dist/src/less2/pages/page-faq.less +++ b/customize.dist/src/less2/pages/page-faq.less @@ -1,84 +1,85 @@ -@import (once) "../include/infopages.less"; +@import (reference) "../include/infopages.less"; @import (reference) "../include/colortheme-all.less"; -.infopages_main(); -.infopages_topbar(); -#cp-main { - background: #fff; -} -.cp-faq { - padding-top: 3em; - padding-bottom: 3em; - background-image: url(/customize/images/cover-faq.jpg); - background-size: cover; - background-repeat: no-repeat; - background-position: center; - .container { - color: #fff; - font-family: "Open Sans"; +&.cp-page-faq { + .infopages_main(); + + #cp-main { + background: #fff; } - h1 { - font-weight: 700; + .cp-faq { + padding-top: 3em; + padding-bottom: 3em; + background-image: url(/customize/images/cover-faq.jpg); + background-size: cover; + background-repeat: no-repeat; + background-position: center; + .container { + color: #fff; + font-family: "Open Sans"; + } + h1 { + font-weight: 700; + } } -} -.cp-faq-ques-det { - .cp-faq-header { - a { - padding: 0; - h4 { - margin-top: 1.5rem; - margin-bottom: 1.5rem; - .cp-brand-font { - font-family: "Neuropolitical"; + .cp-faq-ques-det { + .cp-faq-header { + a { + padding: 0; + h4 { + margin-top: 1.5rem; + margin-bottom: 1.5rem; + .cp-brand-font { + font-family: "Neuropolitical"; + } } } } } -} -.cp-faq-container { - .cp-faq-questions-items { - background: #3a84b6; - color: #fff; - padding: 1rem 1rem 0.5rem 1rem; - margin-bottom: 1rem; - } - .cp-faq-questions-q { - padding: 0; - margin-bottom: 0.5rem; - cursor: pointer; - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - &:hover { - text-decoration: none; + .cp-faq-container { + .cp-faq-questions-items { + background: #3a84b6; + color: #fff; + padding: 1rem 1rem 0.5rem 1rem; + margin-bottom: 1rem; } - &:after { - content: '\f067'; - font-family: FontAwesome; - font-weight: normal; - font-style: normal; - float: right; - text-decoration: none; - font-size: 13px; - line-height: 1.5; + .cp-faq-questions-q { + padding: 0; + margin-bottom: 0.5rem; + cursor: pointer; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + &:hover { + text-decoration: none; + } + &:after { + content: '\f067'; + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + float: right; + text-decoration: none; + font-size: 13px; + line-height: 1.5; + } } - } - .cp-faq-questions-q.active-faq { - &:after { - content: '\f068'; + .cp-faq-questions-q.active-faq { + &:after { + content: '\f068'; + } } + .cp-faq-questions-a { + display: none; + padding: 0.5rem; + margin-bottom: 0.5rem; + background-color: #fff; + color: #212529; + } + margin-bottom: 1.5rem; } - .cp-faq-questions-a { - display: none; - padding: 0.5rem; - margin-bottom: 0.5rem; - background-color: #fff; - color: #212529; - } - margin-bottom: 1.5rem; -} - +} \ No newline at end of file diff --git a/customize.dist/src/less2/pages/page-features.less b/customize.dist/src/less2/pages/page-features.less index 57c1335cf..51ee53165 100644 --- a/customize.dist/src/less2/pages/page-features.less +++ b/customize.dist/src/less2/pages/page-features.less @@ -1,86 +1,88 @@ -@import (once) "../include/infopages.less"; +@import (reference) "../include/infopages.less"; @import (reference) "../include/colortheme-all.less"; -.infopages_main(); -.infopages_topbar(); -#cp-main { - background-color: #fff; -} -.cp_cont_features { - padding-top: 3em; - padding-bottom: 3em; - background-image: url('/customize/images/cover-features.jpg'); - background-size: cover; - background-repeat: no-repeat; - background-position: center; - h1 { - font-weight: 700; - color: #fff; +&.cp-page-features { + .infopages_main(); + + #cp-main { + background-color: #fff; } -} -#cp-features-register { - text-align: center; - padding: 20px; -} -.cp-features-register-button { - font-size: 20px; - color: #fff; - background: @cryptpad_color_blue; - border: 2px solid @cryptpad_color_blue; - border-radius: 0; - &:hover { - transform: scale(1.05); - cursor: pointer; + .cp_cont_features { + padding-top: 3em; + padding-bottom: 3em; + background-image: url('/customize/images/cover-features.jpg'); + background-size: cover; + background-repeat: no-repeat; + background-position: center; + h1 { + font-weight: 700; + color: #fff; + } } - padding: 0.5em 1em; -} -.cp-features-web { - .card { - box-shadow: 0 5px 15px rgba(69, 145, 196, 0.3); - border: none; + #cp-features-register { + text-align: center; + padding: 20px; } - h3 { + .cp-features-register-button { + font-size: 20px; color: #fff; + background: @cryptpad_color_blue; + border: 2px solid @cryptpad_color_blue; + border-radius: 0; + &:hover { + transform: scale(1.05); + cursor: pointer; + } + padding: 0.5em 1em; } - .list-group { - li { - &:before { - content: "\f00c"; - font-family: "FontAwesome"; - font-size: 14px; - color: @cryptpad_color_blue; - padding-right: 10px; + .cp-features-web { + .card { + box-shadow: 0 5px 15px rgba(69, 145, 196, 0.3); + border: none; + } + h3 { + color: #fff; + } + .list-group { + li { + &:before { + content: "\f00c"; + font-family: "FontAwesome"; + font-size: 14px; + color: @cryptpad_color_blue; + padding-right: 10px; + } + } + div { + display: inline; } } - div { - display: inline; + a.voted { + opacity: 0.6; + margin-left: 15px; + &:hover { + opacity: 1; + } } - } - a.voted { - opacity: 0.6; - margin-left: 15px; - &:hover { - opacity: 1; + .list-group-item { + border-color: rgba(69, 145, 196, 0.125); } } - .list-group-item { - border-color: rgba(69, 145, 196, 0.125); - } -} -.cp-anon-user { - .card-body { - background-color: @cryptpad_color_blue; - } -} -.cp-regis-user { - @media (max-width:575px) { - margin-top: 3em; + .cp-anon-user { + .card-body { + background-color: @cryptpad_color_blue; + } } - .card-body { - &:first-of-type { - background: #4591C4; - background: -webkit-linear-gradient(to right, #FF7C4F, #4592C4); // lesshint duplicateProperty: false - background: linear-gradient(to right, #FF7C4F, #4592C4); // lesshint duplicateProperty: false + .cp-regis-user { + @media (max-width:575px) { + margin-top: 3em; + } + .card-body { + &:first-of-type { + background: #4591C4; + background: -webkit-linear-gradient(to right, #FF7C4F, #4592C4); // lesshint duplicateProperty: false + background: linear-gradient(to right, #FF7C4F, #4592C4); // lesshint duplicateProperty: false + } } } -} +} \ No newline at end of file diff --git a/customize.dist/src/less2/pages/page-index.less b/customize.dist/src/less2/pages/page-index.less index 54f8c6275..f6217e300 100644 --- a/customize.dist/src/less2/pages/page-index.less +++ b/customize.dist/src/less2/pages/page-index.less @@ -1,192 +1,192 @@ -@import (once) "../include/infopages.less"; +@import (reference) "../include/infopages.less"; @import (reference) "../include/colortheme-all.less"; -.infopages_main(); -.infopages_topbar(); +&.cp-page-index { + .infopages_main(); -@background_lighter: rgba(0,0,0,0.1); -@background_darker: rgba(0,0,0,0.4); -#cp-main { - color: #FFF; - background: linear-gradient( @background_darker, @background_lighter ), url('/customize/bg14.jpg'); - background-size: cover; - background-position: center; - min-height: 100vh; - display: flex; - flex-direction: column; - justify-content: space-between; - align-items: center; - .container { - @media only screen and (max-device-width : 576px) { - margin-top: 6em; - } - } -} -body { - font-family: "Open Sans", Helvetica; -} -.cp-right { - .cp-register-btn { - padding: 0.5em 1em 0.7em 1em; - border: 2px solid #fff; - &:hover { - transform: scale(1.05); - } - } - .cp-login-btn { - color: #fff; - padding: 0.5em 1em 0.7em 1em; - &:hover { - transform: scale(1.05); - } - } -} -.cp-title { - display: flex; - align-items: center; - flex-direction: column; - margin-top: 1.5em; - img { - height: 20vh; - margin-bottom: 1.5em; - } - margin-left: 0; - h1 { - font-family: "Neuropolitical"; - //font-family: Garamond, Baskerville, "Baskerville Old Face", "Hoefler Text", "Times New Roman", Times, serif; - //font-family: "Raleway"; - font-size: 45px; - } - p { - //font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; - font-size: 20px; - //font-style: italic; - } -} -.navbar { - background: transparent; - width: 100%; - @media only screen and (max-device-width: 991px) { - margin-top: 0; + @background_lighter: rgba(0,0,0,0.1); + @background_darker: rgba(0,0,0,0.4); + #cp-main { + color: #FFF; + background: linear-gradient( @background_darker, @background_lighter ), url('/customize/bg14.jpg'); + background-size: cover; + background-position: center; + min-height: 100vh; + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: center; + .container { + @media only screen and (max-device-width : 576px) { + margin-top: 6em; + } + } } - .navbar-brand { - background-image: url(/customize/CryptPad-white-logo.svg); + body { + font-family: "Open Sans", Helvetica; } - a { - color: #fff; - &:visited { - color: rgba(255,255,255,.9); - }; + .cp-right { + .cp-register-btn { + padding: 0.5em 1em 0.7em 1em; + border: 2px solid #fff; + &:hover { + transform: scale(1.05); + } + } + .cp-login-btn { + color: #fff; + padding: 0.5em 1em 0.7em 1em; + &:hover { + transform: scale(1.05); + } + } } - .nav-link { - &:hover { - color: inherit; - transform: scale(1.05); - }; + .cp-title { + display: flex; + align-items: center; + flex-direction: column; + margin-top: 1.5em; + img { + height: 20vh; + margin-bottom: 1.5em; + } + margin-left: 0; + h1 { + font-family: "Neuropolitical"; + //font-family: Garamond, Baskerville, "Baskerville Old Face", "Hoefler Text", "Times New Roman", Times, serif; + //font-family: "Raleway"; + font-size: 45px; + } + p { + //font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + font-size: 20px; + //font-style: italic; + } } - .cp-register-btn { - border: 2px solid #fff; + .navbar { + background: transparent; + width: 100%; + @media only screen and (max-device-width: 991px) { + margin-top: 0; + } + .navbar-brand { + background-image: url(/customize/CryptPad-white-logo.svg); + } + a { + color: #fff; + &:visited { + color: rgba(255,255,255,.9); + }; + } + .nav-link { + &:hover { + color: inherit; + transform: scale(1.05); + }; + } + .cp-register-btn { + border: 2px solid #fff; + } + .navbar-toggler { + margin-top: 10px; + color: #fff; + } } - .navbar-toggler { - margin-top: 10px; - color: #fff; + @callout-padding: 15px; + a:hover { + text-decoration: none; } -} -@callout-padding: 15px; -a:hover { - text-decoration: none; -} -.bs-callout { - display: flex; - align-items: stretch; - margin: 25px 0; - background: rgba(255,255,255,0.6); - color: black; - transition: all .1s ease-in-out; - box-sizing: border-box; - height: 5em; - position: relative; - a { + .bs-callout { + display: flex; + align-items: stretch; + margin: 25px 0; + background: rgba(255,255,255,0.6); color: black; - &:hover { text-decoration-line: none; } - } - div h4 { - @media only screen and (min-device-width: 576px) and (max-device-width: 767px) { - font-size: 1.3em; - } - } -} -h4 { - margin: 0; -} -.cp-callout-more-moremsg,.cp-callout-more-lessmsg { - transform: none !important; -} -.bs-callout div { - display: flex; - align-items: center; - justify-content: center; - height: 100%; - position: absolute; - left: 5em; -} -.bs-callout+.bs-callout { - margin-top: -5px; -} - -.bs-callout:hover { - //color: white; - transform: scale(1.05); - cursor: pointer; -} -.bs-callout:hover.cp-callout-more { - transform: none !important; -} -.bs-callout .fa { - display: flex; - align-items: center; - font-size: 2em; - padding-left: 0.57em; - width: 2em; - transition: width 0.1s; - color: #fff; -} -.cp-callout-pad .fa { background-color: @colortheme_pad-bg; } -.cp-callout-code .fa { background-color: @colortheme_code-bg; } -.cp-callout-slide .fa { background-color: @colortheme_slide-bg; } -.cp-callout-poll .fa { background-color: @colortheme_poll-bg; } -.cp-callout-kanban .fa { background-color: @colortheme_kanban-bg; } -.cp-callout-whiteboard .fa { background-color: @colortheme_whiteboard-bg; } -.cp-callout-recent .fa { background-color: @colortheme_drive-bg; } -.cp-hidden { display: none !important; } -.cp-callout-more { - display: inline-block; - align-content: center; - height: 2em; - border-radius: 1em; - margin-left: auto; - margin-right: auto; - margin-top: 0; - background: none; - width: 100%; - div { - .infopages_link(); - color: #fff; - .fa { - font-size: inherit; - padding: 0; - width: 1em; - padding-left: 5px; + transition: all .1s ease-in-out; + box-sizing: border-box; + height: 5em; + position: relative; + a { + color: black; + &:hover { text-decoration-line: none; } } + div h4 { + @media only screen and (min-device-width: 576px) and (max-device-width: 767px) { + font-size: 1.3em; + } + } + } + h4 { + margin: 0; + } + .cp-callout-more-moremsg,.cp-callout-more-lessmsg { + transform: none !important; } -} -@media (min-width: 576px) and (max-width: 767px) { - .container { - padding-left: 0; - padding-right: 0; + .bs-callout div { + display: flex; + align-items: center; + justify-content: center; + height: 100%; + position: absolute; + left: 5em; } - div#cp-main.cp-page-index .cp-topbar .navbar-toggler-left { - left: 5px; + .bs-callout+.bs-callout { + margin-top: -5px; } -} + .bs-callout:hover { + //color: white; + transform: scale(1.05); + cursor: pointer; + } + .bs-callout:hover.cp-callout-more { + transform: none !important; + } + .bs-callout .fa { + display: flex; + align-items: center; + font-size: 2em; + padding-left: 0.57em; + width: 2em; + transition: width 0.1s; + color: #fff; + } + .cp-callout-pad .fa { background-color: @colortheme_pad-bg; } + .cp-callout-code .fa { background-color: @colortheme_code-bg; } + .cp-callout-slide .fa { background-color: @colortheme_slide-bg; } + .cp-callout-poll .fa { background-color: @colortheme_poll-bg; } + .cp-callout-kanban .fa { background-color: @colortheme_kanban-bg; } + .cp-callout-whiteboard .fa { background-color: @colortheme_whiteboard-bg; } + .cp-callout-recent .fa { background-color: @colortheme_drive-bg; } + .cp-hidden { display: none !important; } + .cp-callout-more { + display: inline-block; + align-content: center; + height: 2em; + border-radius: 1em; + margin-left: auto; + margin-right: auto; + margin-top: 0; + background: none; + width: 100%; + div { + .infopages_link(); + color: #fff; + .fa { + font-size: inherit; + padding: 0; + width: 1em; + padding-left: 5px; + } + } + } + @media (min-width: 576px) and (max-width: 767px) { + .container { + padding-left: 0; + padding-right: 0; + } + div#cp-main.cp-page-index .cp-topbar .navbar-toggler-left { + left: 5px; + } + } +} \ No newline at end of file diff --git a/customize.dist/src/less2/pages/page-login.less b/customize.dist/src/less2/pages/page-login.less index 8eec31f67..329e09077 100644 --- a/customize.dist/src/less2/pages/page-login.less +++ b/customize.dist/src/less2/pages/page-login.less @@ -1,69 +1,70 @@ -@import (once) "../include/infopages.less"; +@import (reference) "../include/infopages.less"; @import (reference) "../include/colortheme-all.less"; @import (reference) "../include/alertify.less"; @import (reference) "../include/checkmark.less"; -.infopages_main(); -.infopages_topbar(); -.alertify_main(); -.checkmark_main(20px); +&.cp-page-login { + .infopages_main(); + .alertify_main(); + .checkmark_main(20px); -.form-group { - .extra { - display: flex; - align-items: center; - justify-content: space-between; - width: 100%; - } -} -.cp-container { - #data { - background: #4591C4; - padding-top: 3em; - padding-bottom: 7em; - padding-left: 30px; - padding-right: 30px; - p { - color: #fff; - } - h2 { - font-weight: 700; - color: @cryptpad_header_col; + .form-group { + .extra { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; } } - #userForm { - padding-top: 3em; - padding-bottom: 2em; - .form-control { - border-radius: 0; - color: @cryptpad_text_col; - margin-top: 1em; - &:focus { - border-color: @cryptpad_color_blue; + .cp-container { + #data { + background: #4591C4; + padding-top: 3em; + padding-bottom: 7em; + padding-left: 30px; + padding-right: 30px; + p { + color: #fff; + } + h2 { + font-weight: 700; + color: @cryptpad_header_col; + } + } + #userForm { + padding-top: 3em; + padding-bottom: 2em; + .form-control { + border-radius: 0; + color: @cryptpad_text_col; + margin-top: 1em; + &:focus { + border-color: @cryptpad_color_blue; + } + } + .checkbox-container { + color: @cryptpad_text_col; } } - .checkbox-container { - color: @cryptpad_text_col; + .align-items-center { + box-shadow: 0 5px 15px rgba(69,145,196, 0.3); + background: #fff; } - } - .align-items-center { - box-shadow: 0 5px 15px rgba(69,145,196, 0.3); - background: #fff; - } - .extra { - margin-top: 1em; - .login { - background: @cryptpad_color_blue; - color: #fff; - padding: 10px; - border-radius: 0; - &:hover { - transform: scale(1.05); + .extra { + margin-top: 1em; + .login { + background: @cryptpad_color_blue; + color: #fff; + padding: 10px; + border-radius: 0; + &:hover { + transform: scale(1.05); + } } } } -} -.cp-container { - padding-top: 3em; - min-height: 66vh; -} + .cp-container { + padding-top: 3em; + min-height: 66vh; + } +} \ No newline at end of file diff --git a/customize.dist/src/less2/pages/page-privacy.less b/customize.dist/src/less2/pages/page-privacy.less index 3abbc43c3..137f34683 100644 --- a/customize.dist/src/less2/pages/page-privacy.less +++ b/customize.dist/src/less2/pages/page-privacy.less @@ -1,48 +1,50 @@ -@import (once) "../include/infopages.less"; +@import (reference) "../include/infopages.less"; @import (reference) "../include/colortheme-all.less"; -.infopages_main(); -.infopages_topbar(); -#cp-main { - background: #fff; -} -.cp-privacy-top { - padding-top: 3em; - padding-bottom: 3em; - background-image: url(/customize/images/cover-privacy.jpg); - background-size: cover; - background-repeat: no-repeat; - background-position: center; - .container { - color: #fff; - font-family: "Open Sans"; - h1 { - font-weight: 700; - } - a { +&.cp-page-privacy { + .infopages_main(); + + #cp-main { + background: #fff; + } + .cp-privacy-top { + padding-top: 3em; + padding-bottom: 3em; + background-image: url(/customize/images/cover-privacy.jpg); + background-size: cover; + background-repeat: no-repeat; + background-position: center; + .container { color: #fff; - text-decoration: underline; + font-family: "Open Sans"; + h1 { + font-weight: 700; + } + a { + color: #fff; + text-decoration: underline; + } + p { + padding-top: 1em; + } + } + } + .cp-privacy { + background-image: url(/customize/CryptPadlogo_op5.svg); + background-size: cover; + background-repeat: no-repeat; + background-position: center; + hr { + margin-left: 0; + width: 15rem; + border-top: 2px solid #4591C4; + } + h3 { + color: #1E1F1F; + font-weight: 700; } p { - padding-top: 1em; + color: #3F4141; } } -} -.cp-privacy { - background-image: url(/customize/CryptPadlogo_op5.svg); - background-size: cover; - background-repeat: no-repeat; - background-position: center; - hr { - margin-left: 0; - width: 15rem; - border-top: 2px solid #4591C4; - } - h3 { - color: #1E1F1F; - font-weight: 700; - } - p { - color: #3F4141; - } -} +} \ No newline at end of file diff --git a/customize.dist/src/less2/pages/page-register.less b/customize.dist/src/less2/pages/page-register.less index 26c8b0f1f..37ddf333f 100644 --- a/customize.dist/src/less2/pages/page-register.less +++ b/customize.dist/src/less2/pages/page-register.less @@ -1,139 +1,141 @@ -@import (once) "../include/infopages.less"; +@import (reference) "../include/infopages.less"; @import (reference) "../include/colortheme-all.less"; @import (reference) "../include/alertify.less"; @import (reference) "../include/checkmark.less"; -.infopages_main(); -.infopages_topbar(); -.alertify_main(); -.checkmark_main(20px); +&.cp-page-register { + .infopages_main(); -.cp-container { - .form-group { - .checkbox-container { - &:nth-of-type(1) { - margin-top: 2em; - } - &:last-of-type { - margin-bottom: 1em; + .alertify_main(); + .checkmark_main(20px); + + .cp-container { + .form-group { + .checkbox-container { + &:nth-of-type(1) { + margin-top: 2em; + } + &:last-of-type { + margin-bottom: 1em; + } } - } - #register { - &.btn { - padding: .5rem .5rem; + #register { + &.btn { + padding: .5rem .5rem; + } + margin-top: 16px; + font-size: 1.25em; + min-width: 30%; } - margin-top: 16px; - font-size: 1.25em; - min-width: 30%; } + padding-bottom: 3em; + min-height: 5vh; } - padding-bottom: 3em; - min-height: 5vh; -} -.alertify { - // workaround for alertify making empty p - p:empty { - display: none; + .alertify { + // workaround for alertify making empty p + p:empty { + display: none; + } } -} -.cp-register-wel { - padding-top: 6em; - padding-bottom: 20em; - background-image: url(/customize/bkregister.jpg); - background-size: cover; - background-repeat: no-repeat; - background-position: center; - h1 { - font-weight: 700; - color: #fff; - text-shadow: 0 1px 5px rgba(0,0,0,.2); + .cp-register-wel { + padding-top: 6em; + padding-bottom: 20em; + background-image: url(/customize/bkregister.jpg); + background-size: cover; + background-repeat: no-repeat; + background-position: center; + h1 { + font-weight: 700; + color: #fff; + text-shadow: 0 1px 5px rgba(0,0,0,.2); + } } -} -.cp-register-det { - margin-top: -7em; - background: #fff; - box-shadow: 0 5px 15px rgba(69,145,196, 0.3); + .cp-register-det { + margin-top: -7em; + background: #fff; + box-shadow: 0 5px 15px rgba(69,145,196, 0.3); - #data { - // Old browsers - background: #4591C4; + #data { + // Old browsers + background: #4591C4; - // Chrome 10-25, Safari 5.1-6 - background: -webkit-linear-gradient(to right, #FF7C4F, #4592C4); // lesshint duplicateProperty: false + // Chrome 10-25, Safari 5.1-6 + background: -webkit-linear-gradient(to right, #FF7C4F, #4592C4); // lesshint duplicateProperty: false - // W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ - background: linear-gradient(to right, #FF7C4F, #4592C4); // lesshint duplicateProperty: false + // W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ + background: linear-gradient(to right, #FF7C4F, #4592C4); // lesshint duplicateProperty: false - padding-top: 3em; - padding-bottom: 7em; - padding-left: 30px; - padding-right: 30px; - p { - color: #fff; - li { - margin-bottom: 1em; + padding-top: 3em; + padding-bottom: 7em; + padding-left: 30px; + padding-right: 30px; + p { + color: #fff; + li { + margin-bottom: 1em; + } + .fa { + font-size: 1.5em; + padding-right: 10px; + color: #000; + } } - .fa { - font-size: 1.5em; - padding-right: 10px; - color: #000; + h3 { + font-weight: 700; + margin-bottom: 1em; } } - h3 { - font-weight: 700; - margin-bottom: 1em; + #userForm { + padding-top: 3em; + padding-bottom: 2em; + .form-control { + border-radius: 0; + color: @cryptpad_text_col; + margin-top: 1em; + &:focus { + border-color: @cryptpad_color_blue; + } + } + .checkbox-container { + color: @cryptpad_text_col; + } } - } - #userForm { - padding-top: 3em; - padding-bottom: 2em; - .form-control { + .cp-login-register { + color: @cryptpad_color_blue; + background: #fff; + border: 2px solid @cryptpad_color_blue; border-radius: 0; - color: @cryptpad_text_col; - margin-top: 1em; - &:focus { - border-color: @cryptpad_color_blue; + &:hover { + transform: scale(1.05); } } - .checkbox-container { + } + .cp-register-test { + margin-top: 3em; + hr { + width: 15rem; + border-top: 2px solid @cryptpad_color_blue; + margin-top: 0; + margin-bottom: 2em; + } + p { + margin-bottom: 0; + } + .cp-test-source { + font-style: italic; + } + .test-details { + padding-left: 4em; + background-image: url(/customize/testimonial.svg); + background-repeat: no-repeat; + background-position: left top; + background-size: 3em; color: @cryptpad_text_col; } + } - .cp-login-register { - color: @cryptpad_color_blue; + #cp-main { background: #fff; - border: 2px solid @cryptpad_color_blue; - border-radius: 0; - &:hover { - transform: scale(1.05); - } - } -} -.cp-register-test { - margin-top: 3em; - hr { - width: 15rem; - border-top: 2px solid @cryptpad_color_blue; - margin-top: 0; - margin-bottom: 2em; - } - p { - margin-bottom: 0; } - .cp-test-source { - font-style: italic; - } - .test-details { - padding-left: 4em; - background-image: url(/customize/testimonial.svg); - background-repeat: no-repeat; - background-position: left top; - background-size: 3em; - color: @cryptpad_text_col; - } - -} -#cp-main { - background: #fff; -} +} \ No newline at end of file diff --git a/customize.dist/src/less2/pages/page-terms.less b/customize.dist/src/less2/pages/page-terms.less index d16a7d589..79fdafd1f 100644 --- a/customize.dist/src/less2/pages/page-terms.less +++ b/customize.dist/src/less2/pages/page-terms.less @@ -1,5 +1,6 @@ -@import (once) "../include/infopages.less"; +@import (reference) "../include/infopages.less"; @import (reference) "../include/colortheme-all.less"; -.infopages_main(); -.infopages_topbar(); +&.cp-page-terms { + .infopages_main(); +} diff --git a/customize.dist/src/less2/pages/page-what-is-cryptpad.less b/customize.dist/src/less2/pages/page-what-is-cryptpad.less index 0e26f91ed..28522f337 100644 --- a/customize.dist/src/less2/pages/page-what-is-cryptpad.less +++ b/customize.dist/src/less2/pages/page-what-is-cryptpad.less @@ -1,43 +1,44 @@ -@import (once) "../include/infopages.less"; +@import (reference) "../include/infopages.less"; @import (reference) "../include/colortheme-all.less"; -.infopages_main(); -.infopages_topbar(); +&.cp-page-what-is-cryptpad { + .infopages_main(); -.cp-what-is { + .cp-what-is { + padding-top: 3em; + padding-bottom: 3em; + background-image: url(/customize/bkwhat.jpg); + background-size: cover; + background-repeat: no-repeat; + background-position: center; + color: #fff; + h1 { + font-weight: 700; + } + } + #cp-main { + background: #fff; + } + .cp-container { padding-top: 3em; padding-bottom: 3em; - background-image: url(/customize/bkwhat.jpg); - background-size: cover; - background-repeat: no-repeat; - background-position: center; - color: #fff; - h1 { + h2 { + margin-top: 0; font-weight: 700; + color: @cryptpad_header_col; + } + p { + color: @cryptpad_text_col; + } + #zeroknowledge { + width: 65%; + } + .row { + margin-bottom: 1.5em; + } + img { + display: block; + margin: 0 auto; } -} -#cp-main { - background: #fff; -} -.cp-container { - padding-top: 3em; - padding-bottom: 3em; - h2 { - margin-top: 0; - font-weight: 700; - color: @cryptpad_header_col; - } - p { - color: @cryptpad_text_col; - } - #zeroknowledge { - width: 65%; - } - .row { - margin-bottom: 1.5em; - } - img { - display: block; - margin: 0 auto; } -} +} \ No newline at end of file diff --git a/customize.dist/src/less2/readme.md b/customize.dist/src/less2/readme.md index 08a26ec9b..062b5baff 100644 --- a/customize.dist/src/less2/readme.md +++ b/customize.dist/src/less2/readme.md @@ -1,19 +1,45 @@ # CryptPad Styling -How it works: -* In this example, we use the index page, for each page we will have a corresponding class name and a corresponding less file. -* The index page has a main div containing everything `
            ` -* There is a corresponding less file called `less2/pages/page-index.less` -* Finally there is a corresponding line in main.less which imports that less file: `div#main.cp-page-index { @import "./pages/page-index.less"; }` - * cp-page-index class means: - * cp -> cryptpad - * page -> this is a style for accessing a page's less file - * index -> the name of the page and of the less file (page-index.less) -* And everything which is standardized across pages is included from `page-index.less` as variables and mixins. +## Linking Less/CSS + +In order to keep the amount of CSS generated under control, we use "linking", via the LessLoader. +This makes use of CSS variables in order to work. The old solution was to put all of the content into less mixins +which would be used inside of the scope where they should be, but this caused a state explosion because each app needed +essentially the same mixins. However, these mixins had arguments such as colors which were different per-app. + +The new solution is to set CSS variables for the arguments (like color) and then put the bulk of the less at the global +scope. When you include a dependency, the following happens: + +1. You `@include (reference) './include/dependency.less`. The (reference) argument which means it will not emit CSS, +this is important because otherwise all of the dependencies of your app's less file would end up bundled with it, the +state explosion problem. +2. You invoke `.dependency_main(@arg1 @arg2)` inside of the scope you want it in, the name `dependency_main` is a +convention, all less variables, mixins, or CSS variables which a file creates should be prefixed with the name of the +file (in this case, "dependency"). +3. The mixin `.dependency_main` does a couple of things: + * First, it sets a CSS variable called `--LessLoader_require`, this is a special variable which the browser does not + use, the only objective of this variable is to inform LessLoader that another file is needed. To do this, there is a + helper function (also specified in LessLoader.js) called `LessLoader_currentFile()`. The syntax is: + `--LessLoader_require: LessLoader_currentFile();` and in the CSS, this outputs something like: + `--LessLoader_require: "/customize/src/less2/include/dependency.less?ver=2.4.0-1531572157592";` + * Secondly, it sets browser variables for it's arguments, making sure to avoid namespace collisions: + `--dependency-arg1: @arg1;`, `--dependency-arg2: @arg2;`. Sometimes a less transformation needs to be done on a + variable, unfortunately in this case the transformation must be done here and the transformed variable must be output. + `--dependency-arg1-l10: lighten(@arg1, 10%);`. +4. After less processing is completed, the LessLoader caches the result of parsing, then scans the it for instances of +`--LessLoader_require` variable and then processes them, but it does this separately. So even if dependency.less is +required many times, it will only be processed by the less interpreter once. + +## Other convensions -Rules: * All of our new classes and ids should start with `cp-`. -* You may make as many files as you need, for different purposes, but they can only contain mixins and variables. +* The document body has a class on it depending on the app/page, app classes begin with `cp-app-` and page classes begin +with `cp-page-`. +* Custom classes ought to begin with `cp-` and the name of the file where the rules are written for them (see help.less as +an example of doing the right thing). +* Since the include files generate CSS and the app cannot control the scope which it's run at, be considerate avoid +making an include file which changes something significant (like making a rule for `li`). help.less is an excellent example +of doing this well, infopages.less is the worst example (fortunately it doesn't get included in any of the apps). * All mixins and variables must be prefixed with the name of the file where they're defined and and underscore. * e.g. `@colortheme_toolbar-poll-bg: #006304;` defined in `colortheme.less` * All mixin / variable files go in an `/include/` directory. diff --git a/customize.dist/template.js b/customize.dist/template.js index 0ee34d407..661ce6687 100644 --- a/customize.dist/template.js +++ b/customize.dist/template.js @@ -26,7 +26,7 @@ $(function () { window.Tether = function () {}; require([ - 'less!/customize/src/less2/main.less', + 'less!/customize/src/less2/pages/page-' + css + '.less', 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css' ], function () { $body.append($main); diff --git a/www/code/app-code.less b/www/code/app-code.less index a8c78fc02..37a18b4ee 100644 --- a/www/code/app-code.less +++ b/www/code/app-code.less @@ -2,15 +2,13 @@ @import (reference) "../../customize/src/less2/include/markdown.less"; @import (reference) "../../customize/src/less2/include/framework.less"; - -.framework_main( - @bg-color: @colortheme_code-bg, - @warn-color: @colortheme_code-warn, - @color: @colortheme_code-color -); - -// body &.cp-app-code { + .framework_main( + @bg-color: @colortheme_code-bg, + @warn-color: @colortheme_code-warn, + @color: @colortheme_code-color + ); + display: flex; flex-flow: column; max-height: 100%; diff --git a/www/code/inner.js b/www/code/inner.js index afb4cdcd0..9b52f9806 100644 --- a/www/code/inner.js +++ b/www/code/inner.js @@ -37,6 +37,8 @@ define([ 'cm/addon/fold/comment-fold', 'cm/addon/display/placeholder', + 'less!/code/app-code.less' + ], function ( $, DiffMd, diff --git a/www/common/LessLoader.js b/www/common/LessLoader.js index 04fa68714..39f04db5c 100644 --- a/www/common/LessLoader.js +++ b/www/common/LessLoader.js @@ -4,9 +4,11 @@ const define = (x:any, y:any) => {}; const require = define; */ define([ - '/api/config' -], function (Config) { /*::});module.exports = (function() { + '/api/config', + '/bower_components/nthen/index.js' +], function (Config, nThen) { /*::});module.exports = (function() { const Config = (undefined:any); + const nThen = require('/bower_components/nthen/index.js'); */ var module = { exports: {} }; @@ -100,6 +102,10 @@ define([ require(['/bower_components/less/dist/less.min.js'], function (Less) { if (lessEngine) { return void cb(lessEngine); } lessEngine = Less; + Less.functions.functionRegistry.add('LessLoader_currentFile', function () { + return new Less.tree.UnicodeDescriptor('"' + + fixURL(this.currentFileInfo.filename) + '"'); + }); var doXHR = lessEngine.FileManager.prototype.doXHR; lessEngine.FileManager.prototype.doXHR = function (url, type, callback, errback) { url = fixURL(url); @@ -133,19 +139,32 @@ define([ }); }; - module.exports.load = function (url /*:string*/, cb /*:()=>void*/) { + var loadSubmodulesAndInject = function (css, url, cb, stack) { + inject(css, url); + var nt = nThen; + nt = nt(function (w) { + css.replace(/\-\-LessLoader_require\:\s*"([^"]*)"\s*;/g, function (all, u) { + u = u.replace(/\?.*$/, ''); + module.exports.load(u, w(), stack); + }); + }).nThen; + nt(function () { cb(); }); + }; + + module.exports.load = function (url /*:string*/, cb /*:()=>void*/, stack /*:?Array*/) { + stack = stack || []; + if (stack.indexOf(url) > -1) { return void cb(); } + var timeout = setTimeout(function () { console.log('failed', url); }, 10000); + var done = function () { clearTimeout(timeout); cb(); }; + stack.push(url); cacheGet(url, function (css) { - if (css) { - inject(css, url); - return void cb(); - } + if (css) { return void loadSubmodulesAndInject(css, url, done, stack); } console.log('CACHE MISS ' + url); ((/\.less([\?\#].*)?$/.test(url)) ? loadLess : loadCSS)(url, function (err, css) { if (!css) { return void console.error(err); } var output = fixAllURLs(css, url); cachePut(url, output); - inject(output, url); - cb(); + loadSubmodulesAndInject(output, url, done, stack); }); }); }; diff --git a/www/common/file-dialog.less b/www/common/file-dialog.less index 8f47f6024..5fc260f43 100644 --- a/www/common/file-dialog.less +++ b/www/common/file-dialog.less @@ -2,8 +2,8 @@ @import (reference) '../customize/src/less2/include/modal.less'; .fileDialog_main () { - .modal_main(); #fileDialog { + .modal_main(); display: none; .cp-modal { .fileContainer { diff --git a/www/common/sframe-app-framework.js b/www/common/sframe-app-framework.js index e0b9aa1ea..656b6535f 100644 --- a/www/common/sframe-app-framework.js +++ b/www/common/sframe-app-framework.js @@ -18,7 +18,6 @@ define([ '/bower_components/file-saver/FileSaver.min.js', 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', - 'less!/customize/src/less2/main.less', ], function ( $, Hyperjson, diff --git a/www/contacts/app-contacts.less b/www/contacts/app-contacts.less index 66fdb7a8b..35021bb73 100644 --- a/www/contacts/app-contacts.less +++ b/www/contacts/app-contacts.less @@ -1,14 +1,14 @@ @import (reference) '../../customize/src/less2/include/avatar.less'; @import (reference) '../../customize/src/less2/include/framework.less'; -.framework_min_main( - @bg-color: @colortheme_friends-bg, - @warn-color: @colortheme_friends-warn, - @color: @colortheme_friends-color -); - // body &.cp-app-contacts { + .framework_min_main( + @bg-color: @colortheme_friends-bg, + @warn-color: @colortheme_friends-warn, + @color: @colortheme_friends-color + ); + @keyframes example { 0% { background: rgba(0,0,0,0.1); diff --git a/www/contacts/inner.js b/www/contacts/inner.js index 7f9983c5d..0aa4ecbbc 100644 --- a/www/contacts/inner.js +++ b/www/contacts/inner.js @@ -12,7 +12,7 @@ define([ 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', - 'less!/customize/src/less2/main.less', + 'less!/contacts/app-contacts.less', ], function ( $, Crypto, diff --git a/www/debug/app-debug.less b/www/debug/app-debug.less index c1e8a25b3..d1651642d 100644 --- a/www/debug/app-debug.less +++ b/www/debug/app-debug.less @@ -1,11 +1,11 @@ @import (reference) '../../customize/src/less2/include/tokenfield.less'; @import (reference) '../../customize/src/less2/include/framework.less'; -.tokenfield_main(); -.framework_min_main(); - // body &.cp-app-debug { + .tokenfield_main(); + .framework_min_main(); + display: flex; flex-flow: column; height: 100%; diff --git a/www/debug/inner.js b/www/debug/inner.js index 9968ab13b..5efffd8fe 100644 --- a/www/debug/inner.js +++ b/www/debug/inner.js @@ -16,7 +16,7 @@ define([ 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', - 'less!/customize/src/less2/main.less', + 'less!/debug/app-debug.less', ], function ( $, Crypto, diff --git a/www/drive/app-drive.less b/www/drive/app-drive.less index eabc6df08..8c0c1a083 100644 --- a/www/drive/app-drive.less +++ b/www/drive/app-drive.less @@ -5,865 +5,864 @@ @import (reference) "../../customize/src/less2/include/tokenfield.less"; @import (reference) '../../customize/src/less2/include/framework.less'; -.framework_min_main( - @bg-color: @colortheme_drive-bg, - @warn-color: @colortheme_drive-warn, - @color: @colortheme_drive-color -); +&.cp-app-drive { + .framework_min_main( + @bg-color: @colortheme_drive-bg, + @warn-color: @colortheme_drive-warn, + @color: @colortheme_drive-color + ); -.limit-bar_main(); -.tokenfield_main(); + .limit-bar_main(); + .tokenfield_main(); -@drive_hover: #eee; -@drive_hover-light: lighten(@drive_hover, 20%); -@drive_info-box-bg: #d2e1f2; -@drive_info-box-border: #bbb; -@drive_table-header-fg: #555; -@drive_table-header-bg: #e8e8e8; -@drive_mobile-tree-border-col: #ccc; + @drive_hover: #eee; + @drive_hover-light: lighten(@drive_hover, 20%); + @drive_info-box-bg: #d2e1f2; + @drive_info-box-border: #bbb; + @drive_table-header-fg: #555; + @drive_table-header-bg: #e8e8e8; + @drive_mobile-tree-border-col: #ccc; -@drive_content-fg: @colortheme_sidebar-right-fg; -@drive_content-bg: @colortheme_sidebar-right-bg; -@drive_content-bg-ro: darken(@drive_content-bg, 10%); + @drive_content-fg: @colortheme_sidebar-right-fg; + @drive_content-bg: @colortheme_sidebar-right-bg; + @drive_content-bg-ro: darken(@drive_content-bg, 10%); -/* PAGE */ + /* PAGE */ -display: flex; -flex-flow: column; -max-height: 100%; -min-height: auto; + display: flex; + flex-flow: column; + max-height: 100%; + min-height: auto; -.cp-unselectable { - .tools_unselectable(); -} + .cp-unselectable { + .tools_unselectable(); + } -/* local mixins */ -.drive_fileIcon { - li { - display: inline-block; - margin: 10px 10px; - width: 140px; - height: 140px; - text-align: center; - vertical-align: top; - overflow: hidden; - text-overflow: ellipsis; - padding-top: 5px; - padding-bottom: 5px; - border: 1px solid transparent; - - &:not(.cp-app-drive-element-selected):not(.cp-app-drive-element-selected-tmp) { - border: 1px solid #CCC; - } - .cp-app-drive-element-name { - width: 100%; - height: 24px; - margin: 0; + /* local mixins */ + .drive_fileIcon { + li { display: inline-block; - font-size: 14px; - //align-items: center; - //justify-content: center; + margin: 10px 10px; + width: 140px; + height: 140px; + text-align: center; + vertical-align: top; overflow: hidden; - white-space: nowrap; text-overflow: ellipsis; - word-wrap: break-word; - } - .cp-app-drive-element-truncated { - display: block; - position: absolute; - bottom: 0px; - left: 0; right: 0; - text-align: center; - } - img.cp-app-drive-content-icon { - height: 48px; - max-height: none; - max-width: none; - margin: 8px 0; - } - .fa { - display: block; - margin: auto; - font-size: 64px; - margin: 18px 0; - text-align: center; - &.listonly { - display: none; + padding-top: 5px; + padding-bottom: 5px; + border: 1px solid transparent; + + &:not(.cp-app-drive-element-selected):not(.cp-app-drive-element-selected-tmp) { + border: 1px solid #CCC; + } + .cp-app-drive-element-name { + width: 100%; + height: 24px; + margin: 0; + display: inline-block; + font-size: 14px; + //align-items: center; + //justify-content: center; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + word-wrap: break-word; + } + .cp-app-drive-element-truncated { + display: block; + position: absolute; + bottom: 0px; + left: 0; right: 0; + text-align: center; + } + img.cp-app-drive-content-icon { + height: 48px; + max-height: none; + max-width: none; + margin: 8px 0; + } + .fa { + display: block; + margin: auto; + font-size: 64px; + margin: 18px 0; + text-align: center; + &.listonly { + display: none; + } } } } -} -img.cp-app-drive-icon { - max-width: 20px; - max-height: 16px; -} + img.cp-app-drive-icon { + max-width: 20px; + max-height: 16px; + } -.cp-app-drive-container { - flex: 1; - overflow: auto; - width: 100%; - display: flex; - flex-flow: row; - @media screen and (max-width: @browser_media-medium-screen) { - display: block; - #cp-app-drive-toolbar { - .path .element { - display: none; + .cp-app-drive-container { + flex: 1; + overflow: auto; + width: 100%; + display: flex; + flex-flow: row; + @media screen and (max-width: @browser_media-medium-screen) { + display: block; + #cp-app-drive-toolbar { + .path .element { + display: none; + } } - } - #cp-app-drive-tree { - resize: none; - width: 100%; - max-width: unset; - max-height: unset; - border-bottom: 1px solid @drive_mobile-tree-border-col; - .cp-app-drive-tree-category { - margin-top: 0.5em; + #cp-app-drive-tree { + resize: none; + width: 100%; + max-width: unset; + max-height: unset; + border-bottom: 1px solid @drive_mobile-tree-border-col; + .cp-app-drive-tree-category { + margin-top: 0.5em; + } } } } -} - -div:focus { - outline: none; -} - -.fa { - font-family: FontAwesome; -} - -ul { - list-style: none; - padding-left: 0px; // Remove the default padding -} - -li { - padding: 0px 5px; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -.cp-app-drive-context { - display: none; - position: absolute; - z-index: 500; - li { - padding: 0; - font-size: @colortheme_app-font-size; - a { - cursor: pointer; - } - } -} - -.cp-app-drive-element-droppable { - background-color: #FE9A2E; - color: #222; -} - -.cp-app-drive-element-selected { - background: #666 !important; - color: #eee; - margin: -1px; - .fa-minus-square-o, .fa-plus-square-o { - color: @colortheme_sidebar-left-fg; - } -} - -.cp-app-drive-element-selected-tmp { - border: 1px dotted #bbb; - background: #AAA; - color: #ddd; - margin: -1px; - .fa-minus-square-o, .fa-plus-square-o { - color: @colortheme_sidebar-left-fg; + + div:focus { + outline: none; } -} -span { - &.fa-folder, &.fa-folder-open { - //color: #FEDE8B; - //text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; + .fa { + font-family: FontAwesome; } -} - -/* TREE */ - - -#cp-app-drive-tree { - font-size: @colortheme_app-font-size; - //border-right: 1px solid #ccc; - box-sizing: border-box; - background: @colortheme_sidebar-left-bg; - overflow: auto; - resize: horizontal; - width: auto; - white-space: nowrap; - max-width: 500px; - min-width: 200px; - padding: 0px; - color: @colortheme_sidebar-left-fg; - display: flex; - flex-flow: column; - max-height: 100%; - .cp-app-drive-tree-categories-container { - flex: 1; - max-width: 500px; - overflow: auto; + + ul { + list-style: none; + padding-left: 0px; // Remove the default padding } - img.cp-app-drive-icon { - margin-bottom: 3px; - margin-left: -2px; + + li { + padding: 0px 5px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } - .cp-app-drive-tree-docs { - margin-top: 20px; - //padding: 0 0 0 20px; - padding: 0; - cursor: auto; - &li, li { + + .cp-app-drive-context { + display: none; + position: absolute; + z-index: 500; + li { padding: 0; - &.cp-app-drive-element-collapsed ul { - display: none; - } - input { - width: ~"calc(100% - 30px)"; - padding: 0 10px; - border: 0; - color: lighten(@colortheme_sidebar-left-fg, 40%); - } - & > span.cp-app-drive-element-row { - overflow: hidden; - text-overflow: ellipsis; - //min-width: ~"calc(100% + 5px)"; - .leftside-menu-category_main(); - width: ~"calc(100% + 5px)"; - margin: 0; - margin-bottom: -6px; - display: inline-block; + font-size: @colortheme_app-font-size; + a { cursor: pointer; - margin-left: -5px; - padding-left: 5px; - } - & > span.cp-app-drive-element-row:not(.cp-app-drive-element-selected):not(.cp-app-drive-element-active):hover { } } } - span.cp-app-drive-element { - cursor: pointer; + + .cp-app-drive-element-droppable { + background-color: #FE9A2E; + color: #222; } - .cp-app-drive-tree-category { - margin: 0; - margin-top: 15px; - .cp-app-drive-tree-root { - &> .fa { - min-width: 30px; - cursor: pointer; - } - } - li { - padding: 0; - .cp-app-drive-element-row { - display: block; - padding-left: 20px; - .leftside-menu-category_main(); - margin: 0; - .fa { - width: 25px; - } - } + + .cp-app-drive-element-selected { + background: #666 !important; + color: #eee; + margin: -1px; + .fa-minus-square-o, .fa-plus-square-o { + color: @colortheme_sidebar-left-fg; } } - .cp-app-drive-tree-category:last-child { - margin-bottom: 20px; + + .cp-app-drive-element-selected-tmp { + border: 1px dotted #bbb; + background: #AAA; + color: #ddd; + margin: -1px; + .fa-minus-square-o, .fa-plus-square-o { + color: @colortheme_sidebar-left-fg; + } } - .cp-limit-container { - margin-top: 5px; + + span { + &.fa-folder, &.fa-folder-open { + //color: #FEDE8B; + //text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; + } } - #cp-app-drive-tree-search { - text-align: center; - padding: 0; - position: relative; - input { - background: lighten(@colortheme_drive-bg, 8%); - color: @colortheme_drive-color; - .tools_placeholder-color(@colortheme_drive-color); - outline-width: 0px; - border-radius: 0; - width: 100%; - //border: 1px solid #ccc; - border: 0; - border-right: 1px solid lighten(@colortheme_drive-bg, 16%); - //border-right: 0; - height: @variables_bar-height; - padding: 0 5px; - padding-left: 45px; - &:focus { - outline-width: 0px; + + /* TREE */ + + + #cp-app-drive-tree { + font-size: @colortheme_app-font-size; + //border-right: 1px solid #ccc; + box-sizing: border-box; + background: @colortheme_sidebar-left-bg; + overflow: auto; + resize: horizontal; + width: auto; + white-space: nowrap; + max-width: 500px; + min-width: 200px; + padding: 0px; + color: @colortheme_sidebar-left-fg; + display: flex; + flex-flow: column; + max-height: 100%; + .cp-app-drive-tree-categories-container { + flex: 1; + max-width: 500px; + overflow: auto; + } + img.cp-app-drive-icon { + margin-bottom: 3px; + margin-left: -2px; + } + .cp-app-drive-tree-docs { + margin-top: 20px; + //padding: 0 0 0 20px; + padding: 0; + cursor: auto; + &li, li { + padding: 0; + &.cp-app-drive-element-collapsed ul { + display: none; + } + input { + width: ~"calc(100% - 30px)"; + padding: 0 10px; + border: 0; + color: lighten(@colortheme_sidebar-left-fg, 40%); + } + & > span.cp-app-drive-element-row { + overflow: hidden; + text-overflow: ellipsis; + //min-width: ~"calc(100% + 5px)"; + .leftside-menu-category_main(); + width: ~"calc(100% + 5px)"; + margin: 0; + margin-bottom: -6px; + display: inline-block; + cursor: pointer; + margin-left: -5px; + padding-left: 5px; + } + & > span.cp-app-drive-element-row:not(.cp-app-drive-element-selected):not(.cp-app-drive-element-active):hover { + } } } - .cp-app-drive-tree-search-con { - color: @colortheme_drive-color; - position: absolute; - left: 20px; // TODO align with drive categories - top: 8px; + span.cp-app-drive-element { + cursor: pointer; } - } - .fa.cp-app-drive-icon-expcol { - margin-left: -10px; - font-size: 14px; - position: absolute; - left: -20px; - top: 10px; - width: 11px !important; - height: 11px !important; - padding: 0; - margin: 0; - background: white; - z-index: 10; - cursor: default; - &:before { - position:relative; - top: -1px; + .cp-app-drive-tree-category { + margin: 0; + margin-top: 15px; + .cp-app-drive-tree-root { + &> .fa { + min-width: 30px; + cursor: pointer; + } + } + li { + padding: 0; + .cp-app-drive-element-row { + display: block; + padding-left: 20px; + .leftside-menu-category_main(); + margin: 0; + .fa { + width: 25px; + } + } + } } - } - .cp-app-drive-tree-docs { - .cp-app-drive-tree-root > .cp-app-drive-element-row > .cp-app-drive-icon-expcol { - position: relative; - top:0; - left: -10px; + .cp-app-drive-tree-category:last-child { + margin-bottom: 20px; } - .cp-app-drive-tree-root > .cp-app-drive-element-row > .cp-app-drive-icon-folder { - margin-left: -5px; + .cp-limit-container { + margin-top: 5px; } - .cp-app-drive-tree-root { - &> .cp-app-drive-element-row { - padding-left: 20px; + #cp-app-drive-tree-search { + text-align: center; + padding: 0; + position: relative; + input { + background: lighten(@colortheme_drive-bg, 8%); + color: @colortheme_drive-color; + .tools_placeholder-color(@colortheme_drive-color); + outline-width: 0px; + border-radius: 0; + width: 100%; + //border: 1px solid #ccc; + border: 0; + border-right: 1px solid lighten(@colortheme_drive-bg, 16%); + //border-right: 0; + height: @variables_bar-height; + padding: 0 5px; + padding-left: 45px; + &:focus { + outline-width: 0px; + } } - &> ul { - padding-left: 30px; + .cp-app-drive-tree-search-con { + color: @colortheme_drive-color; + position: absolute; + left: 20px; // TODO align with drive categories + top: 8px; } } - } - - // Expand/collapse lines - .cp-app-drive-tree-docs ul { - margin: 0px 0px 0px 10px; - list-style: none; - padding-left: 10px; - li { - position: relative; + .fa.cp-app-drive-icon-expcol { + margin-left: -10px; + font-size: 14px; + position: absolute; + left: -20px; + top: 10px; + width: 11px !important; + height: 11px !important; + padding: 0; + margin: 0; + background: white; + z-index: 10; + cursor: default; &:before { - position: absolute; - left: -15px; - top: -11px; - content: ''; - display: block; - border-left: 1px solid @colortheme_sidebar-left-branch; - height: ~"calc(1em + 11px)"; - border-bottom: 1px solid @colortheme_sidebar-left-branch; - width: 15px; + position:relative; + top: -1px; } - &:after { - position: absolute; - left: -15px; - bottom: -7px; - content: ''; - display: block; - border-left: 1px solid @colortheme_sidebar-left-branch; - height: 100%; + } + .cp-app-drive-tree-docs { + .cp-app-drive-tree-root > .cp-app-drive-element-row > .cp-app-drive-icon-expcol { + position: relative; + top:0; + left: -10px; } - &.cp-app-drive-tree-root { - margin: 0px 0px 0px -10px; + .cp-app-drive-tree-root > .cp-app-drive-element-row > .cp-app-drive-icon-folder { + margin-left: -5px; + } + .cp-app-drive-tree-root { + &> .cp-app-drive-element-row { + padding-left: 20px; + } + &> ul { + padding-left: 30px; + } + } + } + + // Expand/collapse lines + .cp-app-drive-tree-docs ul { + margin: 0px 0px 0px 10px; + list-style: none; + padding-left: 10px; + li { + position: relative; &:before { - display: none; + position: absolute; + left: -15px; + top: -11px; + content: ''; + display: block; + border-left: 1px solid @colortheme_sidebar-left-branch; + height: ~"calc(1em + 11px)"; + border-bottom: 1px solid @colortheme_sidebar-left-branch; + width: 15px; } &:after { + position: absolute; + left: -15px; + bottom: -7px; + content: ''; + display: block; + border-left: 1px solid @colortheme_sidebar-left-branch; + height: 100%; + } + &.cp-app-drive-tree-root { + margin: 0px 0px 0px -10px; + &:before { + display: none; + } + &:after { + display: none; + } + } + &:last-child:after { display: none; } } - &:last-child:after { - display: none; - } } } -} -/* CONTENT */ -#cp-app-drive-content-container { - display: flex; - flex-flow: column; - flex: 1; - // Needed to avoid the folder's path to overflows - // https://stackoverflow.com/questions/38223879/white-space-nowrap-breaks-flexbox-layout - min-width: 0; -} -#cp-app-drive-content { - box-sizing: border-box; - background: @drive_content-bg; - color: @drive_content-fg; - overflow: auto; - flex: 1; - display: flex; - flex-flow: column; - position: relative; - .cp-app-drive-content-select-box { - display: none; - background-color: rgba(100, 100, 100, 0.7); - position: absolute; - z-index: 50; - } - &.cp-app-drive-readonly { - background: @drive_content-bg-ro; - } - h1 { - padding-left: 10px; - margin-top: 10px; - } - .cp-app-drive-content-info-box { - line-height: 2em; - padding: 0.25em 0.75em; - margin: 1em; - background: @drive_info-box-bg; - span { - cursor: pointer; - float: right; - margin-top: 0.5em; + /* CONTENT */ + #cp-app-drive-content-container { + display: flex; + flex-flow: column; + flex: 1; + // Needed to avoid the folder's path to overflows + // https://stackoverflow.com/questions/38223879/white-space-nowrap-breaks-flexbox-layout + min-width: 0; + } + #cp-app-drive-content { + box-sizing: border-box; + background: @drive_content-bg; + color: @drive_content-fg; + overflow: auto; + flex: 1; + display: flex; + flex-flow: column; + position: relative; + .cp-app-drive-content-select-box { + display: none; + background-color: rgba(100, 100, 100, 0.7); + position: absolute; + z-index: 50; } - } - li { - cursor: default; - &:not(.cp-app-drive-element-header) { - &:hover { - &:not(.-cp-app-drive-element-selected, .cp-app-drive-element-selected-tmp) { - background-color: @drive_hover; - } + &.cp-app-drive-readonly { + background: @drive_content-bg-ro; + } + h1 { + padding-left: 10px; + margin-top: 10px; + } + .cp-app-drive-content-info-box { + line-height: 2em; + padding: 0.25em 0.75em; + margin: 1em; + background: @drive_info-box-bg; + span { + cursor: pointer; + float: right; + margin-top: 0.5em; } } - } - #cp-app-drive-content-folder { li { - &.cp-app-drive-search-result { - border-bottom: 1px solid @drive_info-box-border; - display: block; + cursor: default; + &:not(.cp-app-drive-element-header) { &:hover { - background-color: initial; + &:not(.-cp-app-drive-element-selected, .cp-app-drive-element-selected-tmp) { + background-color: @drive_hover; + } } - table { - width: 100%; - .cp-app-drive-search-label2 { - width: 150px; - font-size: 15px; - text-align: right; - padding-right: 15px; + } + } + #cp-app-drive-content-folder { + li { + &.cp-app-drive-search-result { + border-bottom: 1px solid @drive_info-box-border; + display: block; + &:hover { + background-color: initial; } - .cp-app-drive-search-opendir { - display: flex; - justify-content: space-between; - a { + table { + width: 100%; + .cp-app-drive-search-label2 { + width: 150px; + font-size: 15px; + text-align: right; + padding-right: 15px; + } + .cp-app-drive-search-opendir { + display: flex; + justify-content: space-between; + a { + cursor: pointer; + color: #41b7d8; + &:hover { + color: #014c8c; + text-decoration: underline; + } + } + } + .cp-app-drive-search-path { + font-style: italic; + direction: rtl; + .cp-app-drive-path-element { + display: inline-block; + margin-right: 5px; + } + } + .cp-app-drive-search-title { + font-weight: bold; cursor: pointer; - color: #41b7d8; &:hover { - color: #014c8c; - text-decoration: underline; + background-color: @drive_hover; } } - } - .cp-app-drive-search-path { - font-style: italic; - direction: rtl; - .cp-app-drive-path-element { - display: inline-block; - margin-right: 5px; + .cp-app-drive-search-col2 { + width: 250px; } - } - .cp-app-drive-search-title { - font-weight: bold; - cursor: pointer; - &:hover { - background-color: @drive_hover; + td.cp-app-drive-search-icon { + width: 50px; + font-size: 40px; } } - .cp-app-drive-search-col2 { - width: 250px; - } - td.cp-app-drive-search-icon { - width: 50px; - font-size: 40px; - } } - } - &.cp-app-drive-tags-list { - width: 100%; - table { - margin: 10px 50px; - width: ~"calc(100% - 100px)"; - table-layout: fixed; - td, th { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + &.cp-app-drive-tags-list { + width: 100%; + table { + margin: 10px 50px; + width: ~"calc(100% - 100px)"; + table-layout: fixed; + td, th { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } } } } } - } - .cp-app-drive-element { - .cp-app-drive-element-truncated { display: none; } - } - div.cp-app-drive-content-grid { - padding: 20px; - .drive_fileIcon; - li { - &.cp-app-drive-element { - position: relative; - } - input { - width: 100%; - margin: 0; - padding: 0; - border-radius: 0; - border: 1px solid #ddd; - font-size: 14px; - } - .cp-app-drive-element-state { - position: absolute; - top: 3px; - right: 3px; - .fa { - margin:0; - font-size: 18px; + .cp-app-drive-element { + .cp-app-drive-element-truncated { display: none; } + } + div.cp-app-drive-content-grid { + padding: 20px; + .drive_fileIcon; + li { + &.cp-app-drive-element { + position: relative; } - } - .cp-app-drive-element-thumbnail { - max-width: 100px; - max-height: 100px; - & ~ .fa { - display: inline; - font-size: 17px; + input { + width: 100%; + margin: 0; + padding: 0; + border-radius: 0; + border: 1px solid #ddd; + font-size: 14px; + } + .cp-app-drive-element-state { position: absolute; top: 3px; - left: 3px; - margin: 0; + right: 3px; + .fa { + margin:0; + font-size: 18px; + } + } + .cp-app-drive-element-thumbnail { + max-width: 100px; + max-height: 100px; + & ~ .fa { + display: inline; + font-size: 17px; + position: absolute; + top: 3px; + left: 3px; + margin: 0; + } } } - } - .cp-app-drive-element-list { - display: none; - } - .cp-app-drive-new-ghost { - cursor: pointer; - opacity: 0.5; - padding: 0; - flex-flow: column; - align-items: center; - justify-content: center; - display: inline-flex; - &:hover { - opacity: 0.7; + .cp-app-drive-element-list { + display: none; } - .fa { + .cp-app-drive-new-ghost { cursor: pointer; - font-size: 90px; - margin-top: 5px; - margin-bottom: 0; + opacity: 0.5; + padding: 0; + flex-flow: column; + align-items: center; + justify-content: center; + display: inline-flex; + &:hover { + opacity: 0.7; + } + .fa { + cursor: pointer; + font-size: 90px; + margin-top: 5px; + margin-bottom: 0; + } } } - } - .cp-app-drive-content-list { - .cp-app-drive-element-grid { - display: none; - } - // Make it act as a table! - padding-left: 20px; - ul { - display: table; - width: 100%; - padding: 0px 10px; - } - li { - display: table-row; - input { - border: 1px solid #ddd; - margin: 0; - padding: 0 4px; - } - &> span { - padding: 0 5px; - display: table-cell; + .cp-app-drive-content-list { + .cp-app-drive-element-grid { + display: none; } - &:not(.cp-app-drive-element-header) { - height: @variables_bar-height; - line-height: @variables_bar-height; + // Make it act as a table! + padding-left: 20px; + ul { + display: table; + width: 100%; + padding: 0px 10px; } - &.cp-app-drive-element-header { - cursor: default; - color: @drive_table-header-fg; - span { - &:not(.fa) { - text-align: left; - } - &.sortasc, &.sortdesc { - float: right; - } + li { + display: table-row; + input { + border: 1px solid #ddd; + margin: 0; + padding: 0 4px; } &> span { - padding: 15px 5px; - &.cp-app-drive-sort-active { - font-weight: bold; + padding: 0 5px; + display: table-cell; + } + &:not(.cp-app-drive-element-header) { + height: @variables_bar-height; + line-height: @variables_bar-height; + } + &.cp-app-drive-element-header { + cursor: default; + color: @drive_table-header-fg; + span { + &:not(.fa) { + text-align: left; + } + &.sortasc, &.sortdesc { + float: right; + } } - &.cp-app-drive-sort-clickable { - cursor: pointer; - &:hover { - background: @drive_table-header-bg; + &> span { + padding: 15px 5px; + &.cp-app-drive-sort-active { + font-weight: bold; + } + &.cp-app-drive-sort-clickable { + cursor: pointer; + &:hover { + background: @drive_table-header-bg; + } } } } } - } - .cp-app-drive-element { - span { - overflow: hidden; - white-space: nowrap; - box-sizing: border-box; - &.cp-app-drive-element-state { - .fa:not(:last-child) { - margin-right: 5px; + .cp-app-drive-element { + span { + overflow: hidden; + white-space: nowrap; + box-sizing: border-box; + &.cp-app-drive-element-state { + .fa:not(:last-child) { + margin-right: 5px; + } } - } - &.cp-app-drive-content-icon, &.cp-app-drive-element-state, &.cp-icon { - width: 30px; - } - &.cp-app-drive-element-type, &.cp-app-drive-element-atime, &.cp-app-drive-element-ctime { - width: 175px; - } - &.cp-app-drive-element-title { - width: 250px; - @media screen and (max-width: 1200px) { - display: none; + &.cp-app-drive-content-icon, &.cp-app-drive-element-state, &.cp-icon { + width: 30px; + } + &.cp-app-drive-element-type, &.cp-app-drive-element-atime, &.cp-app-drive-element-ctime { + width: 175px; + } + &.cp-app-drive-element-title { + width: 250px; + @media screen and (max-width: 1200px) { + display: none; + } + } + &.cp-app-drive-element-folders, &.cp-app-drive-element-files { + width: 150px; } - } - &.cp-app-drive-element-folders, &.cp-app-drive-element-files { - width: 150px; } } } } -} -#cp-app-drive-content-folder { - padding-right: 10px; - flex: 1; -} + #cp-app-drive-content-folder { + padding-right: 10px; + flex: 1; + } -#cp-app-drive-new-ghost-dialog.cp-modal-container { - .drive_fileIcon; + #cp-app-drive-new-ghost-dialog.cp-modal-container { + .drive_fileIcon; - li:not(.cp-app-drive-element-selected):hover { - border: 1px solid white; - } - .cp-modal { - display: flex; - flex-flow: column; - li, li .fa { - cursor: pointer; - } - &> p { - margin: 50px; + li:not(.cp-app-drive-element-selected):hover { + border: 1px solid white; } - &> div { + .cp-modal { display: flex; - flex-wrap: wrap; - justify-content: center; - align-content: center; - overflow-y: auto; - .cp-app-drive-new-upload { - break-after: always; - page-break-after: always; + flex-flow: column; + li, li .fa { + cursor: pointer; + } + &> p { + margin: 50px; + } + &> div { + display: flex; + flex-wrap: wrap; + justify-content: center; + align-content: center; + overflow-y: auto; + .cp-app-drive-new-upload { + break-after: always; + page-break-after: always; + } } } - } - .cp-app-drive-new-name { - white-space: nowrap; - } + .cp-app-drive-new-name { + white-space: nowrap; + } - @media screen and (max-height: @browser_media-not-big) { - .cp-modal { - & > p { - display: none; - } - & > div { - align-content: unset; - li { - height: 40px; - width: 90%; - display: flex; - align-items: center; - .fa { - font-size: 32px; - } - .cp-app-drive-new-name { - height: auto; + @media screen and (max-height: @browser_media-not-big) { + .cp-modal { + & > p { + display: none; + } + & > div { + align-content: unset; + li { + height: 40px; + width: 90%; + display: flex; + align-items: center; + .fa { + font-size: 32px; + } + .cp-app-drive-new-name { + height: auto; + } } } } } } -} -/* Toolbar */ + /* Toolbar */ -#cp-app-drive-toolbar { - background: lighten(@colortheme_drive-bg, 8%); - color: @colortheme_drive-color; - //height: 30px; - //display: flex; - //flex-flow: row; - z-index: 100; - box-sizing: border-box; - height: @variables_bar-height; - padding: 0; - display: flex; - flex-flow: row; + #cp-app-drive-toolbar { + background: lighten(@colortheme_drive-bg, 8%); + color: @colortheme_drive-color; + //height: 30px; + //display: flex; + //flex-flow: row; + z-index: 100; + box-sizing: border-box; + height: @variables_bar-height; + padding: 0; + display: flex; + flex-flow: row; - * { - outline-width: 0; - &:focus { + * { outline-width: 0; + &:focus { + outline-width: 0; + } } - } - .cp-toolbar-icon-history { - float: right; - .cp-toolbar-drawer-element { - display: none; + .cp-toolbar-icon-history { + float: right; + .cp-toolbar-drawer-element { + display: none; + } } - } - .cp-app-drive-toolbar-rightside, .cp-app-drive-toolbar-leftside { - display: inline-block; - margin: 0; - padding: 0; - .fa { + .cp-app-drive-toolbar-rightside, .cp-app-drive-toolbar-leftside { + display: inline-block; margin: 0; - } - button { - height: @variables_bar-height; - padding: 0 10px; - border: none; - border-radius: 0; - box-sizing: border-box; - background: transparent; - font-size: @colortheme_app-font-size; - color: @colortheme_drive-color; - transition: all 0.15s; - .drawer { - display: none; + padding: 0; + .fa { + margin: 0; } - .fa, span { + button { + height: @variables_bar-height; + padding: 0 10px; + border: none; + border-radius: 0; + box-sizing: border-box; + background: transparent; font-size: @colortheme_app-font-size; - } - &:hover { - background: @colortheme_drive-bg; - } - &.cp-app-drive-toolbar-active { - display: none; + color: @colortheme_drive-color; + transition: all 0.15s; + .drawer { + display: none; + } + .fa, span { + font-size: @colortheme_app-font-size; + } + &:hover { + background: @colortheme_drive-bg; + } + &.cp-app-drive-toolbar-active { + display: none; + } } } - } - .cp-app-drive-toolbar-rightside { - float: right; - & > * { + .cp-app-drive-toolbar-rightside { float: right; + & > * { + float: right; + } + #cp-app-drive-toolbar-contextbuttons { + display: inline-block; + height: 100%; + } + padding-left: 10px; } - #cp-app-drive-toolbar-contextbuttons { - display: inline-block; - height: 100%; - } - padding-left: 10px; - } - .cp-app-drive-toolbar-leftside { - & > span { - height: 100%; - margin: 0; - } - button { - padding: 0 10px; - .fa { - margin-right: 5px; + .cp-app-drive-toolbar-leftside { + & > span { + height: 100%; + margin: 0; } - .cp-dropdown-button-title { - display: inline-flex; - height: @variables_bar-height; - align-items: center; - span:not(.fa) { - line-height: 23px; + button { + padding: 0 10px; + .fa { + margin-right: 5px; + } + .cp-dropdown-button-title { + display: inline-flex; + height: @variables_bar-height; + align-items: center; + span:not(.fa) { + line-height: 23px; + } } } } - } - button { - font: @colortheme_app-font; - span { + button { font: @colortheme_app-font; + span { + font: @colortheme_app-font; + } + .fa, &.fa { + font-family: FontAwesome; + } } - .fa, &.fa { - font-family: FontAwesome; + /* The container
            - needed to position the dropdown content */ + .cp-dropdown-container { + margin: 2px 2px; + line-height: 1em; + position: relative; + display: inline-block; + } + .cp-dropdown-content { + margin-right: 2px; } - } - /* The container
            - needed to position the dropdown content */ - .cp-dropdown-container { - margin: 2px 2px; - line-height: 1em; - position: relative; - display: inline-block; - } - .cp-dropdown-content { - margin-right: 2px; - } - .cp-app-drive-path { - flex: 1; - width: 100%; - height: @variables_bar-height; - line-height: @variables_bar-height; - cursor: default; - width: auto; - overflow: hidden; - white-space: nowrap; - direction: rtl; - max-width: 100%; - text-align: left; - .cp-app-drive-path-element { - display: inline-block; + .cp-app-drive-path { + flex: 1; + width: 100%; height: @variables_bar-height; line-height: @variables_bar-height; - font-size: @colortheme_app-font-size; - padding: 0 5px; - border: 0; - background: darken(@colortheme_drive-bg, 10%); - color: @colortheme_drive-color; - box-sizing: border-box; - transition: all 0.15s; - &.cp-app-drive-path-separator { - color: #ccc; - } - &.cp-app-drive-path-lickable { - cursor: pointer; - &:hover { - background: darken(@colortheme_drive-bg, 15%); + cursor: default; + width: auto; + overflow: hidden; + white-space: nowrap; + direction: rtl; + max-width: 100%; + text-align: left; + .cp-app-drive-path-element { + display: inline-block; + height: @variables_bar-height; + line-height: @variables_bar-height; + font-size: @colortheme_app-font-size; + padding: 0 5px; + border: 0; + background: darken(@colortheme_drive-bg, 10%); + color: @colortheme_drive-color; + box-sizing: border-box; + transition: all 0.15s; + &.cp-app-drive-path-separator { + color: #ccc; + } + &.cp-app-drive-path-lickable { + cursor: pointer; + &:hover { + background: darken(@colortheme_drive-bg, 15%); + } } } } } -} - - - +} \ No newline at end of file diff --git a/www/drive/inner.js b/www/drive/inner.js index d072992d6..5e3207019 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -19,7 +19,7 @@ define([ 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', - 'less!/customize/src/less2/main.less', + 'less!/drive/app-drive.less', ], function ( $, Toolbar, diff --git a/www/file/app-file.less b/www/file/app-file.less index 9d78d5ec3..20428b382 100644 --- a/www/file/app-file.less +++ b/www/file/app-file.less @@ -1,149 +1,152 @@ @import (reference) '../../customize/src/less2/include/tokenfield.less'; @import (reference) '../../customize/src/less2/include/framework.less'; -.framework_min_main( - @bg-color: @colortheme_file-bg, - @warn-color: @colortheme_file-warn, - @color: @colortheme_file-color -); -.tokenfield_main(); +&.cp-app-file { -@button-border: 2px; + .framework_min_main( + @bg-color: @colortheme_file-bg, + @warn-color: @colortheme_file-warn, + @color: @colortheme_file-color + ); + .tokenfield_main(); -// body -display: flex; -flex-flow: column; + @button-border: 2px; -#cp-app-file-content { - flex: 1; + // body display: flex; - justify-content: center; - align-items: center; flex-flow: column; - min-height: 0; -} - -#cp-app-file-content.ready { - //background: url('/customize/bg3.jpg') no-repeat center center; - background-size: cover; - background-position: center; -} - -#cp-app-file-upfile, #cp-app-file-dlfile { - display: block; - height: 100%; - width: 100%; - border: @button-border solid black; -} - -.cp-app-file-input { - width: 0.1px; - height: 0.1px; - opacity: 0; - overflow: hidden; - position: absolute; - z-index: -1; -} - -media-tag { - img { - max-width: 100%; - max-height: ~"calc(100vh - 96px)"; - } -} - -#cp-app-file-upload-form, #cp-app-file-download-form { - padding: 0px; - margin: 0px; - - position: relative; - width: 50vh; - height: 50vh; - display: block; - margin: 50px auto; - max-width: 80vw; - label { - line-height: ~"calc(50vh - 20px)"; - text-align: center; - position: relative; - padding: 10px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - height: 50vh; - box-sizing: border-box; - } -} -#cp-app-file-download-form { - label { + + #cp-app-file-content { + flex: 1; display: flex; justify-content: center; align-items: center; - white-space: normal; - word-wrap: break-word; - span { - width: 50vh; - max-width: 80vw; + flex-flow: column; + min-height: 0; + } + + #cp-app-file-content.ready { + //background: url('/customize/bg3.jpg') no-repeat center center; + background-size: cover; + background-position: center; + } + + #cp-app-file-upfile, #cp-app-file-dlfile { + display: block; + height: 100%; + width: 100%; + border: @button-border solid black; + } + + .cp-app-file-input { + width: 0.1px; + height: 0.1px; + opacity: 0; + overflow: hidden; + position: absolute; + z-index: -1; + } + + media-tag { + img { + max-width: 100%; + max-height: ~"calc(100vh - 96px)"; + } + } + + #cp-app-file-upload-form, #cp-app-file-download-form { + padding: 0px; + margin: 0px; + + position: relative; + width: 50vh; + height: 50vh; + display: block; + margin: 50px auto; + max-width: 80vw; + label { + line-height: ~"calc(50vh - 20px)"; text-align: center; - line-height: 1.5em; + position: relative; + padding: 10px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + height: 50vh; + box-sizing: border-box; } } -} -.cp-app-file-hovering { - background-color: rgba(255, 0, 115, 0.5) !important; -} - -.cp-app-file-block { - display: block; -} -.cp-app-file-hidden { - display: none; -} -.cp-app-file-input + label { - //border: 2px solid black; - //background-color: rgba(50, 50, 50, .10); - display: block; -} - -.cp-app-file-input:focus + label, -.cp-app-file-input + label:hover { - //background-color: rgba(50, 50, 50, 0.30); -} - -#cp-app-file-dlprogress { - position: absolute; - top: 0; - left: 0; - height: 100%; - - - transition: width 200ms; - width: 0%; - max-width: 100%; - max-height: 100%; - background-color: rgba(255, 0, 115, 0.75); - z-index: 10000; - display: block; -} - -#cp-app-file-download-view { - flex: 1; - display: flex; - min-height: 0; - align-items: center; - justify-content: center; - flex-flow: column; - media-tag { + #cp-app-file-download-form { + label { + display: flex; + justify-content: center; + align-items: center; + white-space: normal; + word-wrap: break-word; + span { + width: 50vh; + max-width: 80vw; + text-align: center; + line-height: 1.5em; + } + } + } + .cp-app-file-hovering { + background-color: rgba(255, 0, 115, 0.5) !important; + } + + .cp-app-file-block { + display: block; + } + .cp-app-file-hidden { + display: none; + } + .cp-app-file-input + label { + //border: 2px solid black; + //background-color: rgba(50, 50, 50, .10); + display: block; + } + + .cp-app-file-input:focus + label, + .cp-app-file-input + label:hover { + //background-color: rgba(50, 50, 50, 0.30); + } + + #cp-app-file-dlprogress { + position: absolute; + top: 0; + left: 0; + height: 100%; + + + transition: width 200ms; + width: 0%; + max-width: 100%; + max-height: 100%; + background-color: rgba(255, 0, 115, 0.75); + z-index: 10000; + display: block; + } + + #cp-app-file-download-view { flex: 1; - min-height: 0; - max-width: 100vw; display: flex; + min-height: 0; align-items: center; justify-content: center; - &> * { - max-height: 100%; - max-width: 100%; + flex-flow: column; + media-tag { + flex: 1; + min-height: 0; + max-width: 100vw; + display: flex; + align-items: center; + justify-content: center; + &> * { + max-height: 100%; + max-width: 100%; + } } - } -} + } +} \ No newline at end of file diff --git a/www/file/inner.js b/www/file/inner.js index e9e2d868d..b184d6b9b 100644 --- a/www/file/inner.js +++ b/www/file/inner.js @@ -17,7 +17,7 @@ define([ 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', - 'less!/customize/src/less2/main.less', + 'less!/file/app-file.less', ], function ( $, diff --git a/www/filepicker/app-filepicker.less b/www/filepicker/app-filepicker.less index 712700451..03780c796 100644 --- a/www/filepicker/app-filepicker.less +++ b/www/filepicker/app-filepicker.less @@ -7,78 +7,79 @@ @import (reference) '../../customize/src/less2/include/checkmark.less'; @import (reference) '../../customize/src/less2/include/password-input.less'; -.iconColors_main(); -.fileupload_main(); -.alertify_main(); -.tippy_main(); -.checkmark_main(20px); -.password_main(); -.modal_main(); +&.cp-app-filepicker { + .iconColors_main(); + .fileupload_main(); + .alertify_main(); + .tippy_main(); + .checkmark_main(20px); + .password_main(); + .modal_main(); -#cp-filepicker-dialog { - display: none; - .cp-modal { - .cp-filepicker-content { - display: flex; - flex-wrap: wrap; - justify-content: center; - overflow-y: auto; - } + #cp-filepicker-dialog { + display: none; + .cp-modal { + .cp-filepicker-content { + display: flex; + flex-wrap: wrap; + justify-content: center; + overflow-y: auto; + } - .cp-filepicker-content-element { - @darker: darken(@colortheme_modal-fg, 30%); + .cp-filepicker-content-element { + @darker: darken(@colortheme_modal-fg, 30%); - width: 125px; - //min-width: 200px; - //height: 1em; - padding: 10px; - margin: 5px; + width: 125px; + //min-width: 200px; + //height: 1em; + padding: 10px; + margin: 5px; - display: inline-flex; - flex-flow: column; + display: inline-flex; + flex-flow: column; - box-sizing: content-box; + box-sizing: content-box; - text-align: left; - line-height: 1em; - cursor: pointer; + text-align: left; + line-height: 1em; + cursor: pointer; - background-color: @colortheme_modal-bg; - box-shadow: 2px 2px 5px #000; - color: @darker; + background-color: @colortheme_modal-bg; + box-shadow: 2px 2px 5px #000; + color: @darker; - transition: all 0.1s; + transition: all 0.1s; - &:hover { - color: @colortheme_modal-fg; - } + &:hover { + color: @colortheme_modal-fg; + } - align-items: center; + align-items: center; - img { - max-width: 100px; - max-height: 100px; - background: #fff; - } + img { + max-width: 100px; + max-height: 100px; + background: #fff; + } - .cp-filepicker-content-element-name { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - height: 20px; - line-height: 20px; - margin-top: 5px; - max-width: 100%; - } - .fa { - cursor: pointer; - width: 100px; - height: 100px; - font-size: 70px; - text-align: center; - line-height: 100px; + .cp-filepicker-content-element-name { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + height: 20px; + line-height: 20px; + margin-top: 5px; + max-width: 100%; + } + .fa { + cursor: pointer; + width: 100px; + height: 100px; + font-size: 70px; + text-align: center; + line-height: 100px; + } } } } -} - +} \ No newline at end of file diff --git a/www/filepicker/inner.js b/www/filepicker/inner.js index c30ada772..0ca8bddcc 100644 --- a/www/filepicker/inner.js +++ b/www/filepicker/inner.js @@ -12,7 +12,7 @@ define([ 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', - 'less!/customize/src/less2/main.less', + 'less!/filepicker/app-filepicker.less', ], function ( $, Crypto, diff --git a/www/kanban/app-kanban.less b/www/kanban/app-kanban.less index 417f4fd14..190a8e548 100644 --- a/www/kanban/app-kanban.less +++ b/www/kanban/app-kanban.less @@ -2,12 +2,14 @@ @import (reference) "../../customize/src/less2/include/framework.less"; @import (reference) "../../customize/src/less2/include/tools.less"; -.framework_main( @bg-color: @colortheme_kanban-bg, -@warn-color: @colortheme_kanban-warn, -@color: @colortheme_kanban-color); - // body &.cp-app-kanban { + .framework_main( + @bg-color: @colortheme_kanban-bg, + @warn-color: @colortheme_kanban-warn, + @color: @colortheme_kanban-color + ); + display: flex; flex-flow: column; max-height: 100%; diff --git a/www/kanban/inner.js b/www/kanban/inner.js index 647032548..11eb4f932 100644 --- a/www/kanban/inner.js +++ b/www/kanban/inner.js @@ -11,6 +11,8 @@ define([ '/customize/messages.js', '/kanban/jkanban.js', 'css!/kanban/jkanban.css', + + 'less!/kanban/app-kanban.less' ], function ( $, Sortify, diff --git a/www/pad/app-pad.less b/www/pad/app-pad.less index 74862650c..1bc4db423 100644 --- a/www/pad/app-pad.less +++ b/www/pad/app-pad.less @@ -1,15 +1,12 @@ @import (reference) "../../customize/src/less2/include/framework.less"; -.framework_main( - @bg-color: @colortheme_pad-bg, - @warn-color: @colortheme_pad-warn, - @color: @colortheme_pad-color -); -.alertify_main(); +body.cp-app-pad { + .framework_main( + @bg-color: @colortheme_pad-bg, + @warn-color: @colortheme_pad-warn, + @color: @colortheme_pad-color + ); -// body -&.cp-app-pad { - .tokenfield_main(); #cke_1_top { overflow: visible; padding: 0px; @@ -46,17 +43,16 @@ } } -} - -.cke_wysiwyg_frame { - min-width: 60%; -} - -@media print { - #cke_1_top { - display:none !important; + .cke_wysiwyg_frame { + min-width: 60%; } - &.cp-app-pad .cp-toolbar-userlist-drawer { - display:none; + + @media print { + #cke_1_top { + display:none !important; + } + &.cp-app-pad .cp-toolbar-userlist-drawer { + display:none; + } } -} +} \ No newline at end of file diff --git a/www/pad/inner.js b/www/pad/inner.js index 865be9ef8..a564a9687 100644 --- a/www/pad/inner.js +++ b/www/pad/inner.js @@ -37,7 +37,7 @@ define([ 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', - 'less!/customize/src/less2/main.less', + 'less!/pad/app-pad.less' ], function ( $, Hyperjson, diff --git a/www/poll/app-poll.less b/www/poll/app-poll.less index 69713cce9..c1920ca5a 100644 --- a/www/poll/app-poll.less +++ b/www/poll/app-poll.less @@ -2,668 +2,671 @@ @import (reference) '../../customize/src/less2/include/avatar.less'; @import (reference) "../../customize/src/less2/include/framework.less"; -.framework_main( - @bg-color: @colortheme_poll-bg, - @warn-color: @colortheme_poll-warn, - @color: @colortheme_poll-color -); - -@poll-fore: #555; - -@poll-th-bg: @colortheme_poll-th-bg; -@poll-th-fg: @colortheme_poll-th-fg; -@poll-th-user-bg: darken(@poll-th-bg, 10%); -@poll-editing: lighten(@poll-th-bg, 10%); -@poll-winner: darken(@poll-th-bg, 15%); -@poll-highlighted: lighten(@poll-th-bg, 15%); -@poll-td-bg: @poll-th-bg; -@poll-td-fg: @poll-th-fg; - -@poll-help-bg: @colortheme_poll-help-bg; - -@poll-uncommitted-cell: #eee; -@poll-uncommitted-bg: #ddd; //lighten(@poll-th-bg, 50%); -@poll-uncommitted-text: black; - -@poll-placeholder: #fff; -@poll-border-color: #555; -@poll-cover-color: #000; -@poll-fg: #000; -@poll-option-yellow: #ff5; -@poll-option-gray: #ccc; - -@poll-add-color: #fff; -@poll-add-bg: #777; -@poll-add-bg-alt: #444; - -.bottom-left(@s: 5px) { border-bottom-left-radius: @s; } -.top-left(@s: 5px) { border-top-left-radius: @s; } - -display: flex; -flex-flow: column; -overflow-x: hidden; - -#cp-app-poll-content { +&.cp-app-poll { + + .framework_main( + @bg-color: @colortheme_poll-bg, + @warn-color: @colortheme_poll-warn, + @color: @colortheme_poll-color + ); + + @poll-fore: #555; + + @poll-th-bg: @colortheme_poll-th-bg; + @poll-th-fg: @colortheme_poll-th-fg; + @poll-th-user-bg: darken(@poll-th-bg, 10%); + @poll-editing: lighten(@poll-th-bg, 10%); + @poll-winner: darken(@poll-th-bg, 15%); + @poll-highlighted: lighten(@poll-th-bg, 15%); + @poll-td-bg: @poll-th-bg; + @poll-td-fg: @poll-th-fg; + + @poll-help-bg: @colortheme_poll-help-bg; + + @poll-uncommitted-cell: #eee; + @poll-uncommitted-bg: #ddd; //lighten(@poll-th-bg, 50%); + @poll-uncommitted-text: black; + + @poll-placeholder: #fff; + @poll-border-color: #555; + @poll-cover-color: #000; + @poll-fg: #000; + @poll-option-yellow: #ff5; + @poll-option-gray: #ccc; + + @poll-add-color: #fff; + @poll-add-bg: #777; + @poll-add-bg-alt: #444; + + .bottom-left(@s: 5px) { border-bottom-left-radius: @s; } + .top-left(@s: 5px) { border-top-left-radius: @s; } + display: flex; - flex: 1; - min-height: 0; - #cp-app-poll-form { + flex-flow: column; + overflow-x: hidden; + + #cp-app-poll-content { + display: flex; flex: 1; - overflow-y: auto; - &.cp-app-poll-readonly { - #cp-app-poll-table-scroll { - max-width: ~"calc(75% - 30px - 100px)"; - } - table { - width: 100%; - } - table tr td:last-child { - margin-left: 0; // uncommitted is hidden + min-height: 0; + #cp-app-poll-form { + flex: 1; + overflow-y: auto; + &.cp-app-poll-readonly { + #cp-app-poll-table-scroll { + max-width: ~"calc(75% - 30px - 100px)"; + } + table { + width: 100%; + } + table tr td:last-child { + margin-left: 0; // uncommitted is hidden + } + td.cp-app-poll-table-uncommitted { + display: none; + } } - td.cp-app-poll-table-uncommitted { - display: none; + &.cp-app-poll-published { + #cp-app-poll-create-option { + display: none; + } + .cp-app-poll-table-remove[data-rt-id^="y"], .cp-app-poll-table-edit[data-rt-id^="y"] { + display: none; + } + tr.cp-app-poll-table-uncommitted { + display: none; + } } } - &.cp-app-poll-published { - #cp-app-poll-create-option { - display: none; - } - .cp-app-poll-table-remove[data-rt-id^="y"], .cp-app-poll-table-edit[data-rt-id^="y"] { - display: none; - } - tr.cp-app-poll-table-uncommitted { - display: none; - } + } + + input[type="text"], textarea { + background-color: white; + color: black; + border: 0; + } + + input[type="text"][disabled], textarea[disabled] { + background-color: transparent; + border: 0px; + } + + // The placeholder color only seems to effect Safari when not set + + input[type="text"][disabled]::placeholder { + color: @poll-placeholder; + opacity: 1; + } + + table#cp-app-poll-table { + margin: 0px; + overflow: hidden; + } + #cp-app-poll-table-container { + position: relative; + margin: 20px; + } + #cp-app-poll-table-container button { + border-radius: 0; + border: 0; + } + #cp-app-poll-create-user { + display: inline-flex; + height: 20px; + padding: 0 5px; + margin: 2px auto; + width: auto; + overflow: hidden; + color: @poll-add-color; + background: @poll-add-bg; + &:hover { + background: @poll-add-bg-alt; } } -} - -input[type="text"], textarea { - background-color: white; - color: black; - border: 0; -} - -input[type="text"][disabled], textarea[disabled] { - background-color: transparent; - border: 0px; -} - -// The placeholder color only seems to effect Safari when not set - -input[type="text"][disabled]::placeholder { - color: @poll-placeholder; - opacity: 1; -} - -table#cp-app-poll-table { - margin: 0px; - overflow: hidden; -} -#cp-app-poll-table-container { - position: relative; - margin: 20px; -} -#cp-app-poll-table-container button { - border-radius: 0; - border: 0; -} -#cp-app-poll-create-user { - display: inline-flex; - height: 20px; - padding: 0 5px; - margin: 2px auto; - width: auto; - overflow: hidden; - color: @poll-add-color; - background: @poll-add-bg; - &:hover { - background: @poll-add-bg-alt; + #cp-app-poll-create-option { + order: 3; + display: inline-flex; + width: 46px; + height: 20px; + margin: 2px; + padding: 0; + color: @poll-add-color; + background: @poll-add-bg; + &:hover { + background: @poll-add-bg-alt; + } } -} -#cp-app-poll-create-option { - order: 3; - display: inline-flex; - width: 46px; - height: 20px; - margin: 2px; - padding: 0; - color: @poll-add-color; - background: @poll-add-bg; - &:hover { - background: @poll-add-bg-alt; + #cp-app-poll-table-scroll { + overflow-y: hidden; + overflow-x: auto; + margin-left: 25%; + max-width: ~"calc(75% - 100px - 100px)"; + width: auto; + display: inline-block; } -} -#cp-app-poll-table-scroll { - overflow-y: hidden; - overflow-x: auto; - margin-left: 25%; - max-width: ~"calc(75% - 100px - 100px)"; - width: auto; - display: inline-block; -} -.cp-markdown-toolbar { - margin: auto; - min-width: 80%; - width: 80%; -} -#cp-app-poll-description { - &~ .CodeMirror { + .cp-markdown-toolbar { margin: auto; min-width: 80%; width: 80%; - min-height: 200px; - height: 200px; - border: 1px solid black; - .CodeMirror-placeholder { - color: #777; + } + #cp-app-poll-description { + &~ .CodeMirror { + margin: auto; + min-width: 80%; + width: 80%; + min-height: 200px; + height: 200px; + border: 1px solid black; + .CodeMirror-placeholder { + color: #777; + } } } -} -#cp-app-poll-description-published { - display: none; - padding: 15px; - margin: auto; - - min-width: 80%; - width: 80%; - min-height: 7em; - color: #000; - border: 1px solid transparent; - background-color: #eeeeee; - font: @colortheme_app-font; - text-align: left; - media-tag > * { - max-width: 100%; - max-height: 20em; + #cp-app-poll-description-published { + display: none; + padding: 15px; + margin: auto; + + min-width: 80%; + width: 80%; + min-height: 7em; + color: #000; + border: 1px solid transparent; + background-color: #eeeeee; + font: @colortheme_app-font; + text-align: left; + media-tag > * { + max-width: 100%; + max-height: 20em; + } } -} -div.cp-app-poll-published { - div.cp-app-poll-realtime { - #cp-app-poll-description { - display: none; - &~ .CodeMirror { + div.cp-app-poll-published { + div.cp-app-poll-realtime { + #cp-app-poll-description { display: none; + &~ .CodeMirror { + display: none; + } } - } - #cp-app-poll-description-published { - display: block; - &:empty { + #cp-app-poll-description-published { + display: block; + &:empty { + display: none; + } + } + #cp-app-poll-nocomments { display: none; } - } - #cp-app-poll-nocomments { - display: none; - } - #cp-app-poll-comments { - display: block; + #cp-app-poll-comments { + display: block; + } } } -} - -#cp-app-poll-help { - width: 100%; - margin: auto; - padding: 20px 10%; - background: @poll-help-bg; -} - -// from cryptpad.less - -table { - border-collapse: collapse; - border-spacing: 0; - margin: 20px; -} -tbody { - * { - box-sizing: border-box; - } - tr { - text-align: center; - } - td { - .tools_unselectable(); - border-right: 1px solid @poll-border-color; - padding: 12px; - padding-top: 0px; - padding-bottom: 0px; - &:last-child { - border-right: none; - } + #cp-app-poll-help { + width: 100%; + margin: auto; + padding: 20px 10%; + background: @poll-help-bg; } -} -div.cp-app-poll-realtime { - display: block; - max-height: 100%; - max-width: 100%; + // from cryptpad.less - input { - &[type="text"] { - height: 1em; - margin: 0px; - } + table { + border-collapse: collapse; + border-spacing: 0; + margin: 20px; } - > textarea { - width: 50%; - height: 15vh; + tbody { + * { + box-sizing: border-box; + } + tr { + text-align: center; + } + + td { + .tools_unselectable(); + border-right: 1px solid @poll-border-color; + padding: 12px; + padding-top: 0px; + padding-bottom: 0px; + &:last-child { + border-right: none; + } + } } - padding: 0px; - margin: 0px; + div.cp-app-poll-realtime { + display: block; + max-height: 100%; + max-width: 100%; - .cp-app-poll-table-scrolled { - tr td:last-child { - right: 0; + input { + &[type="text"] { + height: 1em; + margin: 0px; + } } - tr td:nth-last-child(2) { - right: 100px; + > textarea { + width: 50%; + height: 15vh; } - } - table { - border-collapse: collapse; - width: ~"calc(100% - 1px)"; - .cp-app-poll-table-editing { - background-color: @poll-editing; - } - .cp-app-poll-table-uncommitted { - .cp-app-poll-table-cover { - background-color: @poll-uncommitted-cell !important; + padding: 0px; + margin: 0px; + + .cp-app-poll-table-scrolled { + tr td:last-child { + right: 0; } - div.cp-app-poll-table-text-cell { - background-color: @poll-uncommitted-bg !important; - color: @poll-uncommitted-text !important; + tr td:nth-last-child(2) { + right: 100px; } - text-align: center; - background-color: @poll-uncommitted-bg !important; - color: @poll-uncommitted-text !important; } - tr { - height: 28px; - /* Options */ - td:first-child { - position:absolute; - left: 0; - top: auto; - width: 25%; - } - /* Uncommitted column */ - td:nth-last-child(2) { - position: absolute; - top: auto; - width: 100px; - min-width: unset !important; - height: auto !important; - } - /* Results */ - td:last-child { - color: @poll-th-fg; - position:absolute; - top: auto; - margin-left: 100px; - width: 100px; - min-width: unset !important; - background-color: @poll-th-bg; - } - td { - padding: 0px; - margin: 0px; + table { + border-collapse: collapse; + width: ~"calc(100% - 1px)"; + .cp-app-poll-table-editing { + background-color: @poll-editing; + } + .cp-app-poll-table-uncommitted { + .cp-app-poll-table-cover { + background-color: @poll-uncommitted-cell !important; + } div.cp-app-poll-table-text-cell { - height: 28px; + background-color: @poll-uncommitted-bg !important; + color: @poll-uncommitted-text !important; + } + text-align: center; + background-color: @poll-uncommitted-bg !important; + color: @poll-uncommitted-text !important; + } + tr { + height: 28px; + /* Options */ + td:first-child { + position:absolute; + left: 0; + top: auto; + width: 25%; + } + /* Uncommitted column */ + td:nth-last-child(2) { + position: absolute; + top: auto; + width: 100px; + min-width: unset !important; + height: auto !important; + } + /* Results */ + td:last-child { + color: @poll-th-fg; + position:absolute; + top: auto; + margin-left: 100px; + width: 100px; + min-width: unset !important; + background-color: @poll-th-bg; + } + td { padding: 0px; margin: 0px; - display: flex; - align-items: center; - .cp-app-poll-table-remove { - order: 1; - } - .cp-app-poll-table-edit { - order: 3; - } - input { - min-width: 0; - order: 2; - flex: 1; - height: 24px; - border: 0px; - margin: 2px; - &[disabled] { - background-color: transparent; - color: @poll-td-fg; - //font-weight: bold; + + div.cp-app-poll-table-text-cell { + height: 28px; + padding: 0px; + margin: 0px; + display: flex; + align-items: center; + .cp-app-poll-table-remove { + order: 1; + } + .cp-app-poll-table-edit { + order: 3; + } + input { + min-width: 0; + order: 2; + flex: 1; + height: 24px; + border: 0px; + margin: 2px; + &[disabled] { + background-color: transparent; + color: @poll-td-fg; + //font-weight: bold; + } } } - } - - &.cp-app-poll-table-checkbox-cell { - margin: 0px; - padding: 0px; - height: 100%; - min-width: 100px; - div.cp-app-poll-table-checkbox-contain { - display: inline-block; + &.cp-app-poll-table-checkbox-cell { + margin: 0px; + padding: 0px; height: 100%; - width: 100%; - position: relative; + min-width: 100px; - label { - background-color: transparent; - display: block; - position: absolute; - top: 0px; - left: 0px; + div.cp-app-poll-table-checkbox-contain { + display: inline-block; height: 100%; width: 100%; - } - - input { - &[type="number"] { - &:not(.editable) { - display: none; + position: relative; - ~ .cp-app-poll-table-cover { - line-height: 28px; - display: block; - font-weight: bold; - height: 100%; - display: block; + label { + background-color: transparent; + display: block; + position: absolute; + top: 0px; + left: 0px; + height: 100%; + width: 100%; + } - color: @poll-cover-color; + input { + &[type="number"] { + &:not(.editable) { + display: none; - &:after { + ~ .cp-app-poll-table-cover { + line-height: 28px; + display: block; + font-weight: bold; height: 100%; - } + display: block; + color: @poll-cover-color; + + &:after { + height: 100%; + } + + } } } } - } - input[type="number"][value="0"] { - ~ .cp-app-poll-table-cover { - background-color: @colortheme_cp-red; - &:after { content: "✖"; } + input[type="number"][value="0"] { + ~ .cp-app-poll-table-cover { + background-color: @colortheme_cp-red; + &:after { content: "✖"; } + } } - } - input[type="number"][value="1"] { - ~ .cp-app-poll-table-cover { - background-color: @colortheme_cp-green; - &:after { content: "✔"; } + input[type="number"][value="1"] { + ~ .cp-app-poll-table-cover { + background-color: @colortheme_cp-green; + &:after { content: "✔"; } + } } - } - input[type="number"][value="2"] { - ~ .cp-app-poll-table-cover { - background-color: @poll-option-yellow; - &:after { content: "~"; } + input[type="number"][value="2"] { + ~ .cp-app-poll-table-cover { + background-color: @poll-option-yellow; + &:after { content: "~"; } + } } - } - input[type="number"][value="3"] { - ~ .cp-app-poll-table-cover { - background-color: @poll-option-gray; - &:after { content: "?"; } + input[type="number"][value="3"] { + ~ .cp-app-poll-table-cover { + background-color: @poll-option-gray; + &:after { content: "?"; } + } } } } } } - } - input { - &[type="text"] { - height: auto; - width: 80%; + input { + &[type="text"] { + height: auto; + width: 80%; + } } - } - span { - .tools_unselectable(); - } - thead { - height: 52px; - tr { - height: 52px; + span { + .tools_unselectable(); } - td { - padding: 0px 5px; - background: @poll-th-bg; - color: @poll-th-fg; - &:not(:last-child) { - border-right: 1px solid rgba(255,255,255,0.2); - } - &:last-child { + thead { + height: 52px; + tr { height: 52px; - line-height: 52px; - text-align: center; - } - &:nth-last-child(2) { - border-right: 1px solid @poll-border-color; } - &.cp-app-poll-table-own { - background: @poll-th-user-bg; - .cp-app-poll-table-lock { - cursor: default; + td { + padding: 0px 5px; + background: @poll-th-bg; + color: @poll-th-fg; + &:not(:last-child) { + border-right: 1px solid rgba(255,255,255,0.2); } - } - .cp-app-poll-table-buttons { - display: flex; - justify-content: space-between; - flex-wrap: wrap; - align-items: center; - span { - cursor: pointer; - width: 1em; + &:last-child { + height: 52px; + line-height: 52px; text-align: center; } - .cp-app-poll-table-bookmark { - color: darken(@poll-th-fg, 30%); - &.cp-app-poll-table-bookmark-full { - color: @poll-th-fg; + &:nth-last-child(2) { + border-right: 1px solid @poll-border-color; + } + &.cp-app-poll-table-own { + background: @poll-th-user-bg; + .cp-app-poll-table-lock { + cursor: default; } } - } - input { - &[type="text"] { - overflow: hidden; - text-overflow: ellipsis; - break-after: always; - width: ~"calc(100% - 2px)"; // borders... - box-sizing: border-box; - padding: 1px 5px; - margin: 1px; - &[disabled] { - color: @poll-th-fg; + .cp-app-poll-table-buttons { + display: flex; + justify-content: space-between; + flex-wrap: wrap; + align-items: center; + span { + cursor: pointer; + width: 1em; + text-align: center; + } + .cp-app-poll-table-bookmark { + color: darken(@poll-th-fg, 30%); + &.cp-app-poll-table-bookmark-full { + color: @poll-th-fg; + } + } + } + input { + &[type="text"] { + overflow: hidden; + text-overflow: ellipsis; + break-after: always; + width: ~"calc(100% - 2px)"; // borders... + box-sizing: border-box; + padding: 1px 5px; + margin: 1px; + &[disabled] { + color: @poll-th-fg; + } } } } } - } - tbody { - td:first-child { - background: @poll-td-bg; - color: @poll-td-fg; - } - td.cp-app-poll-table-winner { - background-color: @poll-winner; - &:last-child { font-weight: bold; } - } - .cp-app-poll-table-text-cell { - input[type="text"] { - width: ~"calc(100% - 50px)"; - padding: 0 0.5em; + tbody { + td:first-child { + background: @poll-td-bg; + color: @poll-td-fg; } - .cp-app-poll-table-edit { - float:right; - margin: 2px 10px 0 0; + td.cp-app-poll-table-winner { + background-color: @poll-winner; + &:last-child { font-weight: bold; } } - .cp-app-poll-table-remove { - float: left; - margin: 2px 0 0 10px; + .cp-app-poll-table-text-cell { + input[type="text"] { + width: ~"calc(100% - 50px)"; + padding: 0 0.5em; + } + .cp-app-poll-table-edit { + float:right; + margin: 2px 10px 0 0; + } + .cp-app-poll-table-remove { + float: left; + margin: 2px 0 0 10px; + } } - } - tr:not(:first-child) { - td:not(:first-child) { - label { - border-top: 1px solid @poll-border-color; + tr:not(:first-child) { + td:not(:first-child) { + label { + border-top: 1px solid @poll-border-color; + } } } - } - tr:not(:last-child) { - &:hover { - td:first-child { - background-color: @poll-highlighted; + tr:not(:last-child) { + &:hover { + td:first-child { + background-color: @poll-highlighted; + } } } } - } - .cp-app-poll-table-edit { - //color: @poll-cover-color; - cursor: pointer; - float: left; - margin-left: 10px; - } + .cp-app-poll-table-edit { + //color: @poll-cover-color; + cursor: pointer; + float: left; + margin-left: 10px; + } - thead { - tr { - th { - input[type="text"][disabled] { - background-color: transparent; - color: @poll-fore; - font-weight: bold; - } - .cp-app-poll-table-remove { - cursor: pointer; - font-size: 20px; + thead { + tr { + th { + input[type="text"][disabled] { + background-color: transparent; + color: @poll-fore; + font-weight: bold; + } + .cp-app-poll-table-remove { + cursor: pointer; + font-size: 20px; + } } } } - } - tbody { - tr { - td { + tbody { + tr { + td { + } } } - } - tfoot { - display: none; - } - } - #cp-app-poll-nocomments { - color: #999; - text-align: center; - margin: 20px; - font: @colortheme_app-font; - } - #cp-app-poll-comments { - width: 50%; - margin: 20px auto; - min-width: 400px; - padding-bottom: 5px; - display: none; - button { - border-radius: 0; - } - #cp-app-poll-comments-add { - input, textarea { - border: 1px solid black; - width: 90%; - margin: 5px 5%; - } - input { - padding: 5px; - height: 26px; - &[disabled] { - background: #eee; - } - } - textarea { - padding: 5px; - height: 8em; - line-height: 1.5em; - } - button { - padding: 10px; + tfoot { + display: none; } + } + #cp-app-poll-nocomments { + color: #999; text-align: center; + margin: 20px; + font: @colortheme_app-font; } - #cp-app-poll-comments-list { - .cp-app-poll-comments-list-el { - width: 90%; - margin: 5px 5%; + #cp-app-poll-comments { + width: 50%; + margin: 20px auto; + min-width: 400px; + padding-bottom: 5px; + display: none; + button { + border-radius: 0; } - .cp-app-poll-comments-list-msg { - display: flex; - background: #eee; - padding: 5px 10px; - .cp-app-poll-comments-list-msg-text { - flex: 1; - white-space: pre-wrap; - } - .cp-app-poll-comments-list-msg-actions { - button { - padding: 0; - width: 25px; - line-height: 20px; + #cp-app-poll-comments-add { + input, textarea { + border: 1px solid black; + width: 90%; + margin: 5px 5%; + } + input { + padding: 5px; + height: 26px; + &[disabled] { + background: #eee; } } + textarea { + padding: 5px; + height: 8em; + line-height: 1.5em; + } + button { + padding: 10px; + } + text-align: center; } - .cp-app-poll-comments-list-data { - background: #ddd; - padding: 5px 10px; - display: flex; - align-items: center; - .cp-app-poll-comments-list-data-name { - margin-left: 10px; - flex: 1; - } - .cp-app-poll-comments-list-data-avatar { .avatar_main(30px); } + #cp-app-poll-comments-list { + .cp-app-poll-comments-list-el { + width: 90%; + margin: 5px 5%; + } + .cp-app-poll-comments-list-msg { + display: flex; + background: #eee; + padding: 5px 10px; + .cp-app-poll-comments-list-msg-text { + flex: 1; + white-space: pre-wrap; + } + .cp-app-poll-comments-list-msg-actions { + button { + padding: 0; + width: 25px; + line-height: 20px; + } + } + } + .cp-app-poll-comments-list-data { + background: #ddd; + padding: 5px 10px; + display: flex; + align-items: center; + .cp-app-poll-comments-list-data-name { + margin-left: 10px; + flex: 1; + } + .cp-app-poll-comments-list-data-avatar { .avatar_main(30px); } + } } } - } - @media screen and (max-width: 500px) { - #cp-app-poll-table-scroll { - max-width: 100%; - padding: 0; - margin: 0; - table { - tr { - td { - &:first-child { - position: unset; - min-width: 100px; - &:hover:not(:empty) { - position: absolute; + @media screen and (max-width: 500px) { + #cp-app-poll-table-scroll { + max-width: 100%; + padding: 0; + margin: 0; + table { + tr { + td { + &:first-child { + position: unset; min-width: 100px; - width: auto; - z-index: 100; + &:hover:not(:empty) { + position: absolute; + min-width: 100px; + width: auto; + z-index: 100; + } + } + &:nth-last-child(2) { + position: unset; + } + &:last-child { + position: unset; } - } - &:nth-last-child(2) { - position: unset; - } - &:last-child { - position: unset; } } } } - } - #cp-app-poll-comments { - min-width: 90%; + #cp-app-poll-comments { + min-width: 90%; + } } } -} -.btn { - display: inline-flex; - align-items: center; - justify-content: center; -} + .btn { + display: inline-flex; + align-items: center; + justify-content: center; + } +} \ No newline at end of file diff --git a/www/poll/inner.js b/www/poll/inner.js index ad0ea5ada..7a287b7db 100644 --- a/www/poll/inner.js +++ b/www/poll/inner.js @@ -26,7 +26,7 @@ define([ 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', - 'less!/customize/src/less2/main.less', + 'less!/poll/app-poll.less', ], function ( $, Toolbar, diff --git a/www/profile/app-profile.less b/www/profile/app-profile.less index 0fce9ea7b..ec41c4e31 100644 --- a/www/profile/app-profile.less +++ b/www/profile/app-profile.less @@ -1,15 +1,15 @@ @import (reference) '../../customize/src/less2/include/framework.less'; @import (reference) '../../customize/src/less2/include/sidebar-layout.less'; -.framework_min_main( - @bg-color: @colortheme_profile-bg, - @warn-color: @colortheme_profile-warn, - @color: @colortheme_profile-color -); -.sidebar-layout_main(); - -// body &.cp-app-profile { + + .framework_min_main( + @bg-color: @colortheme_profile-bg, + @warn-color: @colortheme_profile-warn, + @color: @colortheme_profile-color + ); + .sidebar-layout_main(); + display: flex; flex-flow: column; #cp-app-profile-header { diff --git a/www/profile/inner.js b/www/profile/inner.js index 76c279ce0..b8f2ed31d 100644 --- a/www/profile/inner.js +++ b/www/profile/inner.js @@ -20,7 +20,7 @@ define([ 'css!/bower_components/codemirror/addon/fold/foldgutter.css', 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', - 'less!/customize/src/less2/main.less', + 'less!/profile/app-profile.less', '/bower_components/croppie/croppie.min.js', 'css!/bower_components/croppie/croppie.css', ], function ( diff --git a/www/settings/app-settings.less b/www/settings/app-settings.less index 3e8f1ed92..c8e5eb2e3 100644 --- a/www/settings/app-settings.less +++ b/www/settings/app-settings.less @@ -3,17 +3,16 @@ @import (reference) "../../customize/src/less2/include/creation.less"; @import (reference) '../../customize/src/less2/include/framework.less'; -.framework_min_main( - @bg-color: @colortheme_settings-bg, - @warn-color: @colortheme_settings-warn, - @color: @colortheme_settings-color -); -.sidebar-layout_main(); -.limit-bar_main(); -.creation_main(); - -// body &.cp-app-settings { + .framework_min_main( + @bg-color: @colortheme_settings-bg, + @warn-color: @colortheme_settings-warn, + @color: @colortheme_settings-color + ); + .sidebar-layout_main(); + .limit-bar_main(); + .creation_main(); + display: flex; flex-flow: column; font: @colortheme_app-font; diff --git a/www/settings/inner.js b/www/settings/inner.js index 9cdda9d00..7bc15bdc8 100644 --- a/www/settings/inner.js +++ b/www/settings/inner.js @@ -16,7 +16,7 @@ define([ '/bower_components/file-saver/FileSaver.min.js', 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', - 'less!/customize/src/less2/main.less', + 'less!/settings/app-settings.less', ], function ( $, Toolbar, diff --git a/www/slide/app-slide.less b/www/slide/app-slide.less index 8a56db15f..27dcef34e 100644 --- a/www/slide/app-slide.less +++ b/www/slide/app-slide.less @@ -2,415 +2,419 @@ @import (reference) "../../customize/src/less2/include/mediatag.less"; @import (reference) "../../customize/src/less2/include/framework.less"; -.mediatag_base(); -.framework_main( - @bg-color: @colortheme_slide-bg, - @warn-color: @colortheme_slide-warn, - @color: @colortheme_slide-color -); - -// body -font-size: unset; -display: flex; -flex-flow: column; - -@slide-default-bg: #000; -.size (@n) { - // font-size: @n * 1vmin; - // line-height: @n * 1.1vmin; - font-size: @n * 10%; - // line-height: @n * 11%; - line-height: 110%; -} - -h1 { font-size: 40px; } -h2 { font-size: 37px; } -h3 { font-size: 34px; } -h4 { font-size: 31px; } -h5 { font-size: 27px; } -h6 { font-size: 24px; } - -#cp-app-slide-editor-container { - display: inline-flex; - flex-flow: column; - height: 100%; - min-height: 100%; - width: 50%; - min-width: 20%; - max-width: 80%; - overflow: hidden; - max-width: 100%; - flex: 1; -} -.CodeMirror { - flex: 1; - width: 100%; - font-size: initial; -} -.CodeMirror-focused .cm-matchhighlight { - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFklEQVQI12NgYGBgkKzc8x9CMDAwAAAmhwSbidEoSQAAAABJRU5ErkJggg==); - background-position: bottom; - background-repeat: repeat-x; -} - -#cp-app-slide-colorpicker { - display: block; -} - -#cme_toolbox { - z-index: 10000; -} - -#cp-app-slide-editor { - flex: 1; +&.cp-app-slide { + + .mediatag_base(); + + .framework_main( + @bg-color: @colortheme_slide-bg, + @warn-color: @colortheme_slide-warn, + @color: @colortheme_slide-color + ); + + // body + font-size: unset; display: flex; - flex-flow: row; - height: 100%; - overflow: hidden; + flex-flow: column; + + @slide-default-bg: #000; + .size (@n) { + // font-size: @n * 1vmin; + // line-height: @n * 1.1vmin; + font-size: @n * 10%; + // line-height: @n * 11%; + line-height: 110%; + } + + h1 { font-size: 40px; } + h2 { font-size: 37px; } + h3 { font-size: 34px; } + h4 { font-size: 31px; } + h5 { font-size: 27px; } + h6 { font-size: 24px; } + + #cp-app-slide-editor-container { + display: inline-flex; + flex-flow: column; + height: 100%; + min-height: 100%; + width: 50%; + min-width: 20%; + max-width: 80%; + overflow: hidden; + max-width: 100%; + flex: 1; + } .CodeMirror { - resize: none; - //width: 100vw; + flex: 1; + width: 100%; + font-size: initial; + } + .CodeMirror-focused .cm-matchhighlight { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFklEQVQI12NgYGBgkKzc8x9CMDAwAAAmhwSbidEoSQAAAABJRU5ErkJggg==); + background-position: bottom; + background-repeat: repeat-x; + } + + #cp-app-slide-colorpicker { + display: block; + } + + #cme_toolbox { + z-index: 10000; } - &.cp-app-slide-preview { + + #cp-app-slide-editor { + flex: 1; + display: flex; + flex-flow: row; + height: 100%; + overflow: hidden; .CodeMirror { - //resize: horizontal; - //width: 50vw; + resize: none; + //width: 100vw; + } + &.cp-app-slide-preview { + .CodeMirror { + //resize: horizontal; + //width: 50vw; + } } } -} -.cp-app-slide-shown { - .cp-app-slide-container { - position: relative; - &> media-tag { - position: absolute; - top:0; right: 0; bottom: 0; left: 0; - z-index: -1; - &> img { - width: 100vw; - height: 56.25vw; // height:width ratio = 9/16 = .5625 - max-height: 100vh; - max-width: 177.78vh; // 16/9 = 1.778 + .cp-app-slide-shown { + .cp-app-slide-container { + position: relative; + &> media-tag { position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; - margin: auto; + top:0; right: 0; bottom: 0; left: 0; + z-index: -1; + &> img { + width: 100vw; + height: 56.25vw; // height:width ratio = 9/16 = .5625 + max-height: 100vh; + max-width: 177.78vh; // 16/9 = 1.778 + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + margin: auto; + } } } } -} -.cp-app-slide-preview { - .cp-app-slide-viewer { - width: 50vw; - overflow: hidden; - div#cp-app-slide-modal:not(.cp-app-slide-shown) { - position: relative; - top: auto; - left: auto; - width: auto; - display: block; - height: 100%; - #cp-app-slide-modal-content { - .cp-app-slide-container { - position: relative; - &> media-tag { - position: absolute; - top:0; right: 0; bottom: 0; left: 0; - z-index: -1; - &> img { - width: 50vw; - height: 28.125vw; - max-height: ~"calc(100vh - 96px)"; - max-width: ~"calc(16 / 9 * (100vh - 96px))"; + .cp-app-slide-preview { + .cp-app-slide-viewer { + width: 50vw; + overflow: hidden; + div#cp-app-slide-modal:not(.cp-app-slide-shown) { + position: relative; + top: auto; + left: auto; + width: auto; + display: block; + height: 100%; + #cp-app-slide-modal-content { + .cp-app-slide-container { + position: relative; + &> media-tag { position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; - margin: auto; + top:0; right: 0; bottom: 0; left: 0; + z-index: -1; + &> img { + width: 50vw; + height: 28.125vw; + max-height: ~"calc(100vh - 96px)"; + max-width: ~"calc(16 / 9 * (100vh - 96px))"; + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + margin: auto; + } } } + .cp-app-slide-container { + width: 100%; + } + .cp-app-slide-frame { + width: 50vw; + height: 28.125vw; // height:width ratio = 9/16 = .5625 + max-height: ~"calc(100vh - 96px)"; + max-width: ~"calc(16 / 9 * (100vh - 96px))"; + //max-height: 100vh; + //max-width: 177.78vh; // 16/9 = 1.778 + } } - .cp-app-slide-container { - width: 100%; - } - .cp-app-slide-frame { - width: 50vw; - height: 28.125vw; // height:width ratio = 9/16 = .5625 - max-height: ~"calc(100vh - 96px)"; - max-width: ~"calc(16 / 9 * (100vh - 96px))"; - //max-height: 100vh; - //max-width: 177.78vh; // 16/9 = 1.778 + #cp-app-slide-modal-exit { + visibility: hidden; } } - #cp-app-slide-modal-exit { - visibility: hidden; - } + } + .CodeMirror { + flex: 1; } } - .CodeMirror { - flex: 1; - } -} -/* Slide position (print mode) */ -@ratio:0.9; -@media print { - #cp-app-slide-editor-container { - display: none; - } -} -#cp-app-slide-print { - position: relative; - display: none; - font-size: @ratio*11.25vw; - .cp-app-slide-frame { - display: flex !important; - flex-flow: column; - padding: 0.5em; - margin: auto; - border: 1px solid black; - height: @ratio*56.25vw; - width: @ratio*100vw; - page-break-after: always; - position: relative; - box-sizing: border-box; - overflow: hidden; - li { - min-width: @ratio*50vw; - } - h1 { - padding-top: 0; + /* Slide position (print mode) */ + @ratio:0.9; + @media print { + #cp-app-slide-editor-container { + display: none; } - } - .cp-app-slide-container { + #cp-app-slide-print { position: relative; - &> media-tag { - position: absolute; - top:0; right: 0; bottom: 0; left: 0; - z-index: -1; - &> img { - width: 90vw; - height: 50.625vw; + display: none; + font-size: @ratio*11.25vw; + .cp-app-slide-frame { + display: flex !important; + flex-flow: column; + padding: 0.5em; + margin: auto; + border: 1px solid black; + height: @ratio*56.25vw; + width: @ratio*100vw; + page-break-after: always; + position: relative; + box-sizing: border-box; + overflow: hidden; + li { + min-width: @ratio*50vw; + } + h1 { + padding-top: 0; + } + + } + .cp-app-slide-container { + position: relative; + &> media-tag { position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; - margin: auto; + top:0; right: 0; bottom: 0; left: 0; + z-index: -1; + &> img { + width: 90vw; + height: 50.625vw; + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + margin: auto; + } } } - } - .cp-app-slide-container { - width: 90vw; - height: 100vh; - margin: 0vh 5vw !important; - display: flex; - &:last-child { - height: ~"calc(100vh - 2px)"; + .cp-app-slide-container { + width: 90vw; + height: 100vh; + margin: 0vh 5vw !important; + display: flex; + &:last-child { + height: ~"calc(100vh - 2px)"; + } } } -} -/* Slide position (present mode) */ -div#cp-app-slide-modal { - display: none; - background-color: black; - color: white; + /* Slide position (present mode) */ + div#cp-app-slide-modal { + display: none; + background-color: black; + color: white; - .cp-app-slide-isempty { - display: flex; - align-items: center; - justify-content: center; - img { - max-width: 100%; - max-height: 100%; + .cp-app-slide-isempty { + display: flex; + align-items: center; + justify-content: center; + img { + max-width: 100%; + max-height: 100%; + } } - } - /* Navigation buttons */ - .cp-app-slide-modal-button { - position: absolute; - cursor: pointer; - font-size: 30px; - opacity: 0.6; - display: none; - z-index: 9001; - } - .cp-app-slide-modal-button:hover { - opacity: 1; - display: block !important; - } - #cp-app-slide-modal-exit { - left: 20px; - top: 20px; - } - #cp-app-slide-modal-left { - left: 6vw; - bottom: 10vh; - } - #cp-app-slide-modal-right { - right: 6vw; - bottom: 10vh; - } - &.cp-app-slide-shown { - display: block; - position: fixed; - top: 0px; - left: 0px; - z-index: 1000000; // one order of magnitude higher than alertify - height: 100vh; - width: 100%; - } - #cp-app-slide-modal-content { - font-size: 20vh; - position: relative; - height: 100%; - overflow: visible; - white-space: nowrap; - .cp-app-slide-frame { - overflow: hidden; - display: flex; - flex-flow: column !important; + /* Navigation buttons */ + .cp-app-slide-modal-button { + position: absolute; + cursor: pointer; + font-size: 30px; + opacity: 0.6; + display: none; + z-index: 9001; + } + .cp-app-slide-modal-button:hover { + opacity: 1; + display: block !important; + } + #cp-app-slide-modal-exit { + left: 20px; + top: 20px; + } + #cp-app-slide-modal-left { + left: 6vw; + bottom: 10vh; + } + #cp-app-slide-modal-right { + right: 6vw; + bottom: 10vh; + } + &.cp-app-slide-shown { + display: block; + position: fixed; + top: 0px; + left: 0px; + z-index: 1000000; // one order of magnitude higher than alertify + height: 100vh; + width: 100%; + } + #cp-app-slide-modal-content { + font-size: 20vh; + position: relative; + height: 100%; + overflow: visible; + white-space: nowrap; + .cp-app-slide-frame { + overflow: hidden; + display: flex; + flex-flow: column !important; - box-sizing: border-box; - border: 1px solid; - white-space: normal; + box-sizing: border-box; + border: 1px solid; + white-space: normal; - vertical-align: middle; + vertical-align: middle; - padding: 0.5em; - width: 100vw; - height: 56.25vw; // height:width ratio = 9/16 = .5625 - max-height: 100vh; - max-width: 177.78vh; // 16/9 = 1.778 - margin: auto; - } - .cp-app-slide-container { - display: inline-flex; - height: 100%; width: 100vw; - text-align: center; - vertical-align: top; - } - &.cp-app-slide-transition { + padding: 0.5em; + width: 100vw; + height: 56.25vw; // height:width ratio = 9/16 = .5625 + max-height: 100vh; + max-width: 177.78vh; // 16/9 = 1.778 + margin: auto; + } .cp-app-slide-container { - transition: margin-left 1s; + display: inline-flex; + height: 100%; width: 100vw; + text-align: center; + vertical-align: top; + } + &.cp-app-slide-transition { + .cp-app-slide-container { + transition: margin-left 1s; + } + } + media-tag button { + max-height: none; } } - media-tag button { - max-height: none; - } - } - box-sizing: border-box; - z-index: 9001; - position: fixed; + box-sizing: border-box; + z-index: 9001; + position: fixed; - top: 0px; - left: 0px; + top: 0px; + left: 0px; - width: 100%; - height: 100vh; - display: none; + width: 100%; + height: 100vh; + display: none; - background-color: @slide-default-bg; -} + background-color: @slide-default-bg; + } -/* Slide content */ -div#cp-app-slide-modal #cp-app-slide-modal-content, #cp-app-slide-print { - .cp-app-slide-frame { - * { - .size(2.75); + /* Slide content */ + div#cp-app-slide-modal #cp-app-slide-modal-content, #cp-app-slide-print { + .cp-app-slide-frame { * { - font-size: 1em; - line-height: 1em; + .size(2.75); + * { + font-size: 1em; + line-height: 1em; + } } - } - ul, ol { ul, ol { - margin: 0; + ul, ol { + margin: 0; + } } - } - h1 { .size(5); } - h2 { .size(4.2); } - h3 { .size(3.6); } - h4 { .size (3); } - h5 { .size(2.2); } - h6 { .size(1.6); } - - h1, h2, h3, h4, h5, h6 { - color: inherit; - text-align: center; - padding-top: 0; - margin-bottom: 0.5em; - } + h1 { .size(5); } + h2 { .size(4.2); } + h3 { .size(3.6); } + h4 { .size (3); } + h5 { .size(2.2); } + h6 { .size(1.6); } - .markdown_preformatted-code; + h1, h2, h3, h4, h5, h6 { + color: inherit; + text-align: center; + padding-top: 0; + margin-bottom: 0.5em; + } - ul, ol { - min-width: 50%; - max-width: 100%; - display: table; - margin: 0 auto; - padding-left: 0.3em; - } + .markdown_preformatted-code; - // fixes image overflowing - media-tag { - height: 100%; - flex-flow: row; - justify-content: center; + ul, ol { + min-width: 50%; + max-width: 100%; + display: table; + margin: 0 auto; + padding-left: 0.3em; + } - & + * { - margin-top: 1rem; + // fixes image overflowing + media-tag { + height: 100%; + flex-flow: row; + justify-content: center; + + & + * { + margin-top: 1rem; + } + img { flex: unset; } } - img { flex: unset; } - } - img { + img { + position: relative; + min-width: 1%; + margin: auto; + } + .cp-app-slide-number { + position: absolute; + right: 5vh; + bottom: 5vh; + .size(1); + } + .cp-app-slide-date { + position: absolute; + left: 5vh; + bottom: 5vh; + .size(1); + } + .cp-app-slide-title { + position: absolute; + bottom: 5vh; + left: 0px; right: 0px; + text-align: center; + .size(1); + } + text-align: left; position: relative; - min-width: 1%; - margin: auto; } - .cp-app-slide-number { - position: absolute; - right: 5vh; - bottom: 5vh; - .size(1); - } - .cp-app-slide-date { - position: absolute; - left: 5vh; - bottom: 5vh; - .size(1); - } - .cp-app-slide-title { - position: absolute; - bottom: 5vh; - left: 0px; right: 0px; - text-align: center; - .size(1); - } - text-align: left; - position: relative; } -} - -.cp-app-slide-frame * { - max-width: 100%; - max-height: 100%; -} - -p { - padding: 0; - margin: 0; - min-height:0; - min-width:0; -} - -pre.cp-slide-css-error { - color: white; -} + + .cp-app-slide-frame * { + max-width: 100%; + max-height: 100%; + } + + p { + padding: 0; + margin: 0; + min-height:0; + min-width:0; + } + + pre.cp-slide-css-error { + color: white; + } +} \ No newline at end of file diff --git a/www/slide/inner.js b/www/slide/inner.js index 497b0b8ca..89ec0dafa 100644 --- a/www/slide/inner.js +++ b/www/slide/inner.js @@ -15,7 +15,7 @@ define([ 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', - 'less!/customize/src/less2/main.less', + 'less!/slide/app-slide.less', 'css!cm/lib/codemirror.css', 'css!cm/addon/dialog/dialog.css', diff --git a/www/todo/app-todo.less b/www/todo/app-todo.less index 191252f53..29818c6fb 100644 --- a/www/todo/app-todo.less +++ b/www/todo/app-todo.less @@ -1,13 +1,13 @@ @import (reference) '../../customize/src/less2/include/framework.less'; -.framework_min_main( - @bg-color: @colortheme_todo-bg, - @warn-color: @colortheme_todo-warn, - @color: @colortheme_todo-color -); - -// body &.cp-app-todo { + + .framework_min_main( + @bg-color: @colortheme_todo-bg, + @warn-color: @colortheme_todo-warn, + @color: @colortheme_todo-color + ); + display: flex; flex-flow: column; diff --git a/www/todo/inner.js b/www/todo/inner.js index 07a8b3f42..eb749c35a 100644 --- a/www/todo/inner.js +++ b/www/todo/inner.js @@ -13,7 +13,7 @@ define([ 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', - 'less!/customize/src/less2/main.less', + 'less!/todo/app-todo.less', ], function ( $, Crypto, diff --git a/www/whiteboard/app-whiteboard.less b/www/whiteboard/app-whiteboard.less index c05405fa0..0ac575df6 100644 --- a/www/whiteboard/app-whiteboard.less +++ b/www/whiteboard/app-whiteboard.less @@ -1,14 +1,14 @@ @import (reference) '../../customize/src/less2/include/tools.less'; @import (reference) "../../customize/src/less2/include/framework.less"; -.framework_main( - @bg-color: @colortheme_whiteboard-bg, - @warn-color: @colortheme_whiteboard-warn, - @color: @colortheme_whiteboard-color -); - -// body &.cp-app-whiteboard { + + .framework_main( + @bg-color: @colortheme_whiteboard-bg, + @warn-color: @colortheme_whiteboard-warn, + @color: @colortheme_whiteboard-color + ); + display: flex; flex-flow: column; height: 100%; diff --git a/www/whiteboard/inner.js b/www/whiteboard/inner.js index bf57e89b7..82bf2f816 100644 --- a/www/whiteboard/inner.js +++ b/www/whiteboard/inner.js @@ -15,6 +15,7 @@ define([ '/bower_components/chainpad/chainpad.dist.js', '/bower_components/secure-fabric.js/dist/fabric.min.js', + 'less!/whiteboard/app-whiteboard.less' ], function ( $, Sortify, diff --git a/www/worker/app-worker.less b/www/worker/app-worker.less index 47295b0aa..9357c8be4 100644 --- a/www/worker/app-worker.less +++ b/www/worker/app-worker.less @@ -1,10 +1,9 @@ @import (reference) "../../customize/src/less2/include/colortheme-all.less"; @import (reference) '../../customize/src/less2/include/framework.less'; -.framework_min_main(); - -// body &.cp-app-worker { + .framework_min_main(); + display: flex; flex-flow: column; diff --git a/www/worker/inner.js b/www/worker/inner.js index 20992b023..2e6d98153 100644 --- a/www/worker/inner.js +++ b/www/worker/inner.js @@ -9,7 +9,7 @@ define([ 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', - 'less!/customize/src/less2/main.less', + 'less!/worker/app-worker.less', ], function ( $, Toolbar, From 6c49318ac7eccfd9829a65f4f8279bad77f880c1 Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Sat, 14 Jul 2018 15:19:39 +0200 Subject: [PATCH 26/86] Show how long it takes to parse less --- www/common/LessLoader.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/www/common/LessLoader.js b/www/common/LessLoader.js index 39f04db5c..a6942ac77 100644 --- a/www/common/LessLoader.js +++ b/www/common/LessLoader.js @@ -152,10 +152,17 @@ define([ }; module.exports.load = function (url /*:string*/, cb /*:()=>void*/, stack /*:?Array*/) { + var btime = stack ? null : +new Date(); stack = stack || []; if (stack.indexOf(url) > -1) { return void cb(); } var timeout = setTimeout(function () { console.log('failed', url); }, 10000); - var done = function () { clearTimeout(timeout); cb(); }; + var done = function () { + clearTimeout(timeout); + if (btime) { + console.log("Compiling [" + url + "] took " + (+new Date() - btime) + "ms"); + } + cb(); + }; stack.push(url); cacheGet(url, function (css) { if (css) { return void loadSubmodulesAndInject(css, url, done, stack); } From 5b48eff78cde98cdc5d938a4901f41a1a3f62fde Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 16 Jul 2018 14:05:36 +0200 Subject: [PATCH 27/86] Remove owned pads deleted from the server in shared folders --- www/common/outer/userObject.js | 5 +-- www/common/proxy-manager.js | 61 +++++++++++++++++++++++----------- 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/www/common/outer/userObject.js b/www/common/outer/userObject.js index defc4dbd9..6f17eaf55 100644 --- a/www/common/outer/userObject.js +++ b/www/common/outer/userObject.js @@ -87,14 +87,15 @@ define([ var filesList = exp.getFiles([ROOT, 'hrefArray', TRASH]); var toClean = []; + var ownedRemoved = []; exp.getFiles([FILES_DATA, SHARED_FOLDERS]).forEach(function (id) { - // XXX if (filesList.indexOf(id) === -1) { var fd = exp.isSharedFolder(id) ? files[SHARED_FOLDERS][id] : exp.getFileData(id); var channelId = fd.channel; // If trying to remove an owned pad, remove it from server also if (!isOwnPadRemoved && !sharedFolder && fd.owners && fd.owners.indexOf(edPublic) !== -1 && channelId) { + if (channelId) { ownedRemoved.push(channelId); } removeOwnedChannel(channelId, function (obj) { if (obj && obj.error) { // If the error is that the file is already removed, nothing to @@ -117,7 +118,7 @@ define([ } }); if (!toClean.length) { return void cb(); } - cb(null, toClean); + cb(null, toClean, ownedRemoved); }; var deleteHrefs = function (ids) { ids.forEach(function (obj) { diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index bfd3fc89e..d943ffc22 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -109,6 +109,24 @@ define([ }); return ret; }; + // Return paths linked to a file ID + var findFile = function (Env, id) { + var ret = []; + var userObjects = _getUserObjects(Env); + userObjects.forEach(function (uo) { + var fPath = _getUserObjectPath(Env, uo); + var results = uo.findFile(id); + if (fPath) { + // This is a shared folder, we have to fix the paths in the results + results.map(function (p) { + Array.prototype.unshift.apply(p, fPath); + }); + } + // Push the results from this proxy + Array.prototype.push.apply(ret, results); + }); + return ret; + }; // Returns file IDs corresponding to the provided channels var _findChannels = function (Env, channels, onlyMain) { @@ -384,13 +402,36 @@ define([ } var toUnpin = []; + var ownedRemoved; nThen(function (waitFor)  { + // Delete paths from the main drive and get the list of pads to unpin + // We also get the list of owned pads that were removed if (resolved.main.length) { - Env.user.userObject.delete(resolved.main, waitFor(function (err, _toUnpin) { + Env.user.userObject.delete(resolved.main, waitFor(function (err, _toUnpin, _ownedRemoved) { if (!Env.unpinPads || !_toUnpin) { return; } Array.prototype.push.apply(toUnpin, _toUnpin); + ownedRemoved = _ownedRemoved; }), data.nocheck, data.isOwnPadRemoved); } + }).nThen(function (waitFor) { + // Check if removed owned pads are duplicated is some shared folders + // If that's the case, we have to remove them from the shared folders too + // We can do that by adding their paths to the list of pads to remove from shared folders + if (ownedRemoved) { + var ids = _findChannels(Env, ownedRemoved); + ids.forEach(function (id) { + var paths = findFile(Env, id); + var _resolved = _resolvePaths(Env, paths); + Object.keys(_resolved.folders).forEach(function (fId) { + if (resolved.folders[fId]) { + Array.prototype.push.apply(resolved.folders[fId], _resolved.folders[fId]); + } else { + resolved.folders[fId] = _resolved.folders[fId]; + } + }); + }); + } + // Delete paths from the shared folders Object.keys(resolved.folders).forEach(function (id) { Env.folders[id].userObject.delete(resolved.folders[id], waitFor(function (err, _toUnpin) { if (!Env.unpinPads || !_toUnpin) { return; } @@ -801,24 +842,6 @@ define([ return ret; }; - var findFile = function (Env, id) { - var ret = []; - var userObjects = _getUserObjects(Env); - userObjects.forEach(function (uo) { - var fPath = _getUserObjectPath(Env, uo); - var results = uo.findFile(id); - if (fPath) { - // This is a shared folder, we have to fix the paths in the results - results = results.map(function (p) { - Array.prototype.unshift.apply(p, fPath); - }); - } - // Push the results from this proxy - Array.prototype.push.apply(ret, results); - }); - return ret; - }; - var getRecentPads = function (Env) { return Env.user.userObject.getRecentPads(); }; From 668b7425a807d7e7f7d9f7b11599297f9316b572 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 16 Jul 2018 15:39:34 +0200 Subject: [PATCH 28/86] Make sure we won't move pads from a shared folder to the trash --- www/drive/inner.js | 59 ++++++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 26 deletions(-) diff --git a/www/drive/inner.js b/www/drive/inner.js index b8a95d8b0..59db8824b 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -1153,7 +1153,10 @@ define([ var getElementName = function (path) { var file = manager.find(path); - if (!file || !manager.isFile(file)) { return '???'; } + if (!file) { return; } + if (manager.isSharedFolder(file)) { + return manager.getSharedFolderData(file).title; + } return manager.getTitle(file); }; // manager.moveElements is able to move several paths to a new location, including @@ -1169,6 +1172,22 @@ define([ } andThenMove(); }; + // Delete paths from the drive and/or shared folders (without moving them to the trash) + var deletePaths = function (paths, pathsList) { + pathsList = pathsList || []; + if (paths) { + paths.forEach(function (p) { pathsList.push(p.path); }); + } + var msg = Messages._getKey("fm_removeSeveralPermanentlyDialog", [pathsList.length]); + if (pathsList.length === 1) { + msg = Messages.fm_removePermanentlyDialog; + } + UI.confirm(msg, function(res) { + $(window).focus(); + if (!res) { return; } + manager.delete(pathsList, refresh); + }); + }; // Drag & drop: // The data transferred is a stringified JSON containing the path of the dragged element var onDrag = function (ev, path) { @@ -1180,7 +1199,7 @@ define([ var ePath = $(elmt).data('path'); if (ePath) { var val = manager.find(ePath); - if (!val) { return; } // Error? A ".selected" element in not in the object + if (!val) { return; } // Error? A ".selected" element is not in the object paths.push({ path: ePath, value: { @@ -1194,7 +1213,7 @@ define([ removeSelected(); $element.addClass('cp-app-drive-element-selected'); var val = manager.find(path); - if (!val) { return; } // The element in not in the object + if (!val) { return; } // The element is not in the object paths = [{ path: path, value: { @@ -1240,21 +1259,22 @@ define([ var oldPaths = JSON.parse(data).path; if (!oldPaths) { return; } - // Dropped elements can be moved from the same file manager or imported from another one. // A moved element should be removed from its previous location var movedPaths = []; - var importedElements = []; + var sharedF = false; oldPaths.forEach(function (p) { - var el = manager.find(p.path); - if (el && (stringify(el) === stringify(p.value.el) || !p.value || !p.value.el)) { - movedPaths.push(p.path); - } else { - importedElements.push(p.value); + movedPaths.push(p.path); + if (!sharedF && manager.isInSharedFolder(p.path)) { + sharedF = true; } }); var newPath = findDropPath(ev.target); if (!newPath) { return; } + if (sharedF && manager.isPathIn(newPath, [TRASH])) { + deletePaths(null, movedPaths); + return; + } if (movedPaths && movedPaths.length) { moveElements(movedPaths, newPath, null, refresh); } @@ -2888,21 +2908,6 @@ define([ $contextMenu.find('.cp-app-drive-context-delete').text(Messages.fc_remove) .attr('data-icon', 'fa-eraser'); } - var deletePaths = function (paths, pathsList) { - pathsList = pathsList || []; - if (paths) { - paths.forEach(function (p) { pathsList.push(p.path); }); - } - var msg = Messages._getKey("fm_removeSeveralPermanentlyDialog", [pathsList.length]); - if (pathsList.length === 1) { - msg = Messages.fm_removePermanentlyDialog; - } - UI.confirm(msg, function(res) { - $(window).focus(); - if (!res) { return; } - manager.delete(pathsList, refresh); - }); - }; var deleteOwnedPaths = function (paths, pathsList) { pathsList = pathsList || []; if (paths) { @@ -3096,7 +3101,9 @@ define([ if (!paths.length) { return; } // If we are in the trash or anon pad or if we are holding the "shift" key, // delete permanently - if (!APP.loggedIn || isTrash || e.shiftKey) { + // Or if we are in a shared folder + if (!APP.loggedIn || isTrash || manager.isInSharedFolder(currentPath) + || e.shiftKey) { deletePaths(null, paths); return; } From 9c58dc216ffec205e2c558235553e9a3e1516778 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 16 Jul 2018 16:17:34 +0200 Subject: [PATCH 29/86] Remove option to move a shared folder to the trash --- www/drive/inner.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/www/drive/inner.js b/www/drive/inner.js index 59db8824b..4de5ef4d6 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -836,6 +836,8 @@ define([ containsFolder = true; hide.push('openro'); hide.push('hashtag'); + hide.push('delete'); + //hide.push('deleteowned'); } else { // it's a folder if (containsFolder) { // More than 1 folder selected: cannot create a new subfolder @@ -852,11 +854,21 @@ define([ hide.push('properties'); } // If we're not in the trash nor in a shared folder, hide "remove" - if (!manager.isInSharedFolder(path)) { + var el = manager.find(path); + if (!manager.isInSharedFolder(path) + && !$element.is('.cp-app-drive-element-sharedf')) { hide.push('removesf'); } else if (type === "tree") { hide.push('delete'); - hide.push('deleteowned'); + // Don't hide the deleteowned link if the element is a shared folder and + // it is owned + if (manager.isInSharedFolder(path) || + !$element.is('.cp-app-drive-element-owned')) { + hide.push('deleteowned'); + } else { + // This is a shared folder and it is owned + hide.push('removesf'); + } } }); if (paths.length > 1) { From fc91cf606bd347d3bd2ec63f3f865a83890a5e65 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 16 Jul 2018 18:05:23 +0200 Subject: [PATCH 30/86] Disable moveToTrash button for pads in shared folders --- www/common/common-ui-elements.js | 28 +++++++++++++++++++--------- www/common/cryptpad-common.js | 7 +++++++ www/common/outer/async-store.js | 12 +++++++++++- www/common/outer/store-rpc.js | 1 + www/common/proxy-manager.js | 13 +++++++++---- www/common/sframe-common-outer.js | 8 +++++++- www/common/sframe-protocol.js | 4 ++++ www/common/userObject.js | 1 - www/drive/inner.js | 1 - 9 files changed, 58 insertions(+), 17 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index ab7d304f3..5d2f15f40 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -679,17 +679,27 @@ define([ button .click(common.prepareFeedback(type)) .click(function() { - var msg = common.isLoggedIn() ? Messages.forgetPrompt : Messages.fm_removePermanentlyDialog; - UI.confirm(msg, function (yes) { - if (!yes) { return; } - sframeChan.query('Q_MOVE_TO_TRASH', null, function (err) { - if (err) { return void callback(err); } - var cMsg = common.isLoggedIn() ? Messages.movedToTrash : Messages.deleted; - var msg = common.fixLinks($('
            ').html(cMsg)); - UI.alert(msg); - callback(); + sframeChan.query('Q_IS_ONLY_IN_SHARED_FOLDER', null, function (err, res) { + if (err || res.error) { return void console.log(err || res.error); } + var msg = Messages.forgetPrompt; + if (res) { + UI.alert("WIP: This pad is only in a shared folder. You can't move it to the trash. You can use your CryptDrive if you want to delete it from the folder."); // XXX return; + } else if (!common.isLoggedIn()) { + msg = Messages.fm_removePermanentlyDialog; + } + UI.confirm(msg, function (yes) { + if (!yes) { return; } + sframeChan.query('Q_MOVE_TO_TRASH', null, function (err) { + if (err) { return void callback(err); } + var cMsg = common.isLoggedIn() ? Messages.movedToTrash : Messages.deleted; + var msg = common.fixLinks($('
            ').html(cMsg)); + UI.alert(msg); + callback(); + return; + }); }); + }); }); break; diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 3011618cd..11d5bda10 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -311,6 +311,13 @@ define([ }); }; + common.isOnlyInSharedFolder = function (data, cb) { + postMessage("IS_ONLY_IN_SHARED_FOLDER", data, function (obj) { + if (obj && obj.error) { return void cb(obj.error); } + cb(null, obj); + }); + }; + common.setDisplayName = function (value, cb) { postMessage("SET_DISPLAY_NAME", value, cb); }; diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index c009459ab..75e376099 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -691,8 +691,18 @@ define([ }; // Pads + Store.isOnlyInSharedFolder = function (clientId, channel, cb) { + var res = store.manager.findChannel(channel); + + // A pad is only in a shared worker if: + // 1. this pad is in at least one proxy + // 2. no proxy containing this pad is the main drive + return cb (res.length && !res.some(function (obj) { + // Main drive doesn't have an fId (folder ID) + return !obj.fId; + })); + }; Store.moveToTrash = function (clientId, data, cb) { - // XXX move a pad from a shared folder to the trash? var href = Hash.getRelativeHref(data.href); store.userObject.forget(href); sendDriveEvent('DRIVE_CHANGE', { diff --git a/www/common/outer/store-rpc.js b/www/common/outer/store-rpc.js index 96c392f2a..cbecfe684 100644 --- a/www/common/outer/store-rpc.js +++ b/www/common/outer/store-rpc.js @@ -41,6 +41,7 @@ define([ MOVE_TO_TRASH: Store.moveToTrash, RESET_DRIVE: Store.resetDrive, GET_METADATA: Store.getMetadata, + IS_ONLY_IN_SHARED_FOLDER: Store.isOnlyInSharedFolder, SET_DISPLAY_NAME: Store.setDisplayName, SET_PAD_ATTRIBUTE: Store.setPadAttribute, GET_PAD_ATTRIBUTE: Store.getPadAttribute, diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index d943ffc22..92ee6097a 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -84,6 +84,7 @@ define([ Object.keys(Env.folders).forEach(function (fId) { Env.folders[fId].userObject.findChannels([channel]).forEach(function (id) { ret.push({ + fId: fId, data: Env.folders[fId].userObject.getFileData(id), userObject: Env.folders[fId].userObject }); @@ -95,12 +96,15 @@ define([ var findHref = function (Env, href) { var ret = []; var id = Env.user.userObject.getIdFromHref(href); - ret.push({ - data: Env.user.userObject.getFileData(id), - userObject: Env.user.userObject - }); + if (id) { + ret.push({ + data: Env.user.userObject.getFileData(id), + userObject: Env.user.userObject + }); + } Object.keys(Env.folders).forEach(function (fId) { var id = Env.folders[fId].userObject.getIdFromHref(href); + if (!id) { return; } ret.push({ fId: fId, data: Env.folders[fId].userObject.getFileData(id), @@ -717,6 +721,7 @@ define([ addPad: callWithEnv(addPad), // Tools findChannel: callWithEnv(findChannel), + findHref: callWithEnv(findHref), user: Env.user, folders: Env.folders }; diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 8b30aa2e2..7dab590f2 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -266,7 +266,7 @@ define([ isDeleted: isNewFile && window.location.hash.length > 0, forceCreationScreen: forceCreationScreen, password: password, - channel: secret.channel + channel: secret.channel, }; for (var k in additionalPriv) { metaObj.priv[k] = additionalPriv[k]; } @@ -484,6 +484,12 @@ define([ cb(); }); + sframeChan.on('Q_IS_ONLY_IN_SHARED_FOLDER', function (data, cb) { + Cryptpad.isOnlyInSharedFolder(secret.channel, function (err, t) { + if (err) { return void cb({error: err}); } + cb(t); + }); + }); // Present mode URL sframeChan.on('Q_PRESENT_URL_GET_VALUE', function (data, cb) { diff --git a/www/common/sframe-protocol.js b/www/common/sframe-protocol.js index cc41dcbf3..91e5e2215 100644 --- a/www/common/sframe-protocol.js +++ b/www/common/sframe-protocol.js @@ -111,6 +111,10 @@ define({ 'Q_GET_PAD_ATTRIBUTE': true, 'Q_SET_PAD_ATTRIBUTE': true, + // Check if a pad is only in a shared folder or (also) in the main drive. + // This allows us to change the behavior of some buttons (trash icon...) + 'Q_IS_ONLY_IN_SHARED_FOLDER': true, + // Open/close the File picker (sent from the iframe to the outside) 'EV_FILE_PICKER_OPEN': true, 'EV_FILE_PICKER_CLOSE': true, diff --git a/www/common/userObject.js b/www/common/userObject.js index 9d3cc738a..6c99d4ae9 100644 --- a/www/common/userObject.js +++ b/www/common/userObject.js @@ -308,7 +308,6 @@ define([ result = id; return true; } - return; }); return result; }; diff --git a/www/drive/inner.js b/www/drive/inner.js index 4de5ef4d6..eae9f1e28 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -854,7 +854,6 @@ define([ hide.push('properties'); } // If we're not in the trash nor in a shared folder, hide "remove" - var el = manager.find(path); if (!manager.isInSharedFolder(path) && !$element.is('.cp-app-drive-element-sharedf')) { hide.push('removesf'); From 3a6f7d9b366f31e1295b332d7d63874afb809dff Mon Sep 17 00:00:00 2001 From: mcrosson Date: Mon, 16 Jul 2018 17:02:55 +0000 Subject: [PATCH 31/86] Fixup docker rename calls (addresses #244) --- rpc.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/rpc.js b/rpc.js index 69d84b6dd..b13d1c9ad 100644 --- a/rpc.js +++ b/rpc.js @@ -7,6 +7,8 @@ var Nacl = require("tweetnacl"); /* globals process */ var Fs = require("fs"); +Fs.move = require('fs-extra').move; +Fs.moveSync = require('fs-extra').moveSync; var Path = require("path"); var Https = require("https"); const Package = require('./package.json'); @@ -1054,7 +1056,7 @@ var upload_complete = function (Env, publicKey, id, cb) { } // lol wut handle ur errors - Fs.rename(oldPath, newPath, function (e) { + Fs.move(oldPath, newPath, function (e) { if (e) { WARN('rename', e); return void cb('RENAME_ERR'); @@ -1146,7 +1148,7 @@ var owned_upload_complete = function (Env, safeKey, cb) { // flow is dumb and I need to guard against this which will never happen // / *:: if (typeof(oldPath) === 'object') { throw new Error('should never happen'); } * / - Fs.rename(oldPath, finalPath, w(function (e) { + Fs.move(oldPath, finalPath, w(function (e) { if (e) { w.abort(); return void cb(e.code); @@ -1254,7 +1256,7 @@ var owned_upload_complete = function (Env, safeKey, id, cb) { // flow is dumb and I need to guard against this which will never happen /*:: if (typeof(oldPath) === 'object') { throw new Error('should never happen'); } */ - Fs.rename(oldPath, finalPath, w(function (e) { + Fs.move(oldPath, finalPath, w(function (e) { if (e) { // Remove the ownership file Fs.unlink(finalOwnPath, function (e) { From c9ac3c7c2b2387fb589851db8bb08e170919e793 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 17 Jul 2018 11:22:01 +0200 Subject: [PATCH 32/86] Fix search in shared folders --- www/common/proxy-manager.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index 92ee6097a..3485c2f1d 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -122,7 +122,7 @@ define([ var results = uo.findFile(id); if (fPath) { // This is a shared folder, we have to fix the paths in the results - results.map(function (p) { + results.forEach(function (p) { Array.prototype.unshift.apply(p, fPath); }); } @@ -833,10 +833,11 @@ define([ userObjects.forEach(function (uo) { var fPath = _getUserObjectPath(Env, uo); var results = uo.search(value); + if (!results.length) { return; } if (fPath) { // This is a shared folder, we have to fix the paths in the search results - results = results.map(function (r) { - r.paths.map(function (p) { + results.forEach(function (r) { + r.paths.forEach(function (p) { Array.prototype.unshift.apply(p, fPath); }); }); @@ -964,7 +965,7 @@ define([ isFolderEmpty: callWithEnv(isFolderEmpty), isPathIn: callWithEnv(isPathIn), isSubpath: callWithEnv(isSubpath), - isinTrashRoot: callWithEnv(isInTrashRoot), + isInTrashRoot: callWithEnv(isInTrashRoot), comparePath: callWithEnv(comparePath), hasSubfolder: callWithEnv(hasSubfolder), hasFile: callWithEnv(hasFile), From b4c294565e3a0e10ea20fbe69601f66329d947c1 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 17 Jul 2018 14:00:28 +0200 Subject: [PATCH 33/86] Hide shared folder creation links when inside a shared folder --- www/drive/inner.js | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/www/drive/inner.js b/www/drive/inner.js index eae9f1e28..a46e448cf 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -792,9 +792,13 @@ define([ var filter; if (type === "content") { + // Return true in filter to hide filter = function ($el, className) { if (className === 'newfolder') { return; } - if (className === 'newsharedfolder') { return; } + if (className === 'newsharedfolder') { + // Hide the new shared folder menu if we're already in a shared folder + return manager.isInSharedFolder(currentPath); + } return AppConfig.availablePadTypes.indexOf($el.attr('data-type')) === -1; }; } else { @@ -1766,12 +1770,14 @@ define([ .click(function () { manager.addFolder(currentPath, null, onCreated); }); - $block.find('a.cp-app-drive-new-shared-folder, li.cp-app-drive-new-shared-folder') - .click(function () { - addSharedFolderModal(function (obj) { - manager.addSharedFolder(currentPath, obj, refresh); + if (!manager.isInSharedFolder(currentPath)) { + $block.find('a.cp-app-drive-new-shared-folder, li.cp-app-drive-new-shared-folder') + .click(function () { + addSharedFolderModal(function (obj) { + manager.addSharedFolder(currentPath, obj, refresh); + }); }); - }); + } $block.find('a.cp-app-drive-new-upload, li.cp-app-drive-new-upload') .click(function () { var $input = $('', { @@ -1811,11 +1817,13 @@ define([ attributes: {'class': 'cp-app-drive-new-folder'}, content: $('
            ').append($folderIcon.clone()).html() + Messages.fm_folder }); - options.push({ - tag: 'a', - attributes: {'class': 'cp-app-drive-new-shared-folder'}, - content: $('
            ').append($folderIcon.clone()).html() + "NEW SF" // XXX - }); + if (!manager.isInSharedFolder(currentPath)) { + options.push({ + tag: 'a', + attributes: {'class': 'cp-app-drive-new-shared-folder'}, + content: $('
            ').append($folderIcon.clone()).html() + "NEW SF" // XXX + }); + } options.push({tag: 'hr'}); options.push({ tag: 'a', @@ -2065,12 +2073,14 @@ define([ $element1.append($('', { 'class': 'cp-app-drive-new-name' }) .text(Messages.fm_folder)); // Shared Folder - var $element3 = $('
          • ', { - 'class': 'cp-app-drive-new-shared-folder cp-app-drive-element-row ' + - 'cp-app-drive-element-grid' - }).prepend($folderIcon.clone()).appendTo($container); - $element3.append($('', { 'class': 'cp-app-drive-new-name' }) - .text("SF")); // XXX + if (!manager.isInSharedFolder(currentPath)) { + var $element3 = $('
          • ', { + 'class': 'cp-app-drive-new-shared-folder cp-app-drive-element-row ' + + 'cp-app-drive-element-grid' + }).prepend($folderIcon.clone()).appendTo($container); + $element3.append($('', { 'class': 'cp-app-drive-new-name' }) + .text("SF")); // XXX + } // File var $element2 = $('
          • ', { 'class': 'cp-app-drive-new-upload cp-app-drive-element-row ' + From 6143bceabb4301662921de3c400c3bb6861830ed Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 17 Jul 2018 15:38:23 +0200 Subject: [PATCH 34/86] Fix XXX --- customize.dist/translations/messages.fr.js | 4 +++- customize.dist/translations/messages.js | 13 +++++++++++- www/common/common-ui-elements.js | 2 +- www/common/outer/userObject.js | 4 ++-- www/common/proxy-manager.js | 4 ++-- www/common/userObject.js | 4 ++-- www/drive/inner.js | 23 +++++++++++++--------- 7 files changed, 36 insertions(+), 18 deletions(-) diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index 520a6ceaf..2945c4d6d 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -387,6 +387,7 @@ define(function () { out.fm_newFolder = "Nouveau dossier"; out.fm_newFile = "Nouveau pad"; out.fm_folder = "Dossier"; + out.fm_sharedFolder = "Dossier partagé"; out.fm_folderName = "Nom du dossier"; out.fm_numberOfFolders = "# de dossiers"; out.fm_numberOfFiles = "# de fichiers"; @@ -447,6 +448,7 @@ define(function () { out.fm_tags_used = "Nombre d'utilisations"; // File - Context menu out.fc_newfolder = "Nouveau dossier"; + out.fc_newsharedfolder = "Nouveau dossier partagé"; out.fc_rename = "Renommer"; out.fc_open = "Ouvrir"; out.fc_open_ro = "Ouvrir (lecture seule)"; @@ -460,7 +462,7 @@ define(function () { out.fc_hashtag = "Mots-clés"; out.fc_sizeInKilobytes = "Taille en kilo-octets"; // fileObject.js (logs) - out.fo_moveUnsortedError = "La liste des éléments non triés ne peut pas contenir de dossiers."; + out.fo_moveUnsortedError = "La liste des modèles ne peut pas contenir de dossiers."; out.fo_existingNameError = "Ce nom est déjà utilisé dans ce répertoire. Veuillez en choisir un autre."; out.fo_moveFolderToChildError = "Vous ne pouvez pas déplacer un dossier dans un de ses descendants"; out.fo_unableToRestore = "Impossible de restaurer ce fichier à son emplacement d'origine. Vous pouvez essayer de le déplacer à un nouvel emplacement."; diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index a9299e71a..a66cc28eb 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -387,6 +387,7 @@ define(function () { out.fm_newFolder = "New folder"; out.fm_newFile = "New pad"; out.fm_folder = "Folder"; + out.fm_sharedFolder = "Shared folder"; out.fm_folderName = "Folder name"; out.fm_numberOfFolders = "# of folders"; out.fm_numberOfFiles = "# of files"; @@ -447,6 +448,7 @@ define(function () { out.fm_tags_used = "Number of uses"; // File - Context menu out.fc_newfolder = "New folder"; + out.fc_newsharedfolder = "New shared folder"; out.fc_rename = "Rename"; out.fc_open = "Open"; out.fc_open_ro = "Open (read-only)"; @@ -460,7 +462,7 @@ define(function () { out.fc_hashtag = "Tags"; out.fc_sizeInKilobytes = "Size in Kilobytes"; // fileObject.js (logs) - out.fo_moveUnsortedError = "You can't move a folder to the list of unsorted pads"; + out.fo_moveUnsortedError = "You can't move a folder to the list of templates"; out.fo_existingNameError = "Name already used in that directory. Please choose another one."; out.fo_moveFolderToChildError = "You can't move a folder into one of its descendants"; out.fo_unableToRestore = "Unable to restore that file to its original location. You can try to move it to a new location."; @@ -1200,5 +1202,14 @@ define(function () { out.loading_drive_2 = "Updating data format"; out.loading_drive_3 = "Verifying data integrity"; + // Shared folders + // XXX + out.sharedFolders_forget = "This pad is only stored in a shared folder, you can't move it to the trash. You can use your CryptDrive if you want to delete it from the folder."; + out.sharedFolders_duplicate = "Some of the pads you were trying to move were already stored."; + out.sharedFolders_create = "Create a shared folder"; + out.sharedFolders_create_name = "Folder name"; + out.sharedFolders_create_owned = "Owned folder"; + out.sharedFolders_create_password = "Folder password"; + return out; }); diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 5d2f15f40..741688797 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -683,7 +683,7 @@ define([ if (err || res.error) { return void console.log(err || res.error); } var msg = Messages.forgetPrompt; if (res) { - UI.alert("WIP: This pad is only in a shared folder. You can't move it to the trash. You can use your CryptDrive if you want to delete it from the folder."); // XXX + UI.alert(Messages.sharedFolders_forget); return; } else if (!common.isLoggedIn()) { msg = Messages.fm_removePermanentlyDialog; diff --git a/www/common/outer/userObject.js b/www/common/outer/userObject.js index 6f17eaf55..aee238007 100644 --- a/www/common/outer/userObject.js +++ b/www/common/outer/userObject.js @@ -220,14 +220,14 @@ define([ // Remove existing pads from the "element" variable if (exp.isFile(element) && toRemove.indexOf(element) !== -1) { - // XXX display error in the UI + exp.log(Messages.sharedFolders_duplicate); return; } else if (exp.isFolder(element)) { var _removeExisting = function (root) { for (var k in root) { if (exp.isFile(root[k])) { if (toRemove.indexOf(root[k]) !== -1) { - // XXX display message in UI + exp.log(Messages.sharedFolders_duplicate); delete root[k]; } } else if (exp.isFolder(root[k])) { diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index 3485c2f1d..df2b4ecd1 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -252,7 +252,7 @@ define([ var resolved = _resolvePaths(Env, data.paths); var newResolved = _resolvePath(Env, data.newPath); - if (!newResolved.userObject.isFolder(newResolved.path)) { return void cb(); } // XXX + if (!newResolved.userObject.isFolder(newResolved.path)) { return void cb(); } nThen(function (waitFor) { if (resolved.main.length) { @@ -384,7 +384,7 @@ define([ // 2b. load the proxy Env.loadSharedFolder(id, folderData, waitFor(function (rt, metadata) { if (!rt.proxy.metadata) { // Creating a new shared folder - rt.proxy.metadata = {title: data.name || Messages.fm_newFolder}; // XXX + rt.proxy.metadata = { title: data.name || Messages.fm_newFolder }; } // If we're importing a folder, check its serverside metadata if (data.folderData && metadata) { diff --git a/www/common/userObject.js b/www/common/userObject.js index 6c99d4ae9..453e2cd29 100644 --- a/www/common/userObject.js +++ b/www/common/userObject.js @@ -37,7 +37,7 @@ define([ var logging = function () { console.log.apply(console, arguments); }; - var log = config.log || logging; + var log = exp.log = config.log || logging; var logError = config.logError || logging; var debug = exp.debug = config.debug || logging; @@ -143,7 +143,7 @@ define([ // Data from filesData var getTitle = exp.getTitle = function (file, type) { if (isSharedFolder(file)) { - return '??'; // XXX + return '??'; } var data = getFileData(file); if (!file || !data || !(data.href || data.roHref)) { diff --git a/www/drive/inner.js b/www/drive/inner.js index a46e448cf..be8585156 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -267,7 +267,7 @@ define([ h('li', h('a.cp-app-drive-context-newsharedfolder.dropdown-item.cp-app-drive-context-editable', { 'tabindex': '-1', 'data-icon': faSharedFolder, - }, 'New SF')), // XXX + }, Messages.fc_newsharedfolder)), h('li', h('a.cp-app-drive-context-hashtag.dropdown-item.cp-app-drive-context-editable', { 'tabindex': '-1', 'data-icon': faTags, @@ -1706,17 +1706,16 @@ define([ }; // Ask for name, password and owner - // XXX var content = h('div', [ - h('h4', "NEW SF TITLE"), - h('label', {for: 'cp-app-drive-sf-name'}, 'SF NAME'), - h('input#cp-app-drive-sf-name', {type: 'text', placeholder: "NEW FOLDER NAME"}), - //h('label', {for: 'cp-app-drive-sf-password'}, 'SF PASSWORD'), + h('h4', Messages.sharedFolders_create), + h('label', {for: 'cp-app-drive-sf-name'}, Messages.sharedFolders_create_name), + h('input#cp-app-drive-sf-name', {type: 'text', placeholder: Messages.fm_newFolder}), + //h('label', {for: 'cp-app-drive-sf-password'}, Messages.sharedFolders_create_password), //UI.passwordInput({id: 'cp-app-drive-sf-password'}), h('span', { style: 'display:flex;align-items:center;justify-content:space-between' }, [ - UI.createCheckbox('cp-app-drive-sf-owned', "OWNED?", true), + UI.createCheckbox('cp-app-drive-sf-owned', Messages.sharedFolders_create_owned, true), createHelper('/faq.html#keywords-owned', Messages.creation_owned1) // TODO ]), ]); @@ -1774,6 +1773,7 @@ define([ $block.find('a.cp-app-drive-new-shared-folder, li.cp-app-drive-new-shared-folder') .click(function () { addSharedFolderModal(function (obj) { + if (!obj) { return; } manager.addSharedFolder(currentPath, obj, refresh); }); }); @@ -1821,7 +1821,7 @@ define([ options.push({ tag: 'a', attributes: {'class': 'cp-app-drive-new-shared-folder'}, - content: $('
            ').append($folderIcon.clone()).html() + "NEW SF" // XXX + content: $('
            ').append($folderIcon.clone()).html() + Messages.fm_sharedFolder }); } options.push({tag: 'hr'}); @@ -2079,7 +2079,7 @@ define([ 'cp-app-drive-element-grid' }).prepend($folderIcon.clone()).appendTo($container); $element3.append($('', { 'class': 'cp-app-drive-new-name' }) - .text("SF")); // XXX + .text(Messages.fm_sharedFolder)); } // File var $element2 = $('
          • ', { @@ -2922,6 +2922,10 @@ define([ data.roHref = base + data.roHref; } + if (manager.isSharedFolder(el)) { + delete data.roHref; + } + UIElements.getProperties(common, data, cb); }; @@ -3002,6 +3006,7 @@ define([ else if ($(this).hasClass('cp-app-drive-context-newsharedfolder')) { if (paths.length !== 1) { return; } addSharedFolderModal(function (obj) { + if (!obj) { return; } manager.addSharedFolder(paths[0].path, obj, refresh); }); } From 38a1e5e39fb854cdbad8896333901beb85ee6510 Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Tue, 17 Jul 2018 16:21:54 +0200 Subject: [PATCH 35/86] Add fallback for browsers which do not support CSS variables --- bower.json | 2 +- customize.dist/src/less2/include/avatar.less | 13 ++- .../src/less2/include/checkmark.less | 37 ++++++-- .../src/less2/include/creation.less | 21 ++++- .../src/less2/include/framework.less | 1 - customize.dist/src/less2/include/help.less | 30 ++++-- customize.dist/src/less2/include/toolbar.less | 94 ++++++++++++++----- 7 files changed, 149 insertions(+), 49 deletions(-) diff --git a/bower.json b/bower.json index 28db3ec8e..79859659e 100644 --- a/bower.json +++ b/bower.json @@ -36,7 +36,7 @@ "alertifyjs": "1.0.11", "scrypt-async": "1.2.0", "require-css": "0.1.10", - "less": "^2.7.2", + "less": "^3.7.1", "bootstrap": "^v4.0.0", "diff-dom": "2.1.1", "nthen": "^0.1.5", diff --git a/customize.dist/src/less2/include/avatar.less b/customize.dist/src/less2/include/avatar.less index 367034972..8e9cfd8fa 100644 --- a/customize.dist/src/less2/include/avatar.less +++ b/customize.dist/src/less2/include/avatar.less @@ -1,11 +1,18 @@ @import (reference) "./tools.less"; +.avatar_vars( + @width: 30px +) { + @avatar-width: @width; + @avatar-font-size: @width / 1.2; +} .avatar_main(@width) { --LessLoader_require: LessLoader_currentFile(); - - --avatar-width: @width; - --avatar-font-size: @width / 1.2; + .avatar_vars(@width); + --avatar-width: @avatar-width; + --avatar-font-size: @avatar-font-size; } & { + .avatar_vars(); &.cp-avatar { overflow: hidden; text-overflow: ellipsis; diff --git a/customize.dist/src/less2/include/checkmark.less b/customize.dist/src/less2/include/checkmark.less index 2f606f7ec..8f6e38cbb 100644 --- a/customize.dist/src/less2/include/checkmark.less +++ b/customize.dist/src/less2/include/checkmark.less @@ -1,17 +1,28 @@ @import (reference) "./colortheme-all.less"; +.checkmark_vars( + @size: 20px +) { + @checkmark-size: @size; + @checkmark-width: round(@size / 8); + @checkmark-dim1: round(@size / 3); + @checkmark-dim2: round(2 * @size / 3); + @checkmark-top: round(@size / 12) - 1; + @checkmark-radio-size: @checkmark-dim1 * 3; +} + .checkmark_main(@size) { --LessLoader_require: LessLoader_currentFile(); - - --checkmark-size: @size; - --checkmark-width: round(@size / 8); - @dim1: round(@size / 3); - --checkmark-dim1: round(@size / 3); - --checkmark-dim2: round(2 * @size / 3); - --checkmark-top: round(@size / 12) - 1; - --checkmark-radio-size: @dim1 * 3; + .checkmark_vars(@size); + --checkmark-size: @checkmark-size; + --checkmark-width: @checkmark-width; + --checkmark-dim1: @checkmark-dim1; + --checkmark-dim2: @checkmark-dim2; + --checkmark-top: @checkmark-top; + --checkmark-radio-size: @checkmark-radio-size; } & { + .checkmark_vars(); // Text .cp-checkmark { margin: 0; @@ -64,7 +75,9 @@ .cp-checkmark-mark { margin-right: 10px; position: relative; + height: @checkmark-size; height: var(--checkmark-size); + width: @checkmark-size; width: var(--checkmark-size); background-color: @colortheme_checkmark-back0; display: flex; @@ -74,11 +87,15 @@ &:after { content: ""; display: none; + margin-top: @checkmark-top; margin-top: var(--checkmark-top); + width: @checkmark-dim1; width: var(--checkmark-dim1); + height: @checkmark-dim2; height: var(--checkmark-dim2); transform: rotate(45deg); border: solid @colortheme_checkmark-col1; + border-width: 0 @checkmark-width @checkmark-width 0; border-width: 0 var(--checkmark-width) var(--checkmark-width) 0; position: absolute; } @@ -139,7 +156,9 @@ .cp-radio-mark { margin-right: 10px; position: relative; + height: @checkmark-radio-size; height: var(--checkmark-radio-size); + width: @checkmark-radio-size; width: var(--checkmark-radio-size); background-color: @colortheme_checkmark-back0; border-radius: 50%; @@ -153,7 +172,9 @@ content: ""; border-radius: 50%; background: white; + width: @checkmark-dim1; width: var(--checkmark-dim1); + height: @checkmark-dim1; height: var(--checkmark-dim1); //transform: rotate(45deg); diff --git a/customize.dist/src/less2/include/creation.less b/customize.dist/src/less2/include/creation.less index bb1d38958..284c5ed39 100644 --- a/customize.dist/src/less2/include/creation.less +++ b/customize.dist/src/less2/include/creation.less @@ -3,18 +3,25 @@ @import (reference) "./tools.less"; @import (reference) './icon-colors.less'; +.creation_vars( + @color: @colortheme_default-color, + @bg-color: @colortheme_default-bg +) { + @creation-color: @color; + @creation-bg-color: @bg-color; +}; + .creation_main( - @color: @colortheme_default-color, // Color of the text for the toolbar - @bg-color: @colortheme_default-bg, // color of the toolbar background - @warn-color: @colortheme_default-warn, // color of the warning text in the toolbar + @color, + @bg-color ) { --LessLoader_require: LessLoader_currentFile(); - + .creation_vars(@color, @bg-color); --creation-color: @color; --creation-bg-color: @bg-color; - // --creation-warn-color: @warn-color; // unused } & { + .creation_vars(); @colortheme_creation-modal-bg: #fff; @colortheme_creation-modal: #666; @colortheme_creation-modal-title: @colortheme_loading-bg; @@ -267,9 +274,12 @@ border: 1px solid transparent; &.cp-creation-template-selected { + color: @creation-color !important; color: var(--creation-color) !important; + background-color: @creation-bg-color !important; background-color: var(--creation-bg-color) !important; .fa { + color: @creation-color; color: var(--creation-color); } } @@ -301,6 +311,7 @@ max-width: 100%; } .fa { + color: @creation-bg-color; color: var(--creation-bg-color); cursor: pointer; width: 100px; diff --git a/customize.dist/src/less2/include/framework.less b/customize.dist/src/less2/include/framework.less index 36db08a61..ae49f0660 100644 --- a/customize.dist/src/less2/include/framework.less +++ b/customize.dist/src/less2/include/framework.less @@ -34,7 +34,6 @@ .password_main(); .creation_main( @bg-color: @bg-color, - @warn-color: @warn-color, @color: @color ); font: @colortheme_app-font; diff --git a/customize.dist/src/less2/include/help.less b/customize.dist/src/less2/include/help.less index cd54aaff2..c39d167d0 100644 --- a/customize.dist/src/less2/include/help.less +++ b/customize.dist/src/less2/include/help.less @@ -1,16 +1,26 @@ @import (reference) "./colortheme-all.less"; +.help_vars ( + @color: @colortheme_default-color, + @bg-color: @colortheme_default-bg +) { + @help-bg-color-l15: lighten(@bg-color, 15%); + @help-text-color: contrast(@help-bg-color-l15, #fff, #000); //@color; + @help-link-color: contrast(@help-bg-color-l15, lighten(spin(@bg-color, 180), 10%), darken(spin(@bg-color, 180), 10%)); +} .help_main (@color, @bg-color) { --LessLoader_require: LessLoader_currentFile(); - - --help-bg-color-l15: lighten(@bg-color, 15%); - --help-bg-color-spin: spin(@bg-color, 180); - --help-bg-color-spin-d10: darken(spin(@bg-color, 180), 10%); - --help-bg-color-spin-l10: lighten(spin(@bg-color, 180), 10%); -} + .help_vars(@color, @bg-color); + --help-bg-color-l15: @help-bg-color-l15; + --help-text-color: @help-text-color; + --help-link-color: @help-link-color; +}; & { + .help_vars(); .cp-help-container { + position: relative; + background-color: @help-bg-color-l15; background-color: var(--help-bg-color-l15); &.cp-help-hidden { display: none; @@ -22,13 +32,13 @@ right: 5px; } .cp-help-text { - color: contrast(var(--help-bg-color-l15), #fff, #000); //@color; + color: @help-text-color; + color: var(--help-text-color); margin: 0; padding: 15px; a { - //color: darken(@colortheme_link-color, 30%); - color: contrast(var(--help-bg-color-l15), var(--help-bg-color-spin-l10), var(--help-bg-color-spin-d10)); - //color: darken(spin(var(--help-bg-color-l15), 180), 10%); + color: @help-link-color; + color: var(--help-link-color); } h1 { font-size: 20px; diff --git a/customize.dist/src/less2/include/toolbar.less b/customize.dist/src/less2/include/toolbar.less index d3e57981e..122fff891 100644 --- a/customize.dist/src/less2/include/toolbar.less +++ b/customize.dist/src/less2/include/toolbar.less @@ -10,27 +10,52 @@ @import (reference) "./modal.less"; @import (reference) "./help.less"; -.toolbar_main ( +.toolbar_vars ( @color: @colortheme_default-color, // Color of the text for the toolbar @bg-color: @colortheme_default-bg, // color of the toolbar background - @warn-color: @colortheme_default-warn, // color of the warning text in the toolbar + @warn-color: @colortheme_default-warn // color of the warning text in the toolbar +) { + @toolbar-color: @color; + @toolbar-color-l20: lighten(@color, 20%); + @toolbar-color-d20: darken(@color, 20%); + @toolbar-color-d15: darken(@color, 15%); + + @toolbar-bg-color: @bg-color; + @toolbar-bg-color-l8: lighten(@bg-color, 8%); + @toolbar-bg-color-l20: lighten(@bg-color, 20%); + @toolbar-bg-color-d5: darken(@bg-color, 5%); + @toolbar-bg-color-d10: darken(@bg-color, 10%); + @toolbar-bg-color-d15: darken(@bg-color, 15%); + + @toolbar-warn-color: @warn-color; + + @toolbar-userlist-name-edit: contrast(@toolbar-color, @toolbar-color-l20, @toolbar-color-d20); +}; + +.toolbar_main ( + @color, // Color of the text for the toolbar + @bg-color, // color of the toolbar background + @warn-color, // color of the warning text in the toolbar @barWidth: 600px // width of the toolbar ) { --LessLoader_require: LessLoader_currentFile(); + .toolbar_vars(@color, @bg-color, @warn-color); + + --toolbar-color: @toolbar-color; + --toolbar-color-l20: @toolbar-color-l20; + --toolbar-color-d20: @toolbar-color-d20; + --toolbar-color-d15: @toolbar-color-d15; - --toolbar-color: @color; - --toolbar-color-l20: lighten(@color, 20%); - --toolbar-color-d20: darken(@color, 20%); - --toolbar-color-d15: darken(@color, 15%); + --toolbar-bg-color: @toolbar-bg-color; + --toolbar-bg-color-l8: @toolbar-bg-color-l8; + --toolbar-bg-color-l20: @toolbar-bg-color-l20; + --toolbar-bg-color-d5: @toolbar-bg-color-d5; + --toolbar-bg-color-d10: @toolbar-bg-color-d10; + --toolbar-bg-color-d15: @toolbar-bg-color-d15; - --toolbar-bg-color: @bg-color; - --toolbar-bg-color-l8: lighten(@bg-color, 8%); - --toolbar-bg-color-l20: lighten(@bg-color, 20%); - --toolbar-bg-color-d5: darken(@bg-color, 5%); - --toolbar-bg-color-d10: darken(@bg-color, 10%); - --toolbar-bg-color-d15: darken(@bg-color, 15%); + --toolbar-warn-color: @toolbar-warn-color; - --toolbar-warn-color: @warn-color; + --toolbar-userlist-name-edit: @toolbar-userlist-name-edit; @media screen and (max-width: @barWidth) { .cp-toolbar-rightside { @@ -47,6 +72,7 @@ .modal_main(); }; & { + .toolbar_vars(); @toolbar_line-height: 32px; @toolbar_top-height: 64px; @toolbar_button-font: @colortheme_app-font; @@ -59,15 +85,18 @@ .cp-markdown-toolbar { height: @toolbar_line-height; + background-color: @toolbar-bg-color-l20; background-color: var(--toolbar-bg-color-l20); display: none; button { height: @toolbar_line-height !important; outline: 0; + color: @toolbar-color; color: var(--toolbar-color); .toolbar_button; font: normal normal normal 14px/1 FontAwesome; &:hover { + background-color: @toolbar-bg-color-l8; background-color: var(--toolbar-bg-color-l8); } &.cp-markdown-help { float: right; } @@ -106,6 +135,7 @@ } .cp-toolbar-userlist-drawer { + background-color: @toolbar-bg-color; background-color: var(--toolbar-bg-color); font: @colortheme_app-font-size @colortheme_font; min-width: 175px; @@ -294,30 +324,38 @@ } .cp-toolbar-userlist-drawer { + background-color: @toolbar-bg-color; background-color: var(--toolbar-bg-color); + color: @toolbar-color; color: var(--toolbar-color); .cp-toolbar-userlist-drawer-close { + color: @toolbar-color; color: var(--toolbar-color); } h2 { + background-color: @toolbar-bg-color-d10; background-color: var(--toolbar-bg-color-d10); + color: @toolbar-color; color: var(--toolbar-color); } .cp-toolbar-userlist-name-input { + background-color: @toolbar-bg-color-d10; background-color: var(--toolbar-bg-color-d10); + color: @toolbar-color; color: var(--toolbar-color); } .cp-toolbar-userlist-name-edit { - color: contrast(var(--toolbar-color), - var(--toolbar-color-l20), - var(--toolbar-color-d20)); + color: @toolbar-userlist-name-edit; + color: var(--toolbar-userlist-name-edit); background: transparent; &:hover { + color: @toolbar-color; color: var(--toolbar-color); } } .cp-toolbar-userlist-friend { &:hover { + color: @toolbar-color-d15; color: var(--toolbar-color-d15); } } @@ -338,7 +376,9 @@ display: flex; flex-wrap: wrap; justify-content: space-between; + background-color: @toolbar-bg-color; background-color: var(--toolbar-bg-color); + color: @toolbar-color; color: var(--toolbar-color); .fa { @@ -557,24 +597,32 @@ .cp-toolbar-spinner { font-size: @colortheme_app-font-size; + color: @toolbar-color; color: var(--toolbar-color); } .cp-toolbar-limit { + text-shadow: -1px 0 @toolbar-color, 0 1px @toolbar-color, 1px 0 @toolbar-color, 0 -1px @toolbar-color; text-shadow: -1px 0 var(--toolbar-color), 0 1px var(--toolbar-color), 1px 0 var(--toolbar-color), 0 -1px var(--toolbar-color); + color: @toolbar-warn-color; color: var(--toolbar-warn-color); } .cp-toolbar-leftside, .cp-toolbar-rightside { + background-color: @toolbar-bg-color-l8; background-color: var(--toolbar-bg-color-l8); button:hover, button.cp-toolbar-button-active { + background-color: @toolbar-bg-color; background-color: var(--toolbar-bg-color); } } .cp-toolbar-title-hoverable:hover { .cp-toolbar-title-editable, .cp-toolbar-title-edit { cursor: text; + border: 1px solid @toolbar-bg-color-d15; border: 1px solid var(--toolbar-bg-color-d15); + background: @toolbar-bg-color-d10; background: var(--toolbar-bg-color-d10); transition: all 0.15s; + color: @toolbar-color; color: var(--toolbar-color); } .cp-toolbar-title-editable { @@ -582,16 +630,23 @@ } } .cp-toolbar-title-save { + border: 1px solid @toolbar-bg-color-d15; border: 1px solid var(--toolbar-bg-color-d15); + background: @toolbar-bg-color-d10; background: var(--toolbar-bg-color-d10); + color: @toolbar-color; color: var(--toolbar-color); &:hover { + background: @toolbar-bg-color-d5; background: var(--toolbar-bg-color-d5); } } input { + border: 1px solid @toolbar-bg-color-d15; border: 1px solid var(--toolbar-bg-color-d15); + background: @toolbar-bg-color-d10; background: var(--toolbar-bg-color-d10); + color: @toolbar-color; color: var(--toolbar-color); } .cp-dropdown-content.cp-dropdown-left a { @@ -618,6 +673,7 @@ padding: 0; margin: 0 5px; font-size: @colortheme_app-font-size; + color: @toolbar-warn-color; color: var(--toolbar-warn-color); .cp-pnp-msg { padding-left: 5px; @@ -627,6 +683,7 @@ font-size: @colortheme_app-font-size; font-family: @colortheme_font; font-weight: bold; + color: @toolbar-warn-color; color: var(--toolbar-warn-color); &:hover { text-decoration: underline; @@ -921,11 +978,6 @@ display: flex; min-height: @toolbar_line-height; overflow: hidden; - @media screen and (max-width: var(--toolbar-barWidth)) { // 450px - flex-wrap: wrap; - height: auto; - width: 100%; - } &:empty { min-height: 0; height: 0; From 08005a709e60bd62fd8144069ae5c326310b284c Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 17 Jul 2018 16:38:20 +0200 Subject: [PATCH 36/86] Add a share icon in the drive when displaying a shared folder --- customize.dist/translations/messages.js | 1 + www/common/common-ui-elements.js | 29 +++++++++++++++++++++++++ www/common/proxy-manager.js | 2 +- www/drive/inner.js | 25 +++++++++++++++++++++ 4 files changed, 56 insertions(+), 1 deletion(-) diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index a66cc28eb..543a0f778 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -1210,6 +1210,7 @@ define(function () { out.sharedFolders_create_name = "Folder name"; out.sharedFolders_create_owned = "Owned folder"; out.sharedFolders_create_password = "Folder password"; + out.sharedFolders_share = "Share this URL with other registered users to give them access to the shared folder. Once they open this URL, the shared folder will be added to the root directory of their CryptDrive."; return out; }); diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 741688797..900913c0f 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -517,6 +517,35 @@ define([ } return tabs; }; + UIElements.createSFShareModal = function (config) { + var origin = config.origin; + var pathname = config.pathname; + var hashes = config.hashes; + + if (!hashes.editHash) { throw new Error("You must provide a valid hash"); } + var url = origin + pathname + '#' + hashes.editHash; + + // Share link tab + var link = h('div.cp-share-modal', [ + h('label', Messages.sharedFolders_share), + h('br'), + UI.dialog.selectable(url, { id: 'cp-share-link-preview', tabindex: 1 }) + ]); + var linkButtons = [{ + name: Messages.cancel, + onClick: function () {}, + keys: [27] + }, { + className: 'primary', + name: Messages.share_linkCopy, + onClick: function () { + var success = Clipboard.copy(url); + if (success) { UI.log(Messages.shareSuccess); } + }, + keys: [13] + }]; + return UI.dialog.customModal(link, {buttons: linkButtons}); + }; UIElements.createButton = function (common, type, rightside, data, callback) { var AppConfig = common.getAppConfig(); diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index df2b4ecd1..622eacbf0 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -866,7 +866,7 @@ define([ var isInSharedFolder = function (Env, path) { var resolved = _resolvePath(Env, path); - return typeof resolved.id === "number"; + return typeof resolved.id === "number" ? resolved.id : false; }; /* Generic: doesn't need access to a proxy */ diff --git a/www/drive/inner.js b/www/drive/inner.js index be8585156..93d8e5722 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -1864,6 +1864,27 @@ define([ $container.append($block); }; + var createShareButton = function (id, $container) { + var $shareBlock = $('