From 7970f5026bac74817cd6b1f2246e716ae9045d83 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 14 May 2020 18:53:14 -0400 Subject: [PATCH 01/66] add support for displaying languages that administrators understand on the support panel --- customize.dist/application_config.js | 2 ++ www/support/inner.js | 29 +++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/customize.dist/application_config.js b/customize.dist/application_config.js index a7ad90f11..0187cf74b 100644 --- a/customize.dist/application_config.js +++ b/customize.dist/application_config.js @@ -9,5 +9,7 @@ define(['/common/application_config_internal.js'], function (AppConfig) { // Example: If you want to remove the survey link in the menu: // AppConfig.surveyURL = ""; + AppConfig.supportLanguages = [ 'en', 'fr' ]; // XXX + return AppConfig; }); diff --git a/www/support/inner.js b/www/support/inner.js index 701d01817..48bb1c4ef 100644 --- a/www/support/inner.js +++ b/www/support/inner.js @@ -11,6 +11,7 @@ define([ '/common/hyperscript.js', '/support/ui.js', '/api/config', + '/customize/application_config.js', 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', @@ -27,7 +28,8 @@ define([ Messages, h, Support, - ApiConfig + ApiConfig, + AppConfig ) { var APP = window.APP = {}; @@ -41,6 +43,7 @@ define([ 'cp-support-list', ], 'new': [ + 'cp-support-language', 'cp-support-form', ], }; @@ -132,6 +135,30 @@ define([ return $div; }; + create['language'] = function () { + if (!Array.isArray(AppConfig.supportLanguages)) { return $(h('div')); } + var languages = AppConfig.supportLanguages; + + var list = h('li', languages + .map(function (lang) { + return Messages._languages[lang]; + }) + .filter(Boolean) + .map(function (lang) { + return h('li', lang); + }) + ); + + var preamble = "This server's administrators speak the following languages:"; // XXX + var $div = $( + h('div.cp-support-language', [ + preamble, + list, + ]) + ); + return $div; + }; + // Create a new tickets create['form'] = function () { var key = 'form'; From 704557fb2e75e50a5d1da3b7120b05349b29e6a0 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 3 Jun 2020 13:29:38 -0400 Subject: [PATCH 02/66] prototype info menu --- www/common/common-ui-elements.js | 114 +++++++++++++++++++++++-------- 1 file changed, 85 insertions(+), 29 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 0caa39c92..9b15659d6 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -2255,6 +2255,80 @@ define([ return $container; }; + UIElements.displayInfoMenu = function (Common, metadataMgr) { + var padType = metadataMgr.getMetadata().type; + var priv = metadataMgr.getPrivateData(); + var origin = priv.origin; + + Messages.help_faq = "Review our list of frequently asked questions"; // XXX + var faqLine = h('p', + h('a', { + target: '_blank', + rel: 'noreferrer noopener', + href: origin + '/faq.html', + }, Messages.help_faq) + ); + + var supportLine; + if (padType === 'support' || !Config.supportMailbox) { + // do nothing + } else if (priv.accountName) { + // registered users can submit support tickets + Messages.help_support = "Submit a support ticket"; // XXX + supportLine = h('p', [ + h('a', { + target: '_blank', + rel: 'noreferrer noopener', + href: origin + '/support/', + }, Messages.help_support) + ]); + } else { + // register to submit support tickets + Messages.help_supportRegisteredOnly = "Registered users can submit support tickets"; // XXX + var login = h('button', Messages.login_login); + $(login).click(function () { + Common.setLoginRedirect(function () { + Common.gotoURL('/login/'); + }); + }); + var register = h('button', Messages.login_register); + $(register).click(function () { + Common.setLoginRedirect(function () { + Common.gotoURL('/register/'); + }); + }); + supportLine = h('span', [ + Messages.help_supportRegisteredOnly, + h('div', [ + login, + register, + ]) + ]); + } + + var content = h('div', [ + // CryptPad version number + h('h6', Pages.versionString), + // First point users to our FAQ + faqLine, + // Link to the support ticket form in case their + // question isn't answered by the FAQ + supportLine, + ]); + + var buttons = [ + { + className: 'primary', + name: Messages.filePicker_close, + onClick: function () {}, + keys: [27], + }, + ]; + + var modal = UI.dialog.customModal(content, {buttons: buttons }); + UI.openCustomModal(modal); + }; + UIElements.createUserAdminMenu = function (Common, config) { var metadataMgr = Common.getMetadataMgr(); @@ -2366,7 +2440,6 @@ define([ }, }); } - options.push({ tag: 'hr' }); // Add administration panel link if the user is an admin if (priv.edPublic && Array.isArray(Config.adminKeys) && Config.adminKeys.indexOf(priv.edPublic) !== -1) { options.push({ @@ -2382,20 +2455,6 @@ define([ }, }); } - if (padType !== 'support' && accountName && Config.supportMailbox) { - options.push({ - tag: 'a', - attributes: {'class': 'cp-toolbar-menu-support fa fa-life-ring'}, - content: h('span', Messages.supportPage || 'Support'), - action: function () { - if (padType) { - window.open(origin+'/support/'); - } else { - window.parent.location = origin+'/support/'; - } - }, - }); - } options.push({ tag: 'hr' }); if (Config.allowSubscriptions) { options.push({ @@ -2435,20 +2494,17 @@ define([ }, }); } - if (Pages.versionString) { - Messages.user_about = Messages.about; // XXX "About CryptPad" - options.push({ - tag: 'a', - attributes: { - 'class': 'cp-toolbar-about fa fa-info', - }, - content: h('span', Messages.user_about), - action: function () { - // XXX UIElements.createHelpButton - UI.alert(Pages.versionString); - }, - }); - } + Messages.user_about = 'About CryptPad'; // XXX + options.push({ + tag: 'a', + attributes: { + 'class': 'cp-toolbar-about fa fa-info', + }, + content: h('span', Messages.user_about), + action: function () { + UIElements.displayInfoMenu(Common, metadataMgr); + }, + }); options.push({ tag: 'hr' }); // Add login or logout button depending on the current status From 26f861f3be1a2953713ce7e3db38d497135cdfce Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 4 Jun 2020 12:17:21 +0200 Subject: [PATCH 03/66] Add Turkish translation --- www/common/translations/messages.tr.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 www/common/translations/messages.tr.json diff --git a/www/common/translations/messages.tr.json b/www/common/translations/messages.tr.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/www/common/translations/messages.tr.json @@ -0,0 +1 @@ +{} From a62ea391223e5d1b5e347899a0632b0b082c884c Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 5 Jun 2020 13:49:18 +0200 Subject: [PATCH 04/66] Fix colors and reload bugs in slides --- www/common/sframe-common-outer.js | 6 ++++++ www/slide/inner.js | 34 +++++++++++++++---------------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 4c240a2ec..b5baf6301 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -1115,7 +1115,13 @@ define([ if (parsed.hashData) { currentPad.hash = parsed.hashData.getHash(opts); } // Rendered (maybe hidden) hash var hiddenParsed = Utils.Hash.parsePadUrl(window.location.href); + + // Update the hash in the address bar + var ohc = window.onhashchange; + window.onhashchange = function () {}; window.location.href = hiddenParsed.getUrl(opts); + window.onhashchange = ohc; + ohc({reset: true}); }); diff --git a/www/slide/inner.js b/www/slide/inner.js index b051724e2..71f25f4e7 100644 --- a/www/slide/inner.js +++ b/www/slide/inner.js @@ -348,7 +348,7 @@ define([ } if (back) { backColor = back; - //$modal.css('background-color', back); + $modal.find('.cp-app-slide-frame').css('background-color', back); $('#' + SLIDE_BACKCOLOR_ID).find('i').css('color', back); slideOptions.bgColor = back; } @@ -362,6 +362,10 @@ define([ framework.localChange(); }; + var $check = $("#cp-app-slide-colorpicker"); + var $backgroundPicker = $('', { type: 'color', value: backColor }) + .css({ display: 'none', }) + .on('change', function() { updateLocalColors(undefined, this.value); }); var $back = framework._.sfCommon.createButton(null, true, { icon: 'fa-square', text: Messages.slide_backCol, @@ -369,7 +373,14 @@ define([ hiddenReadOnly: true, name: 'background', id: SLIDE_BACKCOLOR_ID + }, function () { + $backgroundPicker.val(backColor); + $backgroundPicker.click(); }); + + var $foregroundPicker = $('', { type: 'color', value: textColor }) + .css({ display: 'none', }) + .on('change', function() { updateLocalColors(this.value, undefined); }); var $text = framework._.sfCommon.createButton(null, true, { icon: 'fa-i-cursor', text: Messages.slide_textCol, @@ -377,28 +388,15 @@ define([ hiddenReadOnly: true, name: 'color', id: SLIDE_COLOR_ID + }, function () { + $foregroundPicker.val(textColor); + $foregroundPicker.click(); }); var $testColor = $('', { type: 'color', value: '!' }); - var $check = $("#cp-app-slide-colorpicker"); if ($testColor.attr('type') !== "color" || $testColor.val() === '!') { return; } - var $backgroundPicker = $('', { type: 'color', value: backColor }) - .css({ display: 'none', }) - .on('change', function() { updateLocalColors(undefined, this.value); }); $check.append($backgroundPicker); - $back.on('click', function() { - $backgroundPicker.val(backColor); - $backgroundPicker.click(); - }); - - var $foregroundPicker = $('', { type: 'color', value: textColor }) - .css({ display: 'none', }) - .on('change', function() { updateLocalColors(this.value, undefined); }); $check.append($foregroundPicker); - $text.on('click', function() { - $foregroundPicker.val(textColor); - $foregroundPicker.click(); - }); framework._.toolbar.$theme.append($text).append($back); @@ -524,6 +522,8 @@ define([ if (newPad) { colors.updateLocalColors('#000', '#FFF'); + } else { + colors.updateLocalColors('#FFF', '#000'); } CodeMirror.setMode('markdown', function () { }); From 5d111c623755dca34251a8794dd11abf959ab719 Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 5 Jun 2020 15:14:26 +0200 Subject: [PATCH 05/66] Update tags for multiple pads at once --- www/common/common-ui-elements.js | 63 ++++++++++++++++++++++++++------ www/common/drive-ui.js | 13 +++---- 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 278e8dda8..70b0d25ed 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -46,28 +46,69 @@ define([ return mB + Messages.MB; }; - UIElements.updateTags = function (common, href) { + UIElements.updateTags = function (common, hrefs) { var existing, tags; + var allTags = {}; + if (!hrefs || typeof (hrefs) === "string") { + hrefs = [hrefs]; + } NThen(function(waitFor) { common.getSframeChannel().query("Q_GET_ALL_TAGS", null, waitFor(function(err, res) { if (err || res.error) { return void console.error(err || res.error); } existing = Object.keys(res.tags).sort(); })); }).nThen(function (waitFor) { - common.getPadAttribute('tags', waitFor(function (err, res) { - if (err) { - if (err === 'NO_ENTRY') { - UI.alert(Messages.tags_noentry); + var _err; + hrefs.forEach(function (href) { + common.getPadAttribute('tags', waitFor(function (err, res) { + if (err) { + if (err === 'NO_ENTRY') { + UI.alert(Messages.tags_noentry); + } + waitFor.abort(); + _err = err; + return void console.error(err); } - waitFor.abort(); - return void console.error(err); - } - tags = res || []; - }), href); + allTags[href] = res || []; + + if (tags) { + // Intersect with tags from previous pads + tags = (res || []).filter(function (tag) { + return tags.indexOf(tag) !== -1; + }); + } else { + tags = res || []; + } + }), href); + }); }).nThen(function () { UI.dialog.tagPrompt(tags, existing, function (newTags) { if (!Array.isArray(newTags)) { return; } - common.setPadAttribute('tags', newTags, null, href); + var added = []; + var removed = []; + newTags.forEach(function (tag) { + if (tags.indexOf(tag) === -1) { + added.push(tag); + } + }); + tags.forEach(function (tag) { + if (newTags.indexOf(tag) === -1) { + removed.push(tag); + } + }); + var update = function (oldTags) { + Array.prototype.push.apply(oldTags, added); + removed.forEach(function (tag) { + var idx = oldTags.indexOf(tag); + oldTags.splice(idx, 1); + }); + }; + + hrefs.forEach(function (href) { + var oldTags = allTags[href] || []; + update(oldTags); + common.setPadAttribute('tags', Util.deduplicateString(oldTags), null, href); + }); }); }); }; diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index a92e383d1..413b2624f 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -1294,7 +1294,6 @@ define([ hide.push('properties', 'access'); hide.push('rename'); hide.push('openparent'); - hide.push('hashtag'); hide.push('download'); hide.push('share'); hide.push('savelocal'); @@ -4370,12 +4369,12 @@ define([ }); } else if ($this.hasClass("cp-app-drive-context-hashtag")) { - if (paths.length !== 1) { return; } - el = manager.find(paths[0].path); - data = manager.getFileData(el); - if (!data) { return void console.error("Expected to find a file"); } - var href = data.href || data.roHref; - common.updateTags(href); + var hrefs = paths.map(function (p) { + var el = manager.find(p.path); + var data = manager.getFileData(el); + return data.href || data.roHref; + }).filter(Boolean); + common.updateTags(hrefs); } else if ($this.hasClass("cp-app-drive-context-empty")) { if (paths.length !== 1 || !paths[0].element From c8f7c96cfc1527386d54a9dd1d2caf513edfc7da Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 5 Jun 2020 13:25:22 -0400 Subject: [PATCH 06/66] preserve formatting when displaying multi-line team invite messages --- www/teams/app-team.less | 1 + 1 file changed, 1 insertion(+) diff --git a/www/teams/app-team.less b/www/teams/app-team.less index eb49ec21f..c59d0dcb9 100644 --- a/www/teams/app-team.less +++ b/www/teams/app-team.less @@ -220,6 +220,7 @@ width: 100%; padding: 12px; margin-bottom: 20px; + white-space: pre; } .cp-teams-invite-password { margin-bottom: 20px; From 154a0b1e6e8ff0c6d4e82745df368a3f212815e8 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 5 Jun 2020 13:32:56 -0400 Subject: [PATCH 07/66] hide the drive's contextmenu when you hit escape --- www/common/drive-ui.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index 413b2624f..8c8d7f5f1 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -526,6 +526,8 @@ define([ } }); }); + + return $(menu); }; @@ -919,6 +921,11 @@ define([ if (e.ctrlKey) { ev.ctrlKey = true; } if (e.shiftKey) { ev.shiftKey = true; } + // ESC + if (e.which === 27) { + return void APP.hideMenu(); + } + // Enter if (e.which === 13) { var $allSelected = $content.find('.cp-app-drive-element.cp-app-drive-element-selected'); From b419ead7fefdb2891f99dc915be19f3220041457 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 5 Jun 2020 14:25:24 -0400 Subject: [PATCH 08/66] implement more intuitive keyboard controls for the tag prompt --- www/common/common-interface.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 79951c3c5..6ddf0a320 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -377,6 +377,14 @@ define([ field.focus(); }); + var $field = field.tokenfield.closest('.tokenfield').find('.token-input'); + $field.on('keypress', function (e) { + if (!$field.val() && e.which === 13) { return void $ok.click(); } + }); + $field.on('keydown', function (e) { + if (!$field.val() && e.which === 27) { return void $cancel.click(); } + }); + return tagger; }; From 1ef79d44b4312f76148ec29d3e31b4b4e75f3d35 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 8 Jun 2020 11:47:09 -0400 Subject: [PATCH 09/66] display a disabled upload button to logged out users in the filepicker modal --- www/secureiframe/inner.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/www/secureiframe/inner.js b/www/secureiframe/inner.js index a42cd5e7a..1aa94d9cd 100644 --- a/www/secureiframe/inner.js +++ b/www/secureiframe/inner.js @@ -177,7 +177,7 @@ define([ }); // If file, display the upload button - if (types.indexOf('file') !== -1 && common.isLoggedIn()) { + if (types.indexOf('file') !== -1) { var f = (filters && filters.filter) || {}; delete data.accept; if (Array.isArray(f.fileType)) { @@ -188,7 +188,13 @@ define([ return val; }); } - $filter.append(common.createButton('upload', false, data)); + } + + var $uploadButton = common.createButton('upload', false, data); + $filter.append($uploadButton); + if (!common.isLoggedIn()) { + $uploadButton.prop('disabled', true) + .prop('title', Messages.upload_mustLogin); } var $container = $(h('span.cp-filepicker-content', [ From ce5bcc0022bc840fecb6e33d0b9c5275725f68cd Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 8 Jun 2020 11:57:05 -0400 Subject: [PATCH 10/66] add an XXX for the upload button's tooltip --- www/common/common-ui-elements.js | 1 + 1 file changed, 1 insertion(+) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 70b0d25ed..3a032b36f 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -1364,6 +1364,7 @@ define([ case 'import': button = $('