From cd7c5abc3edbea95caeee9d92fdfb7c4cac6abea Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 10 Jan 2018 16:46:46 +0100 Subject: [PATCH 1/3] Fix a missing callback in closeChannel --- storage/file.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/file.js b/storage/file.js index 31b58aa94..a1348d427 100644 --- a/storage/file.js +++ b/storage/file.js @@ -45,7 +45,7 @@ var getChannelMetadata = function (Env, channelId, cb) { }; var closeChannel = function (env, channelName, cb) { - if (!env.channels[channelName]) { return; } + if (!env.channels[channelName]) { return void cb(); } try { env.channels[channelName].writeStream.close(); delete env.channels[channelName]; From 8c9490868b64eb078bade7666792cfceb2fcbf95 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 10 Jan 2018 17:57:40 +0100 Subject: [PATCH 2/3] improve owned pads management in the drive --- customize.dist/translations/messages.fr.js | 1 + customize.dist/translations/messages.js | 1 + www/common/common-ui-elements.js | 8 +++ www/common/sframe-common-outer.js | 7 +-- www/drive/inner.html | 3 +- www/drive/inner.js | 58 ++++++++++++++++++---- 6 files changed, 63 insertions(+), 15 deletions(-) diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index c26333b2b..ee8a1a4d2 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -419,6 +419,7 @@ define(function () { out.fc_open = "Ouvrir"; out.fc_open_ro = "Ouvrir (lecture seule)"; out.fc_delete = "Déplacer vers la corbeille"; + out.fc_delete_owned = "Supprimer du serveur"; out.fc_restore = "Restaurer"; out.fc_remove = "Supprimer de votre CryptDrive"; out.fc_empty = "Vider la corbeille"; diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index cd3f966a9..84dbdde0e 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -422,6 +422,7 @@ define(function () { out.fc_open = "Open"; out.fc_open_ro = "Open (read-only)"; out.fc_delete = "Move to trash"; + out.fc_delete_owned = "Delete from the server"; out.fc_restore = "Restore"; out.fc_remove = "Remove from your CryptDrive"; out.fc_empty = "Empty the trash"; diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 90e554d31..f49491ebf 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -107,9 +107,11 @@ define([ .appendTo($d); var owners = Messages.creation_noOwner; var edPublic = common.getMetadataMgr().getPrivateData().edPublic; + var owned = false; if (data.owners && data.owners.length) { if (data.owners.indexOf(edPublic) !== -1) { owners = Messages.yourself; + owned = true; } else { owners = Messages.creation_ownedByOther; } @@ -117,6 +119,12 @@ define([ $d.append(UI.dialog.selectable(owners, { id: 'cp-app-prop-owners', })); + /* TODO + if (owned) { + var $deleteOwned = $('button').text(Messages.fc_delete_owned).click(function () { + }); + $d.append($deleteOwned); + }*/ var expire = Messages.creation_expireFalse; if (data.expire && typeof (data.expire) === "number") { diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 64b9df509..31a29b623 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -494,6 +494,10 @@ define([ Cryptpad.setLanguage(data, cb); }); + sframeChan.on('Q_CONTACTS_CLEAR_OWNED_CHANNEL', function (channel, cb) { + Cryptpad.clearOwnedChannel(channel, cb); + }); + if (cfg.addRpc) { cfg.addRpc(sframeChan, Cryptpad, Utils); } @@ -530,9 +534,6 @@ define([ sframeChan.on('Q_CONTACTS_SET_CHANNEL_HEAD', function (opt, cb) { Cryptpad.messenger.setChannelHead(opt, cb); }); - sframeChan.on('Q_CONTACTS_CLEAR_OWNED_CHANNEL', function (channel, cb) { - Cryptpad.clearOwnedChannel(channel, cb); - }); Cryptpad.messenger.onMessageEvent.reg(function (data) { sframeChan.event('EV_CONTACTS_MESSAGE', data); diff --git a/www/drive/inner.html b/www/drive/inner.html index d2f7a2f55..93d4688ef 100644 --- a/www/drive/inner.html +++ b/www/drive/inner.html @@ -24,6 +24,7 @@
  • Open (read-only)
  • Rename
  • Delete
  • +
  • Delete permanently
  • New folder
  • Properties
  • Tags
  • @@ -44,7 +45,7 @@
  • Open
  • Open (read-only)
  • Delete
  • -
  • Delete permanently
  • +
  • Delete permanently
  • Properties
  • Tags
  • diff --git a/www/drive/inner.js b/www/drive/inner.js index 0878449ab..381eb5e94 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -658,11 +658,12 @@ define([ if (!isOwnDrive()) { hide.push($menu.find('a.cp-app-drive-context-own')); } - if ($element.is('.cp-app-drive-element-owned')) { - hide.push($menu.find('a.cp-app-drive-context-delete')); - } else { + if (!$element.is('.cp-app-drive-element-owned')) { hide.push($menu.find('a.cp-app-drive-context-deleteowned')); } + if ($element.is('.cp-app-drive-element-notrash')) { + hide.push($menu.find('a.cp-app-drive-context-delete')); + } if ($element.is('.cp-app-drive-element-file')) { // No folder in files hide.push($menu.find('a.cp-app-drive-context-newfolder')); @@ -1183,6 +1184,7 @@ define([ if (data.owners && data.owners.indexOf(edPublic) !== -1) { var $owned = $ownedIcon.clone().appendTo($state); $owned.attr('title', Messages.fm_padIsOwned); + $span.addClass('cp-app-drive-element-owned'); } else if (data.owners && data.owners.length) { var $owner = $ownerIcon.clone().appendTo($state); $owner.attr('title', Messages.fm_padIsOwnedOther); @@ -2065,7 +2067,7 @@ define([ var roClass = typeof(ro) === 'undefined' ? ' cp-app-drive-element-noreadonly' : ro ? ' cp-app-drive-element-readonly' : ''; var $element = $('
  • ', { - 'class': 'cp-app-drive-element cp-app-drive-element-file cp-app-drive-element-row' + roClass, + 'class': 'cp-app-drive-element cp-app-drive-element-notrash cp-app-drive-element-file cp-app-drive-element-row' + roClass, }); $element.prepend($icon).dblclick(function () { openFile(id); @@ -2103,7 +2105,8 @@ define([ var roClass = typeof(ro) === 'undefined' ? ' cp-app-drive-element-noreadonly' : ro ? ' cp-app-drive-element-readonly' : ''; var $element = $('
  • ', { - 'class': 'cp-app-drive-element cp-app-drive-element-owned cp-app-drive-element-file cp-app-drive-element-row' + roClass + 'class': 'cp-app-drive-element cp-app-drive-element-notrash ' + + 'cp-app-drive-element-file cp-app-drive-element-row' + roClass }); $element.prepend($icon).dblclick(function () { openFile(id); @@ -2600,6 +2603,30 @@ define([ paths.forEach(function (p) { pathsList.push(p.path); }); moveElements(pathsList, [TRASH], false, refresh); } + else if ($(this).hasClass('cp-app-drive-context-deleteowned')) { + var pathsListD = []; + var msgD = Messages.fm_deleteOwnedPads; + UI.confirm(msgD, function(res) { + $(window).focus(); + if (!res) { return; } + // Try to delete each selected pad from server, and delete from drive if no error + var n = nThen(function () {}); + paths.forEach(function (p) { + var el = filesOp.find(p.path); + var data = filesOp.getFileData(el); + var parsed = Hash.parsePadUrl(data.href); + var channel = Util.base64ToHex(parsed.hashData.channel); + n = n.nThen(function (waitFor) { + sframeChan.query('Q_CONTACTS_CLEAR_OWNED_CHANNEL', channel, + waitFor(function (e) { + if (e) { return void console.error(e); } + filesOp.delete([p.path], refresh); + })); + }); + }); + }); + return; + } else if ($(this).hasClass('cp-app-drive-context-open')) { paths.forEach(function (p) { var $element = p.element; @@ -2689,17 +2716,26 @@ define([ moveElements(pathsList, [TRASH], false, refresh); } else if ($(this).hasClass('cp-app-drive-context-deleteowned')) { - // TODO - // Remove owned pad from drive and remove from server var pathsListD = []; - paths.forEach(function (p) { pathsListD.push(p.path); }); var msgD = Messages.fm_deleteOwnedPads; UI.confirm(msgD, function(res) { $(window).focus(); if (!res) { return; } - filesOp.delete(pathsListD, refresh); - // TODO XXX HERE - // RPC to delete from server + // Try to delete each selected pad from server, and delete from drive if no error + var n = nThen(function () {}); + paths.forEach(function (p) { + var el = filesOp.find(p.path); + var data = filesOp.getFileData(el); + var parsed = Hash.parsePadUrl(data.href); + var channel = Util.base64ToHex(parsed.hashData.channel); + n = n.nThen(function (waitFor) { + sframeChan.query('Q_CONTACTS_CLEAR_OWNED_CHANNEL', channel, + waitFor(function (e) { + if (e) { return void console.error(e); } + filesOp.delete([p.path], refresh); + })); + }); + }); }); return; } From ef480fea79c6e1b6eaa761af16c6a413a2f1c746 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 11 Jan 2018 16:02:05 +0100 Subject: [PATCH 3/3] Add a settings category for the pad creation screen --- .../src/less2/include/sidebar-layout.less | 3 + customize.dist/translations/messages.fr.js | 9 + customize.dist/translations/messages.js | 11 +- www/common/common-ui-elements.js | 33 +- www/common/sframe-app-framework.js | 11 +- www/common/sframe-common.js | 8 + www/drive/inner.js | 2 - www/settings/app-settings.less | 76 +- www/settings/inner.js | 655 ++++++++++++------ 9 files changed, 595 insertions(+), 213 deletions(-) diff --git a/customize.dist/src/less2/include/sidebar-layout.less b/customize.dist/src/less2/include/sidebar-layout.less index 89d23d946..ede03942e 100644 --- a/customize.dist/src/less2/include/sidebar-layout.less +++ b/customize.dist/src/less2/include/sidebar-layout.less @@ -48,6 +48,9 @@ display: block; color: @description-color; margin-bottom: 5px; + p { + margin-bottom: 0; + } } margin-bottom: 20px; } diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index ee8a1a4d2..c79e07708 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -487,6 +487,7 @@ define(function () { out.settings_cat_drive = "CryptDrive"; out.settings_cat_code = "Code"; out.settings_cat_pad = "Documents texte"; + out.settings_cat_creation = "Nouveau pad"; out.settings_title = "Préférences"; out.settings_save = "Sauver"; @@ -547,6 +548,14 @@ define(function () { out.settings_padWidthHint = "L'éditeur de documents texte occupe toute la largeur de l'écran disponible par défaut, ce qui peut rendre le texte difficile à lire. Vous pouvez ici réduire la largeur de l'éditeur."; out.settings_padWidthLabel = "Réduire la largeur de l'éditeur"; + out.settings_creationSkip = "Passer l'écran de création de pad"; + out.settings_creationSkipHint = "L'écran de création de pad offre de nouvelles options pour créer un pad, permettant d'avoir plus de contrôle et de sécurité concernant vos données. Toutefois, il peut ralentir votre travail en ajoutant une étape supplémentaire et donc, ici, vous avez la possibilité de choisir de passer cet écran et d'utiliser les paramètres par défaut choisis au-dessus."; + out.settings_creationSkipTrue = "Passer"; + out.settings_creationSkipFalse = "Afficher"; + + out.settings_templateSkip = "Passer la fenêtre de choix d'un modèle"; + out.settings_templateSkipHint = "Quand vous créez un nouveau pad, et si vous possédez des modèles pour ce type de pad, une fenêtre peut apparaître pour demander si vous souhaitez importer un modèle. Ici vous pouvez choisir de ne jamais montrer cette fenêtre et donc de ne jamais utiliser de modèle."; + out.upload_title = "Hébergement de fichiers"; out.upload_rename = "Souhaitez-vous renommer {0} avant son stockage en ligne ?
    " + "L'extension du fichier ({1}) sera ajoutée automatiquement. "+ diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 84dbdde0e..3261f4b3b 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -493,6 +493,7 @@ define(function () { out.settings_cat_drive = "CryptDrive"; out.settings_cat_code = "Code"; out.settings_cat_pad = "Rich text"; + out.settings_cat_creation = "New pad"; out.settings_title = "Settings"; out.settings_save = "Save"; @@ -553,6 +554,14 @@ define(function () { out.settings_padWidthHint = "Rich text pads use by default the maximum available width on your screen and it can be difficult to read. You can reduce the editor's width here."; out.settings_padWidthLabel = "Reduce the editor's width"; + out.settings_creationSkip = "Skip the pad creation screen"; + out.settings_creationSkipHint = "The pad creation screen offers new options to create a pad, providing you more control and security over your data. However, it may slow down your workflow by adding one additionnal step so, here, you have the option to skip this screen and use the default settings selected above."; + out.settings_creationSkipTrue = "Skip"; + out.settings_creationSkipFalse = "Display"; + + out.settings_templateSkip = "Skip the template selection modal"; + out.settings_templateSkipHint = "When you create a new empty pad, if you have stored templates for this type of pad, a modal appears to ask if you want to use a template. Here you can choose to never show this modal and so to never use a template."; + out.upload_title = "File upload"; out.upload_rename = "Do you want to rename {0} before uploading it to the server?
    " + "The file extension ({1}) will be added automatically. "+ @@ -819,7 +828,7 @@ define(function () { out.creation_expireHours = "Hours"; out.creation_expireDays = "Days"; out.creation_expireMonths = "Months"; - out.creation_expire1 = "By default, a pad stored by a registered users will never be removed from the server, unless it is requested by its owner."; + out.creation_expire1 = "By default, a pad stored by a registered user will never be removed from the server, unless it is requested by its owner."; out.creation_expire2 = "If you prefer, you can set a life time to make sure the pad will be permanently deleted from the server and unavailable after the specified date."; out.creation_createTitle = "Create a pad"; out.creation_createFromTemplate = "From template"; diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index f49491ebf..2c1c38efb 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -1317,7 +1317,29 @@ define([ }); }; - UIElements.getPadCreationScreen = function (common, cb) { + UIElements.setExpirationValue = function (val, $expire) { + if (val && typeof (val) === "number") { + $expire.find('#cp-creation-expire-true').attr('checked', true); + if (val % (3600 * 24 * 30) === 0) { + $expire.find('#cp-creation-expire-unit').val("month"); + $expire.find('#cp-creation-expire-val').val(val / (3600 * 24 * 30)); + return; + } + if (val % (3600 * 24) === 0) { + $expire.find('#cp-creation-expire-unit').val("day"); + $expire.find('#cp-creation-expire-val').val(val / (3600 * 24)); + return; + } + if (val % 3600 === 0) { + $expire.find('#cp-creation-expire-unit').val("hour"); + $expire.find('#cp-creation-expire-val').val(val / 3600); + return; + } + // if we're here, it means we don't have a valid value so we should check unlimited + $expire.find('#cp-creation-expire-false').attr('checked', true); + } + }; + UIElements.getPadCreationScreen = function (common, cfg, cb) { if (!common.isLoggedIn()) { return void cb(); } var sframeChan = common.getSframeChannel(); var metadataMgr = common.getMetadataMgr(); @@ -1372,6 +1394,11 @@ define([ ]); $creation.append(owned); + // If set to "open pad" or not set, check "open pad" + if (!cfg.owned && typeof cfg.owned !== "undefined") { + $creation.find('#cp-creation-owned-false').attr('checked', true); + } + // Life time var expire = h('div.cp-creation-expire', [ h('h2', [ @@ -1413,6 +1440,8 @@ define([ ]); $creation.append(expire); + UIElements.setExpirationValue(cfg.expire, $creation); + // Create the pad var create = function (template) { // Type of pad @@ -1430,7 +1459,7 @@ define([ expireVal = ($('#cp-creation-expire-val').val() || 0) * unit; } - sframeChan.query("Q_CREATE_PAD", { + common.createPad({ owned: ownedVal, expire: expireVal, template: template diff --git a/www/common/sframe-app-framework.js b/www/common/sframe-app-framework.js index 04f924c14..b5fb42466 100644 --- a/www/common/sframe-app-framework.js +++ b/www/common/sframe-app-framework.js @@ -300,7 +300,9 @@ define([ } } - if (newPad && !AppConfig.displayCreationScreen) { + var skipTemp = Util.find(privateDat, ['settings', 'general', 'creation', 'noTemplate']); + var skipCreation = Util.find(privateDat, ['settings', 'general', 'creation', 'skip']); + if (newPad && (!skipTemp && skipCreation)) { common.openTemplatePicker(); } }; @@ -402,8 +404,11 @@ define([ }).nThen(function (waitFor) { Test.registerInner(common.getSframeChannel()); if (!AppConfig.displayCreationScreen) { return; } - if (common.getMetadataMgr().getPrivateData().isNewFile) { - common.getPadCreationScreen(waitFor()); + var priv = common.getMetadataMgr().getPrivateData(); + if (priv.isNewFile) { + var c = (priv.settings.general && priv.settings.general.creation) || {}; + if (c.skip) { return void common.createPad(c, waitFor()); } + common.getPadCreationScreen(c, waitFor()); } }).nThen(function (waitFor) { cpNfInner = common.startRealtime({ diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index 634b0506a..103359da8 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -165,6 +165,14 @@ define([ }; // Store + funcs.createPad = function (cfg, cb) { + ctx.sframeChan.query("Q_CREATE_PAD", { + owned: cfg.owned, + expire: cfg.expire, + template: cfg.template + }, cb); + }; + funcs.sendAnonRpcMsg = function (msg, content, cb) { ctx.sframeChan.query('Q_ANON_RPC_MESSAGE', { msg: msg, diff --git a/www/drive/inner.js b/www/drive/inner.js index 381eb5e94..afa12fdec 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -2604,7 +2604,6 @@ define([ moveElements(pathsList, [TRASH], false, refresh); } else if ($(this).hasClass('cp-app-drive-context-deleteowned')) { - var pathsListD = []; var msgD = Messages.fm_deleteOwnedPads; UI.confirm(msgD, function(res) { $(window).focus(); @@ -2716,7 +2715,6 @@ define([ moveElements(pathsList, [TRASH], false, refresh); } else if ($(this).hasClass('cp-app-drive-context-deleteowned')) { - var pathsListD = []; var msgD = Messages.fm_deleteOwnedPads; UI.confirm(msgD, function(res) { $(window).focus(); diff --git a/www/settings/app-settings.less b/www/settings/app-settings.less index 072c37e91..b6fec0158 100644 --- a/www/settings/app-settings.less +++ b/www/settings/app-settings.less @@ -5,6 +5,7 @@ @import (once) '../../customize/src/less2/include/alertify.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"; .toolbar_main( @bg-color: @colortheme_settings-bg, @@ -14,6 +15,7 @@ .alertify_main(); .sidebar-layout_main(); .limit-bar_main(); +.creation_main(); // body &.cp-app-settings { @@ -55,7 +57,7 @@ width: @sidebar_button-width; } } - .cp-settings-backup-drive { + .cp-settings-drive-backup { button { span.fa { margin-right: 5px; @@ -63,6 +65,78 @@ margin-right: 5px; } } + .cp-settings-creation-owned, .cp-settings-creation-expire, + .cp-settings-creation-skip, .cp-settings-creation-template { + input[type="radio"] { + display: none; + &:checked { + & + label { + font-weight: bold; + background-color: lighten(@colortheme_loading-bg, 20%); + cursor: default; + border: 1px solid #c1158e; + color: @colortheme_loading-color; + &:hover { + background-color: lighten(@colortheme_loading-bg, 20%); + } + } + } + } + input[type="radio"] + label { + .tools_unselectable(); + display: inline-flex; + align-items: center; + justify-content: center; + width: 200px; + height: 50px; + padding: 5px; + margin: 0 20px; + border: 1px solid black; + cursor: pointer; + &:hover { + background-color: lighten(@colortheme_loading-bg, 10%); + } + } + .fa { + display: none; + margin-left: 50px; + } + } + .cp-settings-creation-skipped { + display: none !important; // we have to override an inline style attribute + } + .cp-settings-creation-expire { + #cp-creation-expire-true { + display: none; + &:checked { + & + label { + height: 100px; + .cp-creation-expire-picker { + display: inline; + } + } + } + } + label[for="cp-creation-expire-true"] { + flex-wrap: wrap; + .cp-creation-expire-picker { + display: none; + } + input { + width: 70px; + } + select { + width: 100px; + } + input, select { + border: none; + height: 30px; + background: @colortheme_loading-bg; + color: @colortheme_loading-color; + border-radius: 3px; + } + } + } } } } diff --git a/www/settings/inner.js b/www/settings/inner.js index f2c4fb483..22d4b4be5 100644 --- a/www/settings/inner.js +++ b/www/settings/inner.js @@ -4,9 +4,11 @@ define([ '/bower_components/nthen/index.js', '/common/sframe-common.js', '/common/common-interface.js', + '/common/common-ui-elements.js', '/common/common-util.js', '/common/common-hash.js', '/customize/messages.js', + '/common/hyperscript.js', '/bower_components/file-saver/FileSaver.min.js', 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', @@ -18,9 +20,11 @@ define([ nThen, SFCommon, UI, + UIElements, Util, Hash, - Messages + Messages, + h ) { var saveAs = window.saveAs; @@ -41,21 +45,31 @@ define([ 'cp-settings-thumbnails', 'cp-settings-userfeedback' ], + 'creation': [ + 'cp-settings-creation-owned', + 'cp-settings-creation-expire', + 'cp-settings-creation-skip', + 'cp-settings-creation-template' + ], 'drive': [ - 'cp-settings-backup-drive', - 'cp-settings-import-local-pads', - 'cp-settings-reset-drive' + 'cp-settings-drive-backup', + 'cp-settings-drive-import-local', + 'cp-settings-drive-reset' ], 'pad': [ 'cp-settings-pad-width', ], 'code': [ - 'cp-settings-indent-unit', - 'cp-settings-indent-type' + 'cp-settings-code-indent-unit', + 'cp-settings-code-indent-type' ] }; - var createInfoBlock = function () { + var create = {}; + + // Account settings + + create['info-block'] = function () { var $div = $('
    ', {'class': 'cp-settings-info-block'}); var $account = $('
    ', {'class': 'cp-sidebarlayout-element'}).appendTo($div); @@ -81,7 +95,7 @@ define([ }; // Create the block containing the display name field - var createDisplayNameInput = function () { + create['displayname'] = function () { var $div = $('
    ', {'class': 'cp-settings-displayname cp-sidebarlayout-element'}); $('