From 8bdccbdcb0b3d04bd6a891b3ac1a75a284baa772 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 19 Mar 2021 16:34:20 +0530 Subject: [PATCH 01/76] hide kanban controls --- www/kanban/inner.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/www/kanban/inner.js b/www/kanban/inner.js index 3428bd12b..383d64836 100644 --- a/www/kanban/inner.js +++ b/www/kanban/inner.js @@ -1003,6 +1003,14 @@ define([ ]); $container.before(container); + var common = framework._.sfCommon; + var $button = common.createButton('toggle', true, { + element: $(container), + }, function () { + + }); + framework._.toolbar.$bottomL.append($button); + onRedraw.reg(function () { // Redraw if new tags have been added to items var old = Sortify(existing); From c774a5d06e755d1113ff2ee70cc4b276fc91dc9c Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 12 Jul 2021 13:24:32 +0530 Subject: [PATCH 02/76] time out if checkup test #7 doesn't call back in 30s --- www/checkup/main.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/www/checkup/main.js b/www/checkup/main.js index f4a40d11e..a8a69d737 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -255,6 +255,11 @@ define([ ])); })); + // time out after 30 seconds + setTimeout(function () { + cb('TIMEOUT'); + }, 30000); + var bytes = new Uint8Array(Login.requiredBytes); var opt = Login.allocateBytes(bytes); @@ -727,8 +732,6 @@ define([ '. ', RESTART_WARNING(), ])); - - console.error("HTTPS?", trimmedUnsafe, trimmedSafe); cb(isHTTPS(trimmedUnsafe) && isHTTPS(trimmedSafe)); }); From a4092e888b76a7d6d172f2ad312922e49cd5d4e4 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 19 Jul 2021 19:14:47 +0530 Subject: [PATCH 03/76] remove unused images --- customize.dist/images/YannFlory.jpg | Bin 33940 -> 0 bytes customize.dist/images/logo_white.png | Bin 9730 -> 0 bytes customize.dist/images/logo_white.svg | 1 - .../old_logos/CryptPad-white-logo.svg | 1 - .../old_logos/CryptPad_logo_color.svg | 1 - customize.dist/old_logos/CryptPadlogo_op5.svg | 1 - customize.dist/old_logos/cryptofist_mini.png | Bin 36726 -> 0 bytes customize.dist/old_logos/cryptofist_small.png | Bin 91507 -> 0 bytes .../cryptpad-new-logo-colors-logoonly.png | Bin 10031 -> 0 bytes 9 files changed, 4 deletions(-) delete mode 100644 customize.dist/images/YannFlory.jpg delete mode 100644 customize.dist/images/logo_white.png delete mode 100644 customize.dist/images/logo_white.svg delete mode 100644 customize.dist/old_logos/CryptPad-white-logo.svg delete mode 100644 customize.dist/old_logos/CryptPad_logo_color.svg delete mode 100644 customize.dist/old_logos/CryptPadlogo_op5.svg delete mode 100644 customize.dist/old_logos/cryptofist_mini.png delete mode 100644 customize.dist/old_logos/cryptofist_small.png delete mode 100644 customize.dist/old_logos/cryptpad-new-logo-colors-logoonly.png diff --git a/customize.dist/images/YannFlory.jpg b/customize.dist/images/YannFlory.jpg deleted file mode 100644 index 9c358d1a622777fbcd79b5b1aea46e962e501fbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33940 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 \ No newline at end of file diff --git a/customize.dist/old_logos/CryptPad-white-logo.svg b/customize.dist/old_logos/CryptPad-white-logo.svg deleted file mode 100644 index 26131b502..000000000 --- a/customize.dist/old_logos/CryptPad-white-logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/customize.dist/old_logos/CryptPad_logo_color.svg b/customize.dist/old_logos/CryptPad_logo_color.svg deleted file mode 100644 index 64fc86682..000000000 --- a/customize.dist/old_logos/CryptPad_logo_color.svg +++ /dev/null @@ -1 +0,0 @@ -CryptPad_logo_color \ No newline at end of file diff --git a/customize.dist/old_logos/CryptPadlogo_op5.svg b/customize.dist/old_logos/CryptPadlogo_op5.svg deleted file mode 100644 index aa5acb201..000000000 --- a/customize.dist/old_logos/CryptPadlogo_op5.svg +++ /dev/null @@ -1 +0,0 @@ -CryptPadlogo \ No newline at end of file diff --git a/customize.dist/old_logos/cryptofist_mini.png b/customize.dist/old_logos/cryptofist_mini.png deleted file mode 100644 index 73845e455cc3684150091ff4612659019b3625ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36726 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.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

YB7keL3{gO`k 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

_HrCcCYX)s#3*K6W`0eXPXCRp42W+6*3w%LcS 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 From 621941b9337f37f83c31c030979115320cf19426 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 19 Jul 2021 19:49:20 +0530 Subject: [PATCH 04/76] comments about possible form improvements --- www/form/inner.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/www/form/inner.js b/www/form/inner.js index f8dfe5ab8..9f05f80dd 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -721,7 +721,7 @@ define([ var answer = answerObj.results; if (!answer || !answer.values) { return; } var values = answer.values || {}; - var res = Number(values[data]) || 0; + var res = Number(values[data]) || 0; // XXX inc function ? if (res === 1) { y++; } else if (res === 2) { m++; } }); @@ -768,7 +768,7 @@ define([ }; refreshBest(); - if (myLine && evOnChange) { + if (myLine && evOnChange) { // XXX var updateValues = function () { totalEls.forEach(function (cell) { var $c = $(cell); @@ -776,7 +776,7 @@ define([ if (!data) { return; } var y = totals[data].y + ((myTotals[data] || {}).y || 0); var m = totals[data].m + ((myTotals[data] || {}).m || 0); - $c.find('.cp-form-total-yes').text(y); + $c.find('.cp-form-total-yes').text(y); // XXX inc function $c.find('.cp-form-total-maybe').text('('+m+')'); }); }; @@ -977,7 +977,7 @@ define([ printResults: function (answers, uid) { var results = []; var empty = 0; - Object.keys(answers).forEach(function (author) { + Object.keys(answers).forEach(function (author) { // XXX deduplicate these? var obj = answers[author]; var answer = obj.msg[uid]; if (!answer || !answer.trim()) { return empty++; } @@ -989,7 +989,7 @@ define([ }, icon: h('i.cptools.cptools-form-text') }, - textarea: { + textarea: { // XXX defaultOpts: { maxLength: 1000 }, @@ -1043,7 +1043,7 @@ define([ printResults: function (answers, uid) { var results = []; var empty = 0; - Object.keys(answers).forEach(function (author) { + Object.keys(answers).forEach(function (author) { // XXX deduplicate these var obj = answers[author]; var answer = obj.msg[uid]; if (!answer || !answer.trim()) { return empty++; } @@ -1117,7 +1117,7 @@ define([ var obj = answers[author]; var answer = obj.msg[uid]; if (!answer || !answer.trim()) { return empty++; } - count[answer] = count[answer] || 0; + count[answer] = count[answer] || 0; // XXX inc function count[answer]++; }); Object.keys(count).forEach(function (value) { @@ -1220,7 +1220,7 @@ define([ var c = count[q_uid] = count[q_uid] || {}; var res = answer[q_uid]; if (!res || !res.trim()) { return; } - c[res] = c[res] || 0; + c[res] = c[res] || 0; // XXX inc function c[res]++; }); }); @@ -1331,7 +1331,7 @@ define([ var answer = obj.msg[uid]; if (!Array.isArray(answer) || !answer.length) { return empty++; } answer.forEach(function (val) { - count[val] = count[val] || 0; + count[val] = count[val] || 0; // XXX inc function count[val]++; }); }); @@ -1446,7 +1446,7 @@ define([ var c = count[q_uid] = count[q_uid] || {}; var res = answer[q_uid]; if (!Array.isArray(res) || !res.length) { return; } - res.forEach(function (v) { + res.forEach(function (v) { // XXX increment function? c[v] = c[v] || 0; c[v]++; }); @@ -1586,7 +1586,7 @@ define([ if (!Array.isArray(answer) || !answer.length) { return empty++; } answer.forEach(function (el, i) { var score = l - i; - count[el] = (count[el] || 0) + score; + count[el] = (count[el] || 0) + score; // XXX inc function? }); }); var sorted = Object.keys(count).sort(function (a, b) { From 0fc2269a3a6d54e047837a720023f7a52cc16cb8 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 20 Jul 2021 10:40:40 +0200 Subject: [PATCH 05/76] Create links in the drive --- www/code/inner.js | 4 +- www/common/application_config_internal.js | 1 + www/common/common-interface.js | 2 + www/common/common-ui-elements.js | 68 ++++++++++- www/common/drive-ui.js | 140 +++++++++++++++++++++- www/common/inner/share.js | 52 ++++++-- www/common/notifications.js | 14 +++ www/common/outer/async-store.js | 9 +- www/common/outer/mailbox-handlers.js | 2 +- www/common/outer/userObject.js | 43 ++++++- www/common/proxy-manager.js | 62 +++++++++- www/common/sframe-app-framework.js | 11 +- www/common/userObject.js | 27 ++++- www/secureiframe/inner.js | 8 +- www/teams/main.js | 3 +- 15 files changed, 416 insertions(+), 30 deletions(-) diff --git a/www/code/inner.js b/www/code/inner.js index 785e82788..19ffdb285 100644 --- a/www/code/inner.js +++ b/www/code/inner.js @@ -368,8 +368,8 @@ define([ var mkFilePicker = function (framework, editor, evModeChange) { evModeChange.reg(function (mode) { if (MEDIA_TAG_MODES.indexOf(mode) !== -1) { - // Embedding is endabled - framework.setMediaTagEmbedder(function (mt) { + // Embedding is enabled + framework.setMediaTagEmbedder(function (mt, data) { editor.focus(); editor.replaceSelection($(mt)[0].outerHTML); }); diff --git a/www/common/application_config_internal.js b/www/common/application_config_internal.js index 15e5b5e34..3be979f17 100644 --- a/www/common/application_config_internal.js +++ b/www/common/application_config_internal.js @@ -119,6 +119,7 @@ define(function() { file: 'cptools-file', fileupload: 'cptools-file-upload', folderupload: 'cptools-folder-upload', + link: 'fa-link', pad: 'cptools-richtext', code: 'cptools-code', slide: 'cptools-slide', diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 4d3520426..5aea35c78 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -1050,6 +1050,7 @@ define([ var font = icon.indexOf('cptools') === 0 ? 'cptools' : 'fa'; if (type === 'fileupload') { type = 'file'; } if (type === 'folderupload') { type = 'file'; } + if (type === 'link') { type = 'drive'; } var appClass = ' cp-icon cp-icon-color-'+type; $icon = $('', {'class': font + ' ' + icon + appClass}); } @@ -1061,6 +1062,7 @@ define([ if (!data) { return $icon; } var href = data.href || data.roHref; var type = data.type; + if (data.static) { type = 'link'; } if (!href && !type) { return $icon; } if (!type) { type = Hash.parsePadUrl(href).type; } diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 0ab010cb5..6114884b2 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -1032,10 +1032,19 @@ define([ icon: 'fa-picture-o', action: function () { var _cfg = { - types: ['file'], + types: ['file', 'link'], where: ['root'] }; common.openFilePicker(_cfg, function (data) { + // Embed links + if (data.static) { + var a = h('a', { + href: data.href + }, data.name); + cfg.embed(a, data); + return; + } + // Embed files if (data.type !== 'file') { console.log("Unexpected data type picked " + data.type); return; @@ -3021,6 +3030,63 @@ define([ UI.proposal(content, todo); }; + UIElements.displayOpenLinkModal = function (common, data, dismiss) { + var name = Util.fixHTML(data.title); + var url = data.href; + var user = data.name; + Messages.notification_openLink = "You've received a link {0} from {1}:"; // XXX + Messages.link_open = "Open URL"; + Messages.link_store = "Store link in drive"; + + var content = h('div', [ + UI.setHTML(h('p'), Messages._getKey('notification_openLink', [name, user])), + h('pre', url), + UIElements.getVerifiedFriend(common, data.curve, user) + ]); + var clicked = false; + var modal; + var buttons = [{ + name: Messages.friendRequest_later, + onClick: function () { + if (clicked) { return true; } + clicked = true; + }, + keys: [27] + }, { + className: 'primary', + name: Messages.link_open, + onClick: function () { + if (clicked) { return true; } + clicked = true; + common.openUnsafeURL(url); + }, + keys: [13] + }, { + className: 'primary', + name: Messages.link_store, + onClick: function () { + if (clicked) { return; } + clicked = true; + common.getSframeChannel().query("Q_DRIVE_USEROBJECT", { + cmd: "addLink", + data: { + name: name, + href: url, + path: ['root'] + } + }, function () { + modal.closeModal(); + dismiss(); + }); + return true; + }, + keys: [[13, 'ctrl']] + }]; + var _modal = UI.dialog.customModal(content, {buttons: buttons}); + modal = UI.openCustomModal(_modal); + return modal; + }; + UIElements.displayAddOwnerModal = function (common, data) { var priv = common.getMetadataMgr().getPrivateData(); var sframeChan = common.getSframeChannel(); diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index b2489c22b..28ac531e2 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -42,6 +42,8 @@ define([ Pages) { + Messages.fm_link = "Link"; // XXX + var APP = window.APP = { editable: false, online: false, @@ -443,6 +445,11 @@ define([ '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', { + 'tabindex': '-1', + 'data-icon': AppConfig.applicationsIcon.link, + 'data-type': 'link' + }, Messages.fm_link)), ]), ]), $separator.clone()[0], @@ -1111,6 +1118,15 @@ define([ var defaultInApp = ['application/pdf']; var openFile = function (el, isRo, app) { var data = manager.getFileData(el); + + if (data.static) { + if (data.href) { + common.openUnsafeURL(data.href); + manager.updateStaticAccess(el, refresh); + } + return; + } + if (!data || (!data.href && !data.roHref)) { return void logError("Missing data for the file", el, data); } @@ -1263,6 +1279,9 @@ define([ if ($element.is('.cp-border-color-sheet')) { hide.push('download'); } + if ($element.is('.cp-app-drive-static')) { + hide.push('access', 'hashtag', 'properties', 'download'); + } if ($element.is('.cp-app-drive-element-file')) { // No folder in files hide.push('color'); @@ -1899,6 +1918,27 @@ define([ // In list mode, display metadata from the filesData object + var addStaticData = function (element, $element, data) { + $element.addClass('cp-border-color-drive'); + var name = data.name; + var $name = $('', {'class': 'cp-app-drive-element-name'}).text(name); + $element.append($name); + if (getViewMode() === 'grid') { + $element.attr('title', name); + } + + var type = Messages.fm_link; + var $type = $('', { + 'class': 'cp-app-drive-element-type cp-app-drive-element-list' + }).text(type); + var $adate = $('', { + 'class': 'cp-app-drive-element-atime cp-app-drive-element-list' + }).text(getDate(data.atime)); + var $cdate = $('', { + 'class': 'cp-app-drive-element-ctime cp-app-drive-element-list' + }).text(getDate(data.ctime)); + $element.append($type).append($adate).append($cdate); + } var _addOwnership = function ($span, $state, data) { if (data && Array.isArray(data.owners) && data.owners.indexOf(edPublic) !== -1) { var $owned = $ownedIcon.clone().appendTo($state); @@ -1914,6 +1954,9 @@ define([ if (!manager.isFile(element)) { return; } var data = manager.getFileData(element); + if (data.static) { + return addStaticData(element, $element, data); + } if (!Object.keys(data).length) { return true; @@ -2124,7 +2167,9 @@ define([ $icon = manager.isFolderEmpty(root[key]) ? $folderEmptyIcon.clone() : $folderIcon.clone(); $icon.css("color", getFolderColor(path.concat(elPath))); } - var classes = restrictedClass + roClass + liClass; + + var staticClass = manager.isStaticFile(element) ? '.cp-app-drive-static' : ''; + var classes = restrictedClass + roClass + liClass + staticClass; var $element = $(h('li.cp-app-drive-element.cp-app-drive-element-row' + classes, { draggable: true })); @@ -2460,7 +2505,6 @@ define([ showMode(viewMode); $button.click(function (e) { - console.error(e); var viewMode = getViewMode(); var newViewMode = getOppositeViewMode(viewMode); setViewMode(newViewMode); @@ -2686,6 +2730,63 @@ define([ }); $input.click(); }; + var showLinkModal = function () { + Messages.fm_link_name = "Link name"; // XXX + Messages.fm_link_url = "URL"; + Messages.fm_link_warning = "Warning: URL size..."; + var name, url; + var warning = h('div.alert.alert-warning', [ + h('i.fa.fa-exclamation-triangle'), + h('span', Messages.fm_link_warning) + ]); + var content = h('p', [ + warning, + h('label', {for: 'cp-app-drive-link-name'}, Messages.fm_link_name), + name = h('input#cp-app-drive-link-name', { autocomplete: 'off' }), + h('label', {for: 'cp-app-drive-link-url'}, Messages.fm_link_url), + url = h('input#cp-app-drive-link-url', { type: 'url', autocomplete: 'off' }) + ]); + var $warning = $(warning).hide(); + var $url = $(url).on('change keypress keyup keydown', function () { + var v = $url.val().trim(); + if (v.length > 200) { + $warning.show(); + return; + } + $warning.hide(); + }); + var buttons = [{ + className: 'cancel', + name: Messages.cancelButton, + onClick: function () {}, + keys: [27] + }]; + buttons.push({ + className: 'primary', + // We may want to use a new key here + iconClass: '.fa.fa-plus', + name: Messages.tag_add, + onClick: function () { + var n = $(name).val().trim(); + var u = $url.val().trim(); + if (!n || !u) { return true; } + if (!Util.isValidURL(u)) { + // XXX add style for invalid input? input:invalid + UI.warn(Messages.error); + return true; + } + manager.addLink(currentPath, { + name: n, + url: u + }, refresh); + }, + keys: [13] + }); + var m = UI.dialog.customModal(content, { + buttons: buttons + }); + UI.openCustomModal(m); + }; var addNewPadHandlers = function ($block, isInRoot) { // Handlers if (isInRoot) { @@ -2714,6 +2815,7 @@ define([ } $block.find('a.cp-app-drive-new-fileupload, li.cp-app-drive-new-fileupload').click(showUploadFilesModal); $block.find('a.cp-app-drive-new-folderupload, li.cp-app-drive-new-folderupload').click(showUploadFolderModal); + $block.find('a.cp-app-drive-new-link, li.cp-app-drive-new-link').click(showLinkModal); } $block.find('a.cp-app-drive-new-doc, li.cp-app-drive-new-doc') .click(function () { @@ -2757,6 +2859,12 @@ define([ }); } options.push({tag: 'hr'}); + options.push({ + tag: 'a', + attributes: {'class': 'cp-app-drive-new-link'}, + content: $('

').append(getIcon('link')).html() + Messages.fm_link + }); + options.push({tag: 'hr'}); } getNewPadTypes().forEach(function (type) { var attributes = { @@ -3073,6 +3181,13 @@ define([ $elementFolderUpload.append($('', {'class': 'cp-app-drive-new-name'}) .text(Messages.uploadFolderButton)); } + // Link + var $elementFileUpload = $('
  • ', { + 'class': 'cp-app-drive-new-link cp-app-drive-element-row ' + + 'cp-app-drive-element-grid' + }).prepend(getIcon('link')).appendTo($container); + $elementFileUpload.append($('', {'class': 'cp-app-drive-new-name'}) + .text(Messages.fm_link)); } // Pads getNewPadTypes().forEach(function (type) { @@ -3479,6 +3594,7 @@ define([ var path = paths[0]; if (manager.isPathIn(path, [TRASH])) { return; } + if (!file.channel) { file.channel = id; } if (channels.indexOf(file.channel) !== -1) { return; } channels.push(file.channel); @@ -4482,8 +4598,9 @@ define([ password: data.password }, isTemplate: paths[0].path[0] === 'template', - title: data.title, + title: data.title || data.name, sharedFolder: sf, + static: data.static ? data.href : undefined, common: common }; if (padType === 'file') { @@ -4501,6 +4618,20 @@ define([ data = manager.getSharedFolderData(el); } if (!data) { return; } + if (data.static) { + sframeChan.query("Q_DRIVE_USEROBJECT", { + cmd: "addLink", + teamId: -1, + data: { + name: data.name, + href: data.href, + path: ['root'] + } + }, function () { + UI.log(Messages.saved); + }); + return; + } sframeChan.query('Q_STORE_IN_TEAM', { href: data.href || data.rohref, password: data.password, @@ -4539,6 +4670,9 @@ define([ } else if ($this.hasClass("cp-app-drive-context-newdoc")) { var ntype = $this.data('type') || 'pad'; + if (ntype === 'link') { + return void showLinkModal(); + } var path2 = manager.isPathIn(currentPath, [TRASH]) ? '' : currentPath; openIn(ntype, path2, APP.team); } diff --git a/www/common/inner/share.js b/www/common/inner/share.js index 9ba75f867..5225ea818 100644 --- a/www/common/inner/share.js +++ b/www/common/inner/share.js @@ -90,7 +90,11 @@ define([ setTimeout(w); }); if (res && /^http/.test(res)) { - href = Hash.getRelativeHref(res); + var _href = Hash.getRelativeHref(res); + if (_href) { href = _href; } + else { + href = res; + } setTimeout(w); return; } @@ -109,6 +113,7 @@ define([ if (mailbox.notifications && mailbox.curvePublic) { common.mailbox.sendTo("SHARE_PAD", { href: href, + isStatic: Boolean(config.static), password: config.password, isTemplate: config.isTemplate, name: myName, @@ -137,6 +142,20 @@ define([ }); return; } + if (config.static) { + common.getSframeChannel().query("Q_DRIVE_USEROBJECT", { + cmd: "addLink", + teamId: team.id, + data: { + name: title, + href: href, + path: ['root'] + } + }, function () { + UI.log(Messages.saved); + }); + return; + } sframeChan.query('Q_STORE_IN_TEAM', { href: href, password: config.password, @@ -346,6 +365,9 @@ define([ ] : [ UI.createCheckbox('cp-share-embed', Messages.share_linkEmbed, false, { mark: {tabindex:1} }), ]; + + if (opts.static) { linkContent = []; } + linkContent.push(h('div.cp-spacer')); linkContent.push(UI.dialog.selectableArea('', { id: 'cp-share-link-preview', tabindex: 1, rows:3})); @@ -361,7 +383,7 @@ define([ // warning about sharing links // when sharing a version hash, there is a similar warning and we want // to avoid alert fatigue - if (!opts.versionHash) { + if (!opts.versionHash && !opts.static) { var localStore = window.cryptpadStore; var dismissButton = h('span.fa.fa-times'); var shareLinkWarning = h('div.alert.alert-warning.dismissable', @@ -405,6 +427,10 @@ define([ var v = opts.getLinkValue({ embed: Util.isChecked($link.find('#cp-share-embed')) }); + if (opts.static) { + common.openUnsafeURL(v); + return true; + } window.open(v); return true; }, @@ -562,6 +588,7 @@ define([ }); }; opts.getLinkValue = function (initValue, cb) { + if (opts.static) { return opts.static; } var val = initValue || {}; var edit = val.edit !== undefined ? val.edit : Util.isChecked($rights.find('#cp-share-editable-true')); var embed = val.embed; @@ -686,7 +713,7 @@ define([ opts.access = true; // Allow the use of the modal even if the pad is not stored var hashes = opts.hashes; - if (!hashes || (!hashes.editHash && !hashes.viewHash)) { return; } + if (!hashes || (!hashes.editHash && !hashes.viewHash && !opts.static)) { return; } var teams = getEditableTeams(common, opts); opts.teams = teams; @@ -705,19 +732,23 @@ define([ var $rights = opts.$rights = getRightsHeader(common, opts); var resetTab = function () { + if (opts.static) { return; } $rights.show(); $rights.find('label.cp-radio').show(); }; var onShowEmbed = function () { + if (opts.static) { return; } $rights.find('#cp-share-bar').closest('label').hide(); $rights.find('input[type="radio"]:enabled').first().prop('checked', 'checked'); $rights.find('input[type="radio"]').trigger('change'); }; var onShowContacts = function () { + if (opts.static) { return; } if (!hasFriends || priv.offline) { $rights.hide(); } }; + if (opts.static) { $rights.hide(); } var contactsActive = hasFriends && !priv.offline; var tabs = [{ @@ -732,13 +763,16 @@ define([ title: Messages.share_linkCategory, icon: "fa fa-link", active: !contactsActive, - }, { - getTab: getEmbedTab, - title: Messages.share_embedCategory, - icon: "fa fa-code", - onShow: onShowEmbed, - onHide: resetTab }]; + if (!opts.static) { + tabs.push({ + getTab: getEmbedTab, + title: Messages.share_embedCategory, + icon: "fa fa-code", + onShow: onShowEmbed, + onHide: resetTab + }); + } Modal.getModal(common, opts, tabs, function (err, modal) { // Hide the burn-after-reading option by default var $modal = $(modal); diff --git a/www/common/notifications.js b/www/common/notifications.js index 20738e237..24458420e 100644 --- a/www/common/notifications.js +++ b/www/common/notifications.js @@ -92,6 +92,11 @@ define([ (type === 'file' ? 'notification_fileShared' : // Msg.notification_fileSharedTeam 'notification_padShared'); // Msg.notification_padSharedTeam + Messages.notification_linkShared = "{0} has shared a link with you: {1}"; // XXX + if (msg.content.isStatic) { + key = 'notification_linkShared'; // Msg.notification_linkShared; + } + var teamNotification = /^team-/.test(data.type) && Number(data.type.slice(5)); var teamName = ''; if (teamNotification) { @@ -109,6 +114,15 @@ define([ return Messages._getKey(key, [name, title, teamName]); }; content.handler = function() { + if (msg.content.isStatic) { + UIElements.displayOpenLinkModal(common, { + curve: msg.author, + href: msg.content.href, + name: name, + title: title + }, defaultDismiss(common, data)); + return; + } var obj = { p: msg.content.isTemplate ? ['template'] : undefined, t: teamNotification || undefined, diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 9f779a0a8..6aacd4a1b 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -1306,9 +1306,14 @@ define([ getAllStores().forEach(function (s) { s.manager.getSecureFilesList(where).forEach(function (obj) { var data = obj.data; - if (channels.indexOf(data.channel) !== -1) { return; } + if (channels.indexOf(data.channel || data.id) !== -1) { return; } var id = obj.id; - if (data.channel) { channels.push(data.channel); } + if (data.channel) { channels.push(data.channel || data.id); } + // Only include static links if "link" is requested + if (data.static) { + if (types.indexOf('link') !== -1) { list[id] = data; } + return; + } var parsed = Hash.parsePadUrl(data.href || data.roHref); if ((!types || types.length === 0 || types.indexOf(parsed.type) !== -1) && !isFiltered(parsed.type, data)) { diff --git a/www/common/outer/mailbox-handlers.js b/www/common/outer/mailbox-handlers.js index 7f7e20d2a..bb19d2d91 100644 --- a/www/common/outer/mailbox-handlers.js +++ b/www/common/outer/mailbox-handlers.js @@ -239,7 +239,7 @@ define([ if (isMuted(ctx, data)) { return void cb(true); } - var channel = Hash.hrefToHexChannelId(content.href, content.password); + var channel = content.isStatic ? content.href : Hash.hrefToHexChannelId(content.href, content.password); var parsed = Hash.parsePadUrl(content.href); var mode = parsed.hashData && parsed.hashData.mode || 'n/a'; diff --git a/www/common/outer/userObject.js b/www/common/outer/userObject.js index e7c55da67..a12beacf9 100644 --- a/www/common/outer/userObject.js +++ b/www/common/outer/userObject.js @@ -20,6 +20,7 @@ define([ var ROOT = exp.ROOT; var FILES_DATA = exp.FILES_DATA; + var STATIC_DATA = exp.STATIC_DATA; var OLD_FILES_DATA = exp.OLD_FILES_DATA; var UNSORTED = exp.UNSORTED; var TRASH = exp.TRASH; @@ -78,6 +79,14 @@ define([ files[FILES_DATA][id] = data; cb(null, id); }; + exp.pushLink = function (_data, cb) { + if (typeof cb !== "function") { cb = function () {}; } + if (readOnly) { return void cb('EFORBIDDEN'); } + var id = Util.createRandomInteger(); + var data = clone(_data); + files[STATIC_DATA][id] = data; + cb(null, id); + }; exp.pushSharedFolder = function (_data, cb) { if (typeof cb !== "function") { cb = function () {}; } @@ -136,7 +145,7 @@ define([ var filesList = exp.getFiles([ROOT, 'hrefArray', TRASH]); var toClean = []; - exp.getFiles([FILES_DATA, SHARED_FOLDERS]).forEach(function (id) { + exp.getFiles([FILES_DATA, SHARED_FOLDERS, STATIC_DATA]).forEach(function (id) { if (filesList.indexOf(id) === -1) { var fd = exp.isSharedFolder(id) ? files[SHARED_FOLDERS][id] : exp.getFileData(id); var channelId = fd.channel; @@ -146,6 +155,8 @@ define([ if (exp.isSharedFolder(id)) { delete files[SHARED_FOLDERS][id]; if (config.removeProxy) { config.removeProxy(id); } + } else if (files[STATIC_DATA][id]) { + delete files[STATIC_DATA][id]; } else { spliceFileData(id); } @@ -398,7 +409,7 @@ define([ if (!loggedIn && !config.testMode) { return; } id = Number(id); - var data = files[FILES_DATA][id] || files[SHARED_FOLDERS][id]; + var data = files[FILES_DATA][id] || files[STATIC_DATA][id] || files[SHARED_FOLDERS][id]; if (!data || typeof(data) !== "object") { return; } var newPath = path, parentEl; if (path && !Array.isArray(path)) { @@ -634,7 +645,7 @@ define([ delete element[el]; } if (typeof element[el] === "number") { - var data = files[FILES_DATA][element[el]]; + var data = files[FILES_DATA][element[el]] || files[STATIC_DATA][element[el]]; if (!data) { debug("An element in ROOT doesn't have associated data", element[el], el); delete element[el]; @@ -845,6 +856,25 @@ define([ toClean.forEach(function (id) { spliceFileData(id); }); + var sd = files[STATIC_DATA]; + var toCleanSD = []; + for (var id in sd) { + id = Number(id); + var el2 = sd[id]; + if (!el2 || typeof(el2) !== "object" || !el2.href) { + toCleanSD.push(id); + continue; + } + if ((loggedIn || config.testMode) && rootFiles.indexOf(id) === -1) { + toCleanSD.push(id); + continue; + } + } + var spliceSD = function (id) { + if (readOnly) { return; } + delete files[STATIC_DATA][id]; + }; + toCleanSD.forEach(spliceSD); }; var fixSharedFolders = function () { if (sharedFolder) { return; } @@ -892,6 +922,12 @@ define([ } } }; + var fixStaticData = function () { + if (typeof(files[STATIC_DATA]) !== "object") { + debug("STATIC_DATA was not an object"); + files[STATIC_DATA] = {}; + } + }; var fixDrive = function () { @@ -900,6 +936,7 @@ define([ }); }; + fixStaticData(); fixRoot(); fixTrashRoot(); fixTemplate(); diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index 0e799de56..fc42f8aae 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -584,6 +584,24 @@ define([ }); }); }; + // Add a link + var _addLink = function (Env, data, cb) { + data = data || {}; + var resolved = _resolvePath(Env, data.path); + if (!resolved || !resolved.userObject) { return void cb({error: 'E_NOTFOUND'}); } + var uo = resolved.userObject; + var now = +new Date(); + uo.pushLink({ + name: data.name, + href: data.href, + atime: now, + ctime: now + }, function (e, id) { + if (e) { return void cb({error: e}); } + uo.add(id, resolved.path); + Env.onSync(cb); + }); + }; var _restoreSharedFolder = function (Env, _data, cb) { var fId = _data.id; @@ -1019,6 +1037,14 @@ define([ }); }; + + var _updateStaticAccess = function (Env, id, cb) { + var uo = _getUserObjectFromId(Env, id); + var sd = uo.getFileData(id, true); + sd.atime = +new Date(); + Env.onSync(cb); + }; + var onCommand = function (Env, cmdData, cb) { var cmd = cmdData.cmd; var data = cmdData.data || {}; @@ -1031,6 +1057,8 @@ define([ _addFolder(Env, data, cb); break; case 'addSharedFolder': _addSharedFolder(Env, data, cb); break; + case 'addLink': + _addLink(Env, data, cb); break; case 'restoreSharedFolder': _restoreSharedFolder(Env, data, cb); break; case 'convertFolderToSharedFolder': @@ -1045,6 +1073,8 @@ define([ _rename(Env, data, cb); break; case 'setFolderData': _setFolderData(Env, data, cb); break; + case 'updateStaticAccess': + _updateStaticAccess(Env, data, cb); break; default: cb(); } @@ -1129,8 +1159,8 @@ define([ data: uo.getFileData(id) }; }).filter(function (d) { - if (channels.indexOf(d.data.channel) === -1) { - channels.push(d.data.channel); + if (channels.indexOf(d.data.channel || d.id) === -1) { + channels.push(d.data.channel || d.id); return true; } }); @@ -1383,6 +1413,16 @@ define([ } }, cb); }; + var addLinkInner = function (Env, path, data, cb) { + return void Env.sframeChan.query("Q_DRIVE_USEROBJECT", { + cmd: "addLink", + data: { + path: path, + name: data.name, + href: data.url + } + }, cb); + }; var restoreSharedFolderInner = function (Env, fId, password, cb) { return void Env.sframeChan.query("Q_DRIVE_USEROBJECT", { cmd: "restoreSharedFolder", @@ -1433,6 +1473,14 @@ define([ }, cb); }; + var updateStaticAccessInner = function (Env, id, cb) { + return void Env.sframeChan.query("Q_DRIVE_USEROBJECT", { + cmd: "updateStaticAccess", + data: id + }, cb); + + }; + /* Tools */ var findChannels = _findChannels; @@ -1450,6 +1498,11 @@ define([ return String(uo.getTitle(id, type)); }; + var isStaticFile = function (Env, id) { + var uo = _getUserObjectFromId(Env, id); + return uo.isStaticFile(id); + }; + var isReadOnlyFile = function (Env, id) { var uo = _getUserObjectFromId(Env, id); return uo.isReadOnlyFile(id); @@ -1491,7 +1544,7 @@ define([ var files = []; var userObjects = _getUserObjects(Env); userObjects.forEach(function (uo) { - var data = uo.getFiles([UserObject.FILES_DATA]).map(function (id) { + var data = uo.getFiles([UserObject.FILES_DATA, UserObject.STATIC_DATA]).map(function (id) { return [Number(id), uo.getFileData(id)]; }); Array.prototype.push.apply(files, data); @@ -1608,17 +1661,20 @@ define([ emptyTrash: callWithEnv(emptyTrashInner), addFolder: callWithEnv(addFolderInner), addSharedFolder: callWithEnv(addSharedFolderInner), + addLink: callWithEnv(addLinkInner), restoreSharedFolder: callWithEnv(restoreSharedFolderInner), convertFolderToSharedFolder: callWithEnv(convertFolderToSharedFolderInner), delete: callWithEnv(deleteInner), deleteOwned: callWithEnv(deleteOwnedInner), restore: callWithEnv(restoreInner), setFolderData: callWithEnv(setFolderDataInner), + updateStaticAccess: callWithEnv(updateStaticAccessInner), // Tools getFileData: callWithEnv(getFileData), find: callWithEnv(find), getTitle: callWithEnv(getTitle), isReadOnlyFile: callWithEnv(isReadOnlyFile), + isStaticFile: callWithEnv(isStaticFile), getFiles: callWithEnv(getFiles), search: callWithEnv(search), getRecentPads: callWithEnv(getRecentPads), diff --git a/www/common/sframe-app-framework.js b/www/common/sframe-app-framework.js index 0fd250f80..96997cd06 100644 --- a/www/common/sframe-app-framework.js +++ b/www/common/sframe-app-framework.js @@ -733,11 +733,20 @@ define([ if (!common.isLoggedIn()) { return; } $embedButton = common.createButton('mediatag', true).click(function () { var cfg = { - types: ['file'], + types: ['file', 'link'], where: ['root'] }; if ($embedButton.data('filter')) { cfg.filter = $embedButton.data('filter'); } common.openFilePicker(cfg, function (data) { + // Embed links + if (data.static) { + var a = h('a', { + href: data.href + }, data.name); + mediaTagEmbedder($(a), data); + return; + } + // Embed files if (data.type !== 'file') { console.log("Unexpected data type picked " + data.type); return; diff --git a/www/common/userObject.js b/www/common/userObject.js index ca716f25f..9de3ea918 100644 --- a/www/common/userObject.js +++ b/www/common/userObject.js @@ -17,6 +17,7 @@ define([ var SHARED_FOLDERS_TEMP = module.SHARED_FOLDERS_TEMP = "sharedFoldersTemp"; // Maybe deleted or new password var FILES_DATA = module.FILES_DATA = Constants.storageKey; var OLD_FILES_DATA = module.OLD_FILES_DATA = Constants.oldStorageKey; + var STATIC_DATA = module.STATIC_DATA = 'static'; // Create untitled documents when no name is given var getLocaleDate = function () { @@ -138,6 +139,7 @@ define([ var NEW_FILE_NAME = Messages.fm_newFile || 'New file'; exp.ROOT = ROOT; + exp.STATIC_DATA = STATIC_DATA; exp.UNSORTED = UNSORTED; exp.TRASH = TRASH; exp.TEMPLATE = TEMPLATE; @@ -236,6 +238,10 @@ define([ return Boolean(data.roHref && !data.href); }; + exp.isStaticFile = function (element) { + return Boolean(files[STATIC_DATA] && files[STATIC_DATA][element]); + }; + var isFolder = exp.isFolder = function (element) { if (isFolderData(element)) { return false; } return typeof(element) === "object" || isSharedFolder(element); @@ -310,6 +316,12 @@ define([ // Get data from AllFiles (Cryptpad_RECENTPADS) var getFileData = exp.getFileData = function (file, editable) { if (!file) { return; } + var link = (files[STATIC_DATA] || {})[file]; + if (link) { + var _link = editable ? link : Util.clone(link); + if (!editable) { _link.static = true; } + return _link; + } var data = files[FILES_DATA][file] || {}; if (!editable) { data = JSON.parse(JSON.stringify(data)); @@ -344,6 +356,7 @@ define([ return '??'; } var data = getFileData(file); + if (data.static) { return data.name; } if (!file || !data || !(data.href || data.roHref)) { error("getTitle called with a non-existing file id: ", file, data); return; @@ -475,6 +488,11 @@ define([ }); return ret; }; + _getFiles[STATIC_DATA] = function () { + var ret = []; + if (!files[STATIC_DATA]) { return ret; } + return Object.keys(files[STATIC_DATA]).map(Number).filter(Boolean); + }; _getFiles[FILES_DATA] = function () { var ret = []; if (!files[FILES_DATA]) { return ret; } @@ -854,6 +872,7 @@ define([ // RENAME exp.rename = function (path, newName, cb) { + cb = cb || function () {}; if (sframeChan) { return void sframeChan.query("Q_DRIVE_USEROBJECT", { cmd: "rename", @@ -891,9 +910,15 @@ define([ if (isSharedFolder(element)) { data = files[SHARED_FOLDERS][element]; } else { - data = files[FILES_DATA][element]; + data = files[FILES_DATA][element] || files[STATIC_DATA][element]; } if (!data) { return; } + if (files[STATIC_DATA][element]) { + if (!newName || !newName.trim()) { return void cb(); } + data.name = newName; + cb(); + return; + } if (!newName || newName.trim() === "") { delete data.filename; if (typeof cb === "function") { cb(); } diff --git a/www/secureiframe/inner.js b/www/secureiframe/inner.js index 4226c7f82..18970c47b 100644 --- a/www/secureiframe/inner.js +++ b/www/secureiframe/inner.js @@ -127,6 +127,7 @@ define([ sframeChan.event("EV_SECURE_ACTION", { type: parsed.type, password: data.password, + static: data.static, href: data.url, name: data.name }); @@ -214,20 +215,21 @@ define([ $container.html(''); Object.keys(list).forEach(function (id) { var data = list[id]; - var name = data.filename || data.title || '?'; + var name = data.filename || data.title || data.name || '?'; if (filter && name.toLowerCase().indexOf(filter.toLowerCase()) === -1) { return; } var $span = $('', { 'class': 'cp-filepicker-content-element', - 'title': name, + 'title': Util.fixHTML(name), }).appendTo($container); $span.append(UI.getFileIcon(data)); $('', {'class': 'cp-filepicker-content-element-name'}).text(name) .appendTo($span); + if (data.static) { $span.attr('title', Util.fixHTML(data.href)); } $span.click(function () { if (typeof onFilePicked === "function") { - onFilePicked({url: data.href, name: name, password: data.password}); + onFilePicked({url: data.href, name: name, static: data.static, password: data.password}); } }); diff --git a/www/teams/main.js b/www/teams/main.js index ea48f72a1..4bf00e105 100644 --- a/www/teams/main.js +++ b/www/teams/main.js @@ -24,7 +24,8 @@ define([ sframeChan.on('Q_DRIVE_USEROBJECT', function (data, cb) { if (!teamId) { return void cb({error: 'EINVAL'}); } - data.teamId = teamId; + if (data.teamId !== -1) { data.teamId = teamId; } + else { delete data.teamId; } Cryptpad.userObjectCommand(data, cb); }); sframeChan.on('Q_DRIVE_GETOBJECT', function (data, cb) { From e38206ffb34775081d5e2d8f616c86b6fb638636 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 20 Jul 2021 10:46:40 +0200 Subject: [PATCH 06/76] Fix premium tickets --- www/support/ui.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/support/ui.js b/www/support/ui.js index 90fd43fa5..db51e1221 100644 --- a/www/support/ui.js +++ b/www/support/ui.js @@ -345,7 +345,7 @@ define([ var senderKey = content.sender && content.sender.edPublic; var fromMe = senderKey === privateData.edPublic; var fromAdmin = ctx.adminKeys.indexOf(senderKey) !== -1; - var fromPremium = Boolean(content.sender.plan); + var fromPremium = Boolean(content.sender.plan || Util.find(content, ['sender', 'quota', 'plan']); var userData = h('div.cp-support-showdata', [ Messages.support_showData, From 1a88baf9c367bb41edb579df694fc67dd17c9a07 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 20 Jul 2021 10:48:25 +0200 Subject: [PATCH 07/76] lint compliance --- www/support/ui.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/support/ui.js b/www/support/ui.js index db51e1221..f61ddac4b 100644 --- a/www/support/ui.js +++ b/www/support/ui.js @@ -345,7 +345,7 @@ define([ var senderKey = content.sender && content.sender.edPublic; var fromMe = senderKey === privateData.edPublic; var fromAdmin = ctx.adminKeys.indexOf(senderKey) !== -1; - var fromPremium = Boolean(content.sender.plan || Util.find(content, ['sender', 'quota', 'plan']); + var fromPremium = Boolean(content.sender.plan || Util.find(content, ['sender', 'quota', 'plan'])); var userData = h('div.cp-support-showdata', [ Messages.support_showData, From d530a51f99facde8c496142f46615bc85c941542 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 20 Jul 2021 10:51:12 +0200 Subject: [PATCH 08/76] Fix premium ticket category in admin panel --- www/admin/inner.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/www/admin/inner.js b/www/admin/inner.js index 61cf05896..b35059df0 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -833,7 +833,8 @@ define([ var premium = t.some(function (msg) { var _ed = Util.find(msg, ['content', 'msg', 'content', 'sender', 'edPublic']); if (ed !== _ed) { return; } - return Util.find(msg, ['content', 'msg', 'content', 'sender', 'plan']); + return Util.find(msg, ['content', 'msg', 'content', 'sender', 'plan']) || + Util.find(msg, ['content', 'msg', 'content', 'sender', 'quota', 'plan']); }); var lastMsg = t[t.length - 1]; var lastMsgEd = Util.find(lastMsg, ['content', 'msg', 'content', 'sender', 'edPublic']); From 0a5614b79f20c841da7172f5e7d5603bdffa8a50 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 21 Jul 2021 11:37:44 +0200 Subject: [PATCH 09/76] Fix team invitation link #774 --- www/common/outer/team.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/outer/team.js b/www/common/outer/team.js index 4184b8482..94f91c807 100644 --- a/www/common/outer/team.js +++ b/www/common/outer/team.js @@ -195,7 +195,7 @@ define([ Pinpad.create(ctx.store.network, data, function (e, call) { if (e) { return void cb(e); } team.rpc = call; - team.onRpcReadyEvt.fire(); + if (team && team.onRpcReadyEvt) { team.onRpcReadyEvt.fire(); } cb(); }, Cache); }); From 667bef2a840951e7226a8cb2147734ba9ca5eb3c Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 21 Jul 2021 17:19:35 +0200 Subject: [PATCH 10/76] Fix links in shared folders --- www/common/outer/userObject.js | 6 ++++++ www/common/proxy-manager.js | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/www/common/outer/userObject.js b/www/common/outer/userObject.js index a12beacf9..257fa5001 100644 --- a/www/common/outer/userObject.js +++ b/www/common/outer/userObject.js @@ -253,6 +253,12 @@ define([ id = Number(id); // Find and maybe update existing pads with the same channel id var d = data[id]; + // If we were given a static link, copy to STATIC_DATA + if (d.static) { + delete d.static; + files[STATIC_DATA][id] = d; + return; + } // If we were given an edit link, encrypt its value if needed if (d.href) { d.href = exp.cryptor.encrypt(d.href); } var found = false; diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index fc42f8aae..01c22812c 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -22,11 +22,11 @@ define([ // a cached version if (Env.folders[id].offline && !lm.cache) { Env.folders[id].offline = false; + if (Env.folders[id].userObject.fixFiles) { Env.folders[id].userObject.fixFiles(); } Env.Store.refreshDriveUI(); } return; } - if (Env.folders[id]) { console.warn(Env.folders[id]); } var cfg = getConfig(Env); cfg.sharedFolder = true; cfg.id = id; From 6faaec5042f8442463f481b1267212022eafc94e Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 22 Jul 2021 12:06:48 +0200 Subject: [PATCH 11/76] lint compliance --- www/code/inner.js | 2 +- www/common/drive-ui.js | 16 ++++++++-------- www/common/outer/userObject.js | 12 ++++++------ 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/www/code/inner.js b/www/code/inner.js index 19ffdb285..4f6c0308e 100644 --- a/www/code/inner.js +++ b/www/code/inner.js @@ -369,7 +369,7 @@ define([ evModeChange.reg(function (mode) { if (MEDIA_TAG_MODES.indexOf(mode) !== -1) { // Embedding is enabled - framework.setMediaTagEmbedder(function (mt, data) { + framework.setMediaTagEmbedder(function (mt) { editor.focus(); editor.replaceSelection($(mt)[0].outerHTML); }); diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index 28ac531e2..9c0a37f42 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -1113,6 +1113,10 @@ define([ common.getMediaTagPreview(mts, idx); }; + var refresh = APP.refresh = function () { + APP.displayDirectory(currentPath); + }; + // `app`: true (force open wiht the app), false (force open in preview), // falsy (open in preview if default is not using the app) var defaultInApp = ['application/pdf']; @@ -1163,10 +1167,6 @@ define([ common.openURL(Hash.getNewPadURL(href, obj)); }; - var refresh = APP.refresh = function () { - APP.displayDirectory(currentPath); - }; - var pickFolderColor = function ($element, currentColor, cb) { var colors = ["", "#f23c38", "#ff0073", "#da0eba", "#9d00ac", "#6c19b3", "#4a42b1", "#3d8af0", "#30a0f1", "#1fb9d1", "#009686", "#45b354", "#84c750", "#c6e144", "#faf147", "#fbc423", "#fc9819", "#fd5227", "#775549", "#9c9c9c", "#607a89"]; @@ -1938,7 +1938,7 @@ define([ 'class': 'cp-app-drive-element-ctime cp-app-drive-element-list' }).text(getDate(data.ctime)); $element.append($type).append($adate).append($cdate); - } + }; var _addOwnership = function ($span, $state, data) { if (data && Array.isArray(data.owners) && data.owners.indexOf(edPublic) !== -1) { var $owned = $ownedIcon.clone().appendTo($state); @@ -2504,7 +2504,7 @@ define([ setViewMode(viewMode || 'grid'); showMode(viewMode); - $button.click(function (e) { + $button.click(function () { var viewMode = getViewMode(); var newViewMode = getOppositeViewMode(viewMode); setViewMode(newViewMode); @@ -3182,11 +3182,11 @@ define([ .text(Messages.uploadFolderButton)); } // Link - var $elementFileUpload = $('
  • ', { + var $elementLink = $('
  • ', { 'class': 'cp-app-drive-new-link cp-app-drive-element-row ' + 'cp-app-drive-element-grid' }).prepend(getIcon('link')).appendTo($container); - $elementFileUpload.append($('', {'class': 'cp-app-drive-new-name'}) + $elementLink.append($('', {'class': 'cp-app-drive-new-name'}) .text(Messages.fm_link)); } // Pads diff --git a/www/common/outer/userObject.js b/www/common/outer/userObject.js index 257fa5001..97c2207e0 100644 --- a/www/common/outer/userObject.js +++ b/www/common/outer/userObject.js @@ -864,15 +864,15 @@ define([ }); var sd = files[STATIC_DATA]; var toCleanSD = []; - for (var id in sd) { - id = Number(id); - var el2 = sd[id]; + for (var id2 in sd) { + id2 = Number(id2); + var el2 = sd[id2]; if (!el2 || typeof(el2) !== "object" || !el2.href) { - toCleanSD.push(id); + toCleanSD.push(id2); continue; } - if ((loggedIn || config.testMode) && rootFiles.indexOf(id) === -1) { - toCleanSD.push(id); + if ((loggedIn || config.testMode) && rootFiles.indexOf(id2) === -1) { + toCleanSD.push(id2); continue; } } From 6c720ce9d1881f5dacabe5e15877edad91b6781a Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 23 Jul 2021 10:18:42 +0200 Subject: [PATCH 12/76] Fix type error --- www/form/inner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/form/inner.js b/www/form/inner.js index 9f05f80dd..e30f0775a 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -607,7 +607,7 @@ define([ _date = new Date(data); data = Flatpickr.formatDate(_date, timeFormat); } - var day = allDays[_date.getDay()]; + var day = _date && allDays[_date.getDay()]; return h('div.cp-poll-cell.cp-form-poll-option', { title: Util.fixHTML(data) }, [ From 212b3d48845b9ad17408f18ea920bdd3f4305f78 Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 23 Jul 2021 14:47:30 +0200 Subject: [PATCH 13/76] Form fixes and improvements --- www/common/sframe-common-outer.js | 1 - www/form/app-form.less | 14 ++++++ www/form/inner.js | 71 ++++++++++++++++++++++++++----- 3 files changed, 74 insertions(+), 12 deletions(-) diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index b0759b5ec..a532863a2 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -1925,7 +1925,6 @@ define([ var cryptputCfg = $.extend(true, {}, rtConfig, {password: password}); if (data.templateContent) { Cryptget.put(currentPad.hash, JSON.stringify(data.templateContent), function () { - console.error(arguments); startRealtime(); cb(); }, cryptputCfg); diff --git a/www/form/app-form.less b/www/form/app-form.less index b0e38f27c..b037efac2 100644 --- a/www/form/app-form.less +++ b/www/form/app-form.less @@ -247,6 +247,14 @@ .cp-form-anon-answer { text-align: center; margin: 20px 0 30px 0; + .cp-form-anon-answer-input { + display: flex; + white-space: nowrap; + align-items: center; + input { + margin-left: 10px; + } + } } } @@ -669,6 +677,12 @@ .avatar_main(30px); margin-right: 10px; } + &.cp-clickable { + cursor: pointer; + &:hover { + transform: scale(1.1); + } + } } .cp-poll-time-day { flex-basis: 100px; diff --git a/www/form/inner.js b/www/form/inner.js index 9f05f80dd..773740701 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -588,7 +588,9 @@ define([ return weekDays.map(function (day) { return day.replace(/^./, function (str) { return str.toUpperCase(); }); }); }; - var makePollTable = function (answers, opts) { + // "resultsPageObj" is an object with "content" and "answers" + // only available when viewing the Responses page + var makePollTable = function (answers, opts, resultsPageObj) { // Sort date values if (opts.type !== "text") { opts.values.sort(function (a, b) { @@ -607,7 +609,7 @@ define([ _date = new Date(data); data = Flatpickr.formatDate(_date, timeFormat); } - var day = allDays[_date.getDay()]; + var day = _date && allDays[_date.getDay()]; return h('div.cp-poll-cell.cp-form-poll-option', { title: Util.fixHTML(data) }, [ @@ -667,13 +669,19 @@ define([ }, v); return cell; }); - els.unshift(h('div.cp-poll-cell.cp-poll-answer-name', { + var nameCell; + els.unshift(nameCell = h('div.cp-poll-cell.cp-poll-answer-name', { title: Util.fixHTML(name) }, [ avatar, h('span', name) ])); bodyEls.push(h('div', els)); + if (resultsPageObj && (APP.isEditor || APP.isAuditor)) { + $(nameCell).addClass('cp-clickable').click(function () { + APP.renderResults(resultsPageObj.content, resultsPageObj.answers, answerObj.curve); + }); + } }); } var body = h('div.cp-form-poll-body', bodyEls); @@ -815,6 +823,7 @@ define([ if (filterCurve && user === filterCurve) { return; } try { return { + curve: user, user: answers[user].msg._userdata, results: answers[user].msg[uid] }; @@ -1615,7 +1624,7 @@ define([ if (!opts) { opts = TYPES.poll.defaultOpts; } if (!Array.isArray(opts.values)) { return; } - var lines = makePollTable(answers, opts); + var lines = makePollTable(answers, opts, false); // Add form var addLine = opts.values.map(function (data) { @@ -1699,10 +1708,16 @@ define([ }; }, - printResults: function (answers, uid, form) { + printResults: function (answers, uid, form, content) { var opts = form[uid].opts || TYPES.poll.defaultOpts; var _answers = getBlockAnswers(answers, uid); - var lines = makePollTable(_answers, opts); + + // If content is defined, we'll be able to click on a row to display + // all the answers of this user + var lines = makePollTable(_answers, opts, content && { + content: content, + answers: answers + }); var total = makePollTotal(_answers, opts); if (total) { lines.push(h('div', total)); } @@ -1723,7 +1738,7 @@ define([ }, }; - var renderResults = function (content, answers) { + var renderResults = APP.renderResults = function (content, answers, showUser) { var $container = $('div.cp-form-creator-results').empty(); if (!Object.keys(answers || {}).length) { @@ -1767,7 +1782,9 @@ define([ var type = block.type; var model = TYPES[type]; if (!model || !model.printResults) { return; } - var print = model.printResults(answers, uid, form); + + // Only use content if we're not viewing individual answers + var print = model.printResults(answers, uid, form, !header && content); var q = h('div.cp-form-block-question', block.q || Messages.form_default); @@ -1861,10 +1878,19 @@ define([ e.preventDefault(); APP.common.openURL(Hash.hashToHref(ud.profile, 'profile')); }); + if (showUser === curve) { + setTimeout(function () { + showUser = undefined; + $(viewButton).click(); + }); + } return div; }); $results.append(els); }); + if (showUser) { + $s.click(); + } }; var addResultsButton = function (framework, content) { @@ -1910,16 +1936,34 @@ define([ var makeFormControls = function (framework, content, update, evOnChange) { var loggedIn = framework._.sfCommon.isLoggedIn(); var metadataMgr = framework._.cpNfInner.metadataMgr; + var user = metadataMgr.getUserData(); if (!loggedIn && !content.answers.anonymous) { return; } var cbox; + var anonName, $anonName; cbox = UI.createCheckbox('cp-form-anonymous', Messages.form_anonymousBox, true, { mark: { tabindex:1 } }); + var $anonBox = $(cbox).find('input'); if (loggedIn) { if (!content.answers.anonymous || APP.cantAnon) { $(cbox).hide().find('input').attr('disabled', 'disabled').prop('checked', false); } + } else { + Messages.form_anonName = "Your username"; // XXX + Messages.form_answerAs = "Answer as"; // XXX + anonName = h('div.cp-form-anon-answer-input', [ + Messages.form_answerAs, + h('input', { + value: user.name || '', + placeholder: Messages.form_anonName + }) + ]) + $anonName = $(anonName).hide(); + $anonBox.on('change', function () { + if (Util.isChecked($anonBox)) { $anonName.hide(); } + else { $anonName.show(); } + }); } var send = h('button.cp-open.btn.btn-primary', update ? Messages.form_update : Messages.form_submit); @@ -1937,14 +1981,16 @@ define([ if (!results) { return; } var user = metadataMgr.getUserData(); - if (!Util.isChecked($(cbox).find('input'))) { + if (!Util.isChecked($anonBox)) { results._userdata = loggedIn ? { avatar: user.avatar, name: user.name, notifications: user.notifications, curvePublic: user.curvePublic, profile: user.profile - } : { name: user.name }; + } : { + name: $anonName ? $anonName.find('input').val() : user.name + }; } var sframeChan = framework._.sfCommon.getSframeChannel(); @@ -2024,7 +2070,10 @@ define([ return h('div.cp-form-send-container', [ invalid, - cbox ? h('div.cp-form-anon-answer', cbox) : undefined, + cbox ? h('div.cp-form-anon-answer', [ + cbox, + anonName + ]) : undefined, reset, send ]); }; From a93a9f14d3f8cd252ab29e6a5330a588f6251b16 Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 23 Jul 2021 17:51:42 +0200 Subject: [PATCH 14/76] Fix initial title with forms templates --- www/common/sframe-common-title.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/www/common/sframe-common-title.js b/www/common/sframe-common-title.js index 2539d1542..d1b06df73 100644 --- a/www/common/sframe-common-title.js +++ b/www/common/sframe-common-title.js @@ -23,6 +23,12 @@ define([ var $title; exp.setToolbar = function (toolbar) { $title = toolbar && (toolbar.title || toolbar.pageTitle); + if ($title && exp.defaultTitle) { + var md = metadataMgr.getMetadata(); + $title.find('input').prop('placeholder', md.defaultTitle); + $title.find('span.cp-toolbar-title-value').text(md.title || md.defaultTitle); + $title.find('input').val(md.title || md.defaultTitle); + } }; exp.getTitle = function () { return exp.title; }; From f5fc4f28bffd7815635d0cae57a84c25f8809f13 Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 23 Jul 2021 17:51:56 +0200 Subject: [PATCH 15/76] Improve forms CSV export with polls --- www/form/inner.js | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/www/form/inner.js b/www/form/inner.js index 773740701..8db1f8e16 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -1724,15 +1724,31 @@ define([ return h('div.cp-form-type-poll', lines); }, - exportCSV: function (answer) { - if (answer === false) { return; } - if (!answer || !answer.values) { return ['']; } + exportCSV: function (answer, form) { + var opts = form.opts || TYPES.poll.defaultOpts; + var q = form.q || Messages.form_default; + if (answer === false) { + var cols = opts.values.map(function (key) { + return q + ' | ' + key; + }); + cols.unshift(q); + return cols; + } + if (!answer || !answer.values) { + var empty = opts.values.map(function () { return ''; }); + empty.unshift(''); + return empty; + } var str = ''; Object.keys(answer.values).sort().forEach(function (k, i) { if (i !== 0) { str += ';'; } str += k.replace(';', '').replace(':', '') + ':' + answer.values[k]; }); - return [str]; + var res = opts.values.map(function (key) { + return answer.values[key] || ''; + }); + res.unshift(str); + return res; }, icon: h('i.cptools.cptools-form-poll') }, From 9b192a8e4cf474e2b8f69c6d08138b236fdf4c11 Mon Sep 17 00:00:00 2001 From: Weblate Date: Sat, 24 Jul 2021 13:30:03 +0200 Subject: [PATCH 16/76] Translated using Weblate (Lithuanian) Currently translated at 14.9% (204 of 1368 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/lt/ --- www/common/translations/messages.lt.json | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.lt.json b/www/common/translations/messages.lt.json index bd3a3a86b..9d252e196 100644 --- a/www/common/translations/messages.lt.json +++ b/www/common/translations/messages.lt.json @@ -182,5 +182,27 @@ "tags_add": "Atnaujinkite pažymėtų padų žymas", "tags_title": "Žymos (tik jums)", "filePicker_filter": "Filtruokite failus pagal pavadinimą", - "filePicker_description": "Pasirinkite failą iš „CryptDrive“, kad jį įdėtumėte arba įkeltumėte naują" + "filePicker_description": "Pasirinkite failą iš „CryptDrive“, kad jį įdėtumėte arba įkeltumėte naują", + "oo_cantUpload": "Įkelti negalima, kol dalyvauja kiti vartotojai.", + "oo_reconnect": "Serverio ryšys atkurtas. Spustelėkite Gerai, jei norite iš naujo įkelti ir tęsti leidimą.", + "poll_comment_disabled": "Paskelbkite šią apklausą naudodami mygtuką ✓, kad įgalintumėte komentarus.", + "poll_comment_placeholder": "Jūsų komentaras", + "poll_comment_remove": "Ištrinti šį komentarą", + "poll_comment_submit": "Siųsti", + "poll_comment_add": "Pridėti komentarą", + "poll_comment_list": "Komentarai", + "poll_total": "Bendras", + "poll_bookmarked_col": "Tai yra jūsų pažymėtas stulpelis. Jums visada bus atrakinta ir rodoma pradžioje.", + "poll_bookmark_col": "Pažymėkite šį stulpelį taip, kad jis visada būtų atrakintas ir rodomas pradžioje", + "poll_unlocked": "Atrakinta", + "poll_locked": "Užrakinta", + "poll_edit": "Redaguoti", + "poll_remove": "Pašalinti", + "poll_descriptionHint": "Apibūdinkite apklausą ir, kai baigsite, naudokite mygtuką ✓ (paskelbti).\nAprašymas gali būti parašytas naudojant žymėjimo sintaksę ir galite įdėti laikmenos elementus iš savo „CryptDrive“.\nVisi, turintys nuorodą, gali pakeisti aprašą, tačiau tai nerekomenduojama.", + "poll_removeUser": "Ar tikrai norite pašalinti šį vartotoją?", + "poll_removeOption": "Ar tikrai norite pašalinti šią parinktį?", + "poll_userPlaceholder": "Vardas", + "poll_optionPlaceholder": "Pasirinkimai", + "poll_commit": "Pateikti", + "poll_create_option": "Pridėti naują parinktį" } From af8ef252e601a9d1f9d92cef1df1e3b854d32096 Mon Sep 17 00:00:00 2001 From: Weblate Date: Sat, 24 Jul 2021 13:30:04 +0200 Subject: [PATCH 17/76] Translated using Weblate (Chinese (Simplified)) Currently translated at 17.8% (244 of 1368 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/zh_Hans/ --- www/common/translations/messages.zh.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.zh.json b/www/common/translations/messages.zh.json index 49331f9a5..ca0b85c73 100644 --- a/www/common/translations/messages.zh.json +++ b/www/common/translations/messages.zh.json @@ -13,7 +13,8 @@ "todo": "待办事项", "teams": "团队", "sheet": "工作表", - "contacts": "联系我们" + "contacts": "联系我们", + "form": "从" }, "button_newpad": "富文件檔案", "button_newcode": "新代碼檔案", From 79541dd914f0c5b38d77731f3e425a9bfade94e6 Mon Sep 17 00:00:00 2001 From: Weblate Date: Sat, 24 Jul 2021 13:30:04 +0200 Subject: [PATCH 18/76] Translated using Weblate (Japanese) Currently translated at 100.0% (1368 of 1368 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 100.0% (1368 of 1368 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 100.0% (1368 of 1368 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 100.0% (1368 of 1368 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 100.0% (1368 of 1368 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 100.0% (1368 of 1368 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ --- www/common/translations/messages.ja.json | 52 ++++++++++++------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index 742a137d6..bab839f09 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -1,7 +1,7 @@ { "common_connectionLost": "サーバーとの接続が切断しました
    再接続するまで閲覧モードになります。", "button_newsheet": "新規スプレッドシート", - "button_newkanban": "新規のカンバン", + "button_newkanban": "新規カンバン", "button_newwhiteboard": "新規ホワイトボード", "button_newslide": "新規プレゼンテーション", "button_newpoll": "新規投票・アンケート", @@ -111,7 +111,7 @@ "settings_backupCategory": "バックアップ", "settings_backup": "バックアップ", "settings_title": "設定", - "settings_cat_subscription": "サブスクリプション", + "settings_cat_subscription": "定額利用", "settings_cat_drive": "CryptDrive", "settings_cat_account": "アカウント", "settings_save": "保存", @@ -125,7 +125,7 @@ "login_invalUser": "ユーザー名を入力してください", "register_importRecent": "匿名セッションのドキュメントをインポート", "importButton": "インポート", - "main_catch_phrase": "コラボレーションスイート
    暗号化されかつオープンソース", + "main_catch_phrase": "コラボレーションスイート
    端末間暗号化とオープンソース", "tos_3rdparties": "私たちは、法令に基づく場合を除き、個人情報を第三者に提供しません。", "tos_logs": "あなたのブラウザからサーバーに送信されたメタデータは、サービスを維持するために記録される場合があります。", "tos_availability": "私たちはこのサービスがあなたの役に立つことを願っていますが、可用性や性能は保証できません。定期的にデータをエクスポートしてください。", @@ -150,7 +150,7 @@ "logoutButton": "ログアウト", "login_login": "ログイン", "autostore_hide": "保存しない", - "autostore_store": "保存する", + "autostore_store": "保存", "autostore_notstored": "この{0}はあなたのCryptDriveに保存されていません。今すぐ保存しますか?", "user_displayName": "表示名", "exportButton": "エクスポート", @@ -166,13 +166,13 @@ "profile_upload": " 新しいアバターをアップロード", "teams_table_generic_edit": "編集: フォルダとパッドの作成、変更、削除が可能。", "teams_table_generic_view": "表示: フォルダとパッドへのアクセス(閲覧のみ)。", - "teams_table_generic_own": "チームの管理: チーム名とチームのアバターの変更、オーナーの追加または削除、チームのサブスクリプションの変更、チームの削除が可能。", + "teams_table_generic_own": "チームの管理: チーム名とチームのアバターの変更、オーナーの追加または削除、チームの定額利用に関する変更、チームの削除が可能。", "teams_table_owners": "チームの管理", "teams_table_generic_admin": "メンバーの管理: メンバーの招待および取り消し、メンバーに管理者までの権限の付与が可能。", "teams_table_admins": "メンバーの管理", "teams_table_generic": "権限一覧", "teams_table": "権限", - "contacts_fetchHistory": "古い履歴を取得する", + "contacts_fetchHistory": "古い履歴を取得", "contacts_warning": "ここに入力した全てのメッセージは永続的であり、このパッドの現在および将来の全てのユーザーが確認できます。機密情報の入力には注意してください!", "contacts_typeHere": "ここにメッセージを入力...", "team_cat_drive": "ドライブ", @@ -228,14 +228,14 @@ "notifications_cat_friends": "連絡先リクエスト", "notifications_dismiss": "確認済みにする", "settings_autostoreMaybe": "手動 (確認しない)", - "settings_autostoreNo": "手動 (常に確認する)", + "settings_autostoreNo": "手動(常に確認)", "settings_autostoreHint": "自動 アクセスした全てのパッドをCryptDriveに保存します。
    手動(常に確認) 保存していないパッドにアクセスした際、CryptDriveに保存するかどうかを確認します。
    手動(確認しない) アクセス先のパッドはCryptDriveに自動で保存されません。保存オプションは表示されません。", "settings_userFeedback": "ユーザーフィードバックを有効にする", "settings_userFeedbackHint2": "あなたのパッドのコンテンツがサーバーと共有されることはありません。", "settings_userFeedbackHint1": "CryptPadは、ユーザーエクスペリエンスの向上のため、いくつかの非常に基本的なフィードバックを、サーバーに提供します。 ", "settings_userFeedbackTitle": "フィードバック", "settings_autostoreYes": "自動", - "settings_importConfirm": "このブラウザで最近使用したパッドを、あなたのユーザーアカウントのCryptDriveにインポートしますか?", + "settings_importConfirm": "このブラウザで最近利用したパッドを、あなたのユーザーアカウントのCryptDriveにインポートしますか?", "settings_importDone": "インポートが完了しました", "settings_import": "インポート", "settings_importTitle": "このブラウザでの最近のパッドをあなたのCryptDriveにインポートします", @@ -246,7 +246,7 @@ "fc_delete": "ごみ箱へ移動", "fc_remove": "削除", "fc_restore": "復元", - "fc_delete_owned": "完全削除", + "fc_delete_owned": "破棄", "creation_create": "作成", "creation_password": "パスワード\n", "creation_expireMonths": "か月", @@ -266,7 +266,7 @@ "features_f_cryptdrive1": "CryptDriveの全機能", "features_f_anon_note": "追加機能あり", "features_f_anon": "匿名ユーザーの全機能", - "features_f_storage0_note": "ドキュメントは{0}日以上使用されないと削除されます", + "features_f_storage0_note": "ドキュメントは{0}日以上利用されないと削除されます", "features_f_storage0": "一時的な保存", "features_f_cryptdrive0_note": "アクセスしたパッドをブラウザに保存して、後で開くことができます", "features_f_cryptdrive0": "CryptDriveへの限定的なアクセス", @@ -322,7 +322,7 @@ "properties_passwordSuccessFile": "パスワードは正常に変更されました。", "drive_sfPasswordError": "誤ったパスワードです", "team_title": "チーム: {0}", - "password_error": "ドキュメントが存在しません!
    このエラーは、誤ったパスワードが入力された場合、またはドキュメントがサーバーから完全削除された場合に発生します。", + "password_error": "ドキュメントが存在しません!
    このエラーは、誤ったパスワードが入力された場合、またはドキュメントがサーバーから破棄された場合に発生します。", "password_error_seed": "パッドが存在しません!
    このエラーは「パスワードが追加・変更された」場合、または「パッドがサーバーから削除された」場合に発生します。", "password_submit": "送信", "password_placeholder": "パスワードを入力...", @@ -332,7 +332,7 @@ "properties_addPassword": "パスワードを設定", "history_close": "閉じる", "history_restore": "復元", - "fm_emptyTrashOwned": "ごみ箱に、あなたが所有しているドキュメントが入っています。あなたのドライブからのみ削除するか、全てのユーザーから完全削除するかを選択できます。", + "fm_emptyTrashOwned": "ごみ箱に、あなたの所有するドキュメントが入っています。あなたのドライブからのみ削除するか、全てのユーザーから破棄するかを選択できます。", "access_destroyPad": "このドキュメントまたはフォルダを完全に削除する", "accessButton": "アクセス", "access_allow": "リスト", @@ -417,7 +417,7 @@ "fm_noname": "無題のドキュメント", "fm_openParent": "フォルダに表示", "fm_newButtonTitle": "新しいドキュメントやフォルダを作成したり、ファイルを現在のフォルダにインポートしたりできます。", - "contacts_info4": "チャットの参加者のどちらも履歴を削除できます", + "contacts_info4": "チャットの参加者は誰でも履歴を消去できます", "contacts_info2": "連絡先のアイコンをクリックしてチャットを開始", "contacts_confirmRemove": "{0}をあなたの連絡先から削除してよろしいですか?", "profile_error": "プロフィールの作成時にエラーが発生しました: {0}", @@ -475,7 +475,7 @@ "poll_create_option": "新しいオプションを追加", "poll_create_user": "新しいユーザーを追加", "pad_mediatagImport": "あなたのCryptDriveに保存", - "admin_listMyInstanceLabel": "このインスタンスをリストに表示する", + "admin_listMyInstanceLabel": "このインスタンスをリストに表示", "admin_checkupTitle": "インスタンスの設定を検証", "cba_disable": "消去して無効にする", "upload_pending": "保留中", @@ -595,7 +595,7 @@ "toolbar_file": "ファイル", "drive_treeButton": "ファイル", "toolbar_insert": "挿入", - "fm_sort": "並び替え", + "fm_sort": "並び替える", "comments_comment": "コメント", "comments_resolve": "解決", "comments_reply": "返信", @@ -765,25 +765,25 @@ "errorState": "重大なエラー: {0}", "realtime_unrecoverableError": "回復不能なエラーが発生しました。OKをクリックして再読み込みを行ってください。", "disabledApp": "このアプリケーションは無効になっています。詳細については、このCryptPadの管理者にお問い合わせください。", - "deletedFromServer": "パッドは完全削除されました", + "deletedFromServer": "ドキュメントが破棄されました", "newVersionError": "新しいバージョンのCryptPadがあります。
    リロードすると新しいバージョンを読み込みます。Escキーを押すとオフラインモードでコンテンツにアクセスします。", "errorRedirectToHome": "Escキーを押すとCryptDriveにリダイレクトします。", "errorCopy": " Escキーを押すと、閲覧モードで引き続きコンテンツにアクセスできます。", "invalidHashError": "要求したドキュメントのURLが無効です。", "chainpadError": "コンテンツを更新する際に重大なエラーが発生しました。コンテンツが失われないよう、閲覧モードで表示されています。
    このパッドを表示し続けるにはEscキーを押し、再度編集を試みるにはリロードをしてください。", - "inactiveError": "このパッドは使用されていなかったため削除されました。Escキーを押して新しいパッドを作成します。", - "deletedError": "このドキュメントは削除されたため、使用できなくなりました。", - "expiredError": "このパッドは使用期限が過ぎてしまったため、使用できなくなりました。", + "inactiveError": "このパッドは利用されていなかったため削除されました。Escキーを押すと新しいパッドを作成します。", + "deletedError": "このドキュメントは削除されたため、利用できなくなりました。", + "expiredError": "このパッドは利用期限を過ぎてしまったため、利用できなくなりました。", "anonymousStoreDisabled": "このCryptPadのインスタンスの管理者は、匿名ユーザーによる保存を無効に設定しています。CryptDriveを使用するにはログインする必要があります。", - "padNotPinnedVariable": "このパッドは{4}日使用しないと期限切れになります。{0}ログイン{1}または{2}登録{3}し保存してください。", - "padNotPinned": "このパッドは3ヶ月間使用しないと有効期限が切れます。{0}ログイン{1}するか{2}登録{3}して保存してください。", + "padNotPinnedVariable": "このパッドは{4}日間利用しないと有効期限が切れます。{0}ログイン{1}するか{2}登録{3}して保存してください。", + "padNotPinned": "このパッドは3か月間利用しないと有効期限が切れます。{0}ログイン{1}するか{2}登録{3}して保存してください。", "onLogout": "ログアウトしました。{0}ここをクリック{1}するか
    Escapeキーを押すと、閲覧モードでパッドにアクセスできます。", "typeError": "このパッドは選択したアプリケーションと互換性がありません", "form_type_page": "ページ分割", "form_description_default": "ここにテキストを入力", "team_pcsSelectHelp": "所有するパッドをチームのドライブに作成すると、そのパッドのオーナー権はチームに与えられます。", "sharedFolders_create_owned": "所有するフォルダ", - "creation_owned1": "所有している項目は、オーナーの望むときにいつでも完全削除できます。完全削除すると、他のユーザーのCryptDriveからも削除されます。", + "creation_owned1": "所有している項目は、オーナーの望むときにいつでも破棄できます。破棄すると、他のユーザーのCryptDriveからも削除されます。", "creation_owned": "パッドを所有", "uploadFolder_modal_owner": "所有するファイル", "upload_modal_owner": "所有するファイル", @@ -824,7 +824,7 @@ "pad_goToAnchor": "アンカーに移動", "oo_cantMigrate": "この表はアップロードの最大のサイズを超えているため、移行することができません。", "footer_roadmap": "ロードマップ", - "settings_deleteSubscription": "サブスクリプションを管理", + "settings_deleteSubscription": "定額利用を管理", "broadcast_translations": "翻訳", "admin_broadcastCancel": "メッセージを削除", "admin_broadcastButton": "送信", @@ -1252,7 +1252,7 @@ "owner_removeMeConfirm": "オーナー権を放棄しようとしています。これは取り消せません。よろしいですか?", "requestEdit_confirm": "{1}がパッド「{0}」の編集権を要求しました。編集権を与えますか?", "admin_supportInitHelp": "サーバーはサポートメールボックスを使用するように設定されていません。サポートメールボックスを有効にし、ユーザーからメッセージを受け取るためには、サーバーの管理者に連絡し、「./scripts/generate-admin-keys.js」のスクリプトを実行してもらい、生成された公開鍵を「config.js」に保存して、秘密鍵をあなたに送信してもらうよう依頼する必要があります。", - "feedback_privacy": "私たちはプライバシーを配慮すると同時に、CryptPadを使いやすくしたいと望んでいます。このファイルは、実行されたアクションを特定するパラメーターと共に要求され、ユーザーにとって重要なUI機能を特定するために使用されます。", + "feedback_privacy": "私たちはプライバシーに配慮すると同時に、CryptPadを使いやすくしたいと望んでいます。このファイルは、実行されたアクションを特定するパラメーターと共に要求され、ユーザーにとって重要なUI機能を特定するために使用されます。", "register_warning_note": "暗号化を行うCryptPadの性質上、サービス管理者は、ユーザー名とパスワードを忘れた場合にデータを回復することができません。ユーザー名とパスワードを安全な場所に保管してください。", "history_restoreDriveTitle": "選択したバージョンのCryptDriveを復元", "errorPopupBlocked": "新しいタブを開く許可が必要です。お使いのブラウザのアドレスバーから、ポップアップウィンドウを許可してください。これらのウィンドウが広告の表示に使用されることはありません。", @@ -1308,8 +1308,8 @@ "share_linkPasswordAlert": "この項目はパスワードで保護されています。リンクを受け取った相手はパスワードを入力する必要があります。", "register_notes_title": "重要な注意事項", "teams_table_specificHint": "以前のバージョンの共有フォルダでは、閲覧者は既存のパッドを変更することができます。 これらのフォルダで作成またはコピーしたパッドには、標準の権限が与えられます。", - "broadcast_maintenance": "{0}から{1}の間でメンテナンスを予定しています。その間CryptPadは使用できません。", - "admin_archiveHint": "ドキュメントを完全削除することなく、利用できないよう設定できます。「アーカイブ」フォルダに移動し、数日後に削除します(期間については設定ファイルより設定できます)。", + "broadcast_maintenance": "{0}から{1}の間でメンテナンスを予定しています。その間CryptPadは利用できません。", + "admin_archiveHint": "ドキュメントを破棄することなく、利用できないよう設定できます。「アーカイブ」フォルダに移動し、数日後に削除します(期間については設定ファイルより設定できます)。", "admin_unarchiveHint": "アーカイブされたドキュメントを復元できます", "admin_registrationTitle": "登録を締め切る", "admin_defaultlimitHint": "ユーザー定義のルールが適用されていない際の最大のストレージ容量(ユーザーとチームについて)を設定できます", From 2019e1d70a75dd8c36c8b5b1459e34f3f59d3b41 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 26 Jul 2021 13:05:47 +0530 Subject: [PATCH 19/76] implement minor fixes and add comments following code review --- www/common/drive-ui.js | 7 +++--- www/common/outer/mailbox-handlers.js | 3 ++- www/common/outer/userObject.js | 32 +++++++++++++++++----------- www/teams/main.js | 2 ++ 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index 9c0a37f42..cd456fd41 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -42,7 +42,8 @@ define([ Pages) { - Messages.fm_link = "Link"; // XXX + Messages.fm_link = "Link"; // XXX "New Link" ? + // XXX check for all occurrences of `fm_link` before changing it var APP = window.APP = { editable: false, @@ -1924,10 +1925,10 @@ define([ var $name = $('', {'class': 'cp-app-drive-element-name'}).text(name); $element.append($name); if (getViewMode() === 'grid') { - $element.attr('title', name); + $element.attr('title', name); // XXX Util.fixHTML } - var type = Messages.fm_link; + var type = Messages.fm_link; // XXX new translation key ("Link") var $type = $('', { 'class': 'cp-app-drive-element-type cp-app-drive-element-list' }).text(type); diff --git a/www/common/outer/mailbox-handlers.js b/www/common/outer/mailbox-handlers.js index bb19d2d91..88e43352b 100644 --- a/www/common/outer/mailbox-handlers.js +++ b/www/common/outer/mailbox-handlers.js @@ -238,7 +238,8 @@ define([ // content.name, content.title, content.href, content.password if (isMuted(ctx, data)) { return void cb(true); } - + // if the shared content is a 'link' then we can't use the channel to deduplicate notifications + // use href instead. var channel = content.isStatic ? content.href : Hash.hrefToHexChannelId(content.href, content.password); var parsed = Hash.parsePadUrl(content.href); var mode = parsed.hashData && parsed.hashData.mode || 'n/a'; diff --git a/www/common/outer/userObject.js b/www/common/outer/userObject.js index 97c2207e0..4051c79c1 100644 --- a/www/common/outer/userObject.js +++ b/www/common/outer/userObject.js @@ -616,13 +616,18 @@ define([ var element = elem || files[ROOT]; if (!element) { return console.error("Invalid element in root"); } var nbMetadataFolders = 0; + // caching this variables saves a lot of hashmap lookups in this loop + var static_data = files[STATIC_DATA]; + var files_data = files[FILES_DATA]; + var element_el; for (var el in element) { - if (element[el] === null) { + element_el = element[el]; + if (element_el === null) { console.error('element[%s] is null', el); delete element[el]; continue; } - if (exp.isFolderData(element[el])) { + if (exp.isFolderData(element_el)) { if (nbMetadataFolders !== 0) { debug("Multiple metadata files in folder"); delete element[el]; @@ -630,30 +635,30 @@ define([ nbMetadataFolders++; continue; } - if (!exp.isFile(element[el], true) && !exp.isFolder(element[el])) { - debug("An element in ROOT was not a folder nor a file. ", element[el]); + if (!exp.isFile(element_el, true) && !exp.isFolder(element_el)) { + debug("An element in ROOT was not a folder nor a file. ", element_el); delete element[el]; continue; } - if (exp.isFolder(element[el])) { - fixRoot(element[el]); + if (exp.isFolder(element_el)) { + fixRoot(element_el); continue; } - if (typeof element[el] === "string") { + if (typeof element_el === "string") { // We have an old file (href) which is not in filesData: add it var id = Util.createRandomInteger(); var key = Hash.createChannelId(); - files[FILES_DATA][id] = { - href: exp.cryptor.encrypt(element[el]), + files_data[id] = { + href: exp.cryptor.encrypt(element_el), filename: el }; element[key] = id; delete element[el]; } - if (typeof element[el] === "number") { - var data = files[FILES_DATA][element[el]] || files[STATIC_DATA][element[el]]; + if (typeof element_el === "number") { + var data = files_data[element_el] || static_data[element_el]; if (!data) { - debug("An element in ROOT doesn't have associated data", element[el], el); + debug("An element in ROOT doesn't have associated data", element_el, el); delete element[el]; } } @@ -862,6 +867,7 @@ define([ toClean.forEach(function (id) { spliceFileData(id); }); + // make sure that links are displayed at least once in your drive if you are going to keep them var sd = files[STATIC_DATA]; var toCleanSD = []; for (var id2 in sd) { @@ -929,7 +935,7 @@ define([ } }; var fixStaticData = function () { - if (typeof(files[STATIC_DATA]) !== "object") { + if (Util.isObject(files[STATIC_DATA])) { debug("STATIC_DATA was not an object"); files[STATIC_DATA] = {}; } diff --git a/www/teams/main.js b/www/teams/main.js index 4bf00e105..7d12126eb 100644 --- a/www/teams/main.js +++ b/www/teams/main.js @@ -24,6 +24,8 @@ define([ sframeChan.on('Q_DRIVE_USEROBJECT', function (data, cb) { if (!teamId) { return void cb({error: 'EINVAL'}); } + // a teamId of -1 bypasses guards against modifying your drive + // from the team app if (data.teamId !== -1) { data.teamId = teamId; } else { delete data.teamId; } Cryptpad.userObjectCommand(data, cb); From 6578b66ba6b6b665eb4b440f4e74b65811dcfed5 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 26 Jul 2021 13:07:23 +0530 Subject: [PATCH 20/76] convert a warning to an error --- www/checkup/main.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/www/checkup/main.js b/www/checkup/main.js index f4a40d11e..93ead1bbc 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -714,8 +714,6 @@ define([ if (isOnion(trimmedUnsafe) && isOnion(trimmedSafe)) { return void cb(true); } // otherwise expect that both inner and outer domains use HTTPS - setWarningClass(msg); - msg.appendChild(h('span', [ "Both ", code('httpUnsafeOrigin'), From 9ca3682df95dac85084d912bb5742707f56df35e Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 26 Jul 2021 14:10:32 +0530 Subject: [PATCH 21/76] fix an accidentally flipped boolean --- www/common/outer/userObject.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/outer/userObject.js b/www/common/outer/userObject.js index 4051c79c1..7108da936 100644 --- a/www/common/outer/userObject.js +++ b/www/common/outer/userObject.js @@ -935,7 +935,7 @@ define([ } }; var fixStaticData = function () { - if (Util.isObject(files[STATIC_DATA])) { + if (!Util.isObject(files[STATIC_DATA])) { debug("STATIC_DATA was not an object"); files[STATIC_DATA] = {}; } From 99c11f032e3cb131011e2bf584412f1105526358 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 26 Jul 2021 14:53:04 +0530 Subject: [PATCH 22/76] tally form votes with an increment function --- www/common/common-util.js | 4 ++++ www/form/inner.js | 22 +++++++++------------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/www/common/common-util.js b/www/common/common-util.js index 1fd78cec1..ac50a1f24 100644 --- a/www/common/common-util.js +++ b/www/common/common-util.js @@ -161,6 +161,10 @@ }; }; + Util.inc = function (map, key, val) { + map[key] = (map[key] || 0) + (typeof(val) === 'number'? val: 1); + }; + Util.find = function (map, path) { var l = path.length; for (var i = 0; i < l; i++) { diff --git a/www/form/inner.js b/www/form/inner.js index 8db1f8e16..266be125b 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -729,7 +729,7 @@ define([ var answer = answerObj.results; if (!answer || !answer.values) { return; } var values = answer.values || {}; - var res = Number(values[data]) || 0; // XXX inc function ? + var res = Number(values[data]) || 0; if (res === 1) { y++; } else if (res === 2) { m++; } }); @@ -784,7 +784,7 @@ define([ if (!data) { return; } var y = totals[data].y + ((myTotals[data] || {}).y || 0); var m = totals[data].m + ((myTotals[data] || {}).m || 0); - $c.find('.cp-form-total-yes').text(y); // XXX inc function + $c.find('.cp-form-total-yes').text(y); $c.find('.cp-form-total-maybe').text('('+m+')'); }); }; @@ -1126,8 +1126,7 @@ define([ var obj = answers[author]; var answer = obj.msg[uid]; if (!answer || !answer.trim()) { return empty++; } - count[answer] = count[answer] || 0; // XXX inc function - count[answer]++; + Util.inc(count, answer); }); Object.keys(count).forEach(function (value) { results.push(h('div.cp-form-results-type-radio-data', [ @@ -1229,8 +1228,7 @@ define([ var c = count[q_uid] = count[q_uid] || {}; var res = answer[q_uid]; if (!res || !res.trim()) { return; } - c[res] = c[res] || 0; // XXX inc function - c[res]++; + Util.inc(c, res); }); }); Object.keys(count).forEach(function (q_uid) { @@ -1340,8 +1338,7 @@ define([ var answer = obj.msg[uid]; if (!Array.isArray(answer) || !answer.length) { return empty++; } answer.forEach(function (val) { - count[val] = count[val] || 0; // XXX inc function - count[val]++; + Util.inc(count, val); }); }); Object.keys(count).forEach(function (value) { @@ -1455,9 +1452,8 @@ define([ var c = count[q_uid] = count[q_uid] || {}; var res = answer[q_uid]; if (!Array.isArray(res) || !res.length) { return; } - res.forEach(function (v) { // XXX increment function? - c[v] = c[v] || 0; - c[v]++; + res.forEach(function (v) { + Util.inc(c, v); }); }); }); @@ -1595,7 +1591,7 @@ define([ if (!Array.isArray(answer) || !answer.length) { return empty++; } answer.forEach(function (el, i) { var score = l - i; - count[el] = (count[el] || 0) + score; // XXX inc function? + Util.inc(count, el, score); }); }); var sorted = Object.keys(count).sort(function (a, b) { @@ -1974,7 +1970,7 @@ define([ value: user.name || '', placeholder: Messages.form_anonName }) - ]) + ]); $anonName = $(anonName).hide(); $anonBox.on('change', function () { if (Util.isChecked($anonBox)) { $anonName.hide(); } From 7bc6ed17b9aee94e23c422d26edb61a51c35f590 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 26 Jul 2021 14:57:28 +0530 Subject: [PATCH 23/76] update max choices input in forms ...when the maximum exceeds the number of choices --- www/form/inner.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/www/form/inner.js b/www/form/inner.js index 266be125b..210d8bd68 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -298,6 +298,7 @@ define([ del ]); $(del).click(function () { + var $block = $(el).closest('.cp-form-edit-block'); $(el).remove(); // We've just deleted an item/option so we should be under the MAX limit and // we can show the "add" button again @@ -306,6 +307,13 @@ define([ $add.show(); if (v.type === "time") { $(addMultiple).show(); } } + // decrement the max choices input when there are fewer options than the current maximum + if (maxInput) { + var inputs = $block.find('input').length; + var $maxInput = $(maxInput); + var currentMax = Number($maxInput.val()); + $maxInput.val(Math.min(inputs, currentMax)); + } }); return el; }; @@ -776,7 +784,7 @@ define([ }; refreshBest(); - if (myLine && evOnChange) { // XXX + if (myLine && evOnChange) { var updateValues = function () { totalEls.forEach(function (cell) { var $c = $(cell); @@ -2564,8 +2572,8 @@ define([ var refreshResponse = function () { $responseMsg.empty(); Messages.form_updateMsg = "Update response message"; // XXX - Messages.form_addMsg = "Add response message"; - Messages.form_responseMsg = "Add a message that will be displayed in the response page."; + Messages.form_addMsg = "Add response message"; // XXX + Messages.form_responseMsg = "Add a message that will be displayed in the response page."; // XXX var text = content.answers.msg ? Messages.form_updateMsg : Messages.form_addMsg; var btn = h('button.btn.btn-secondary', text); $(btn).click(function () { From e5558b516c16a847d911ddba7378d806511dd778 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 26 Jul 2021 15:02:48 +0530 Subject: [PATCH 24/76] guard against a typeError when drive-less users try to send a pad-burned notification --- www/common/outer/async-store.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 6aacd4a1b..30b71f1bd 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -2058,8 +2058,15 @@ define([ } catch (e) { console.error(e); } + // Tell all the owners that the pad was deleted from the server - var curvePublic = store.proxy.curvePublic; + var curvePublic; + try { + curvePublic = store.proxy.curvePublic; + } catch (err) { + console.error(err); + return; // XXX anons can't send notifications... + } m.forEach(function (obj) { var mb = JSON.parse(obj); if (mb.curvePublic === curvePublic) { return; } From 513f1531e3dc514876b811ce43ad1104bee33830 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 26 Jul 2021 15:03:02 +0530 Subject: [PATCH 25/76] remove some dead code --- www/common/toolbar.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/www/common/toolbar.js b/www/common/toolbar.js index 785d1bc7e..5b53aa9a1 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -867,10 +867,6 @@ MessengerUI, Messages, Pages) { 'class': "cp-toolbar-link-logo" }).append(UIElements.getSvgLogo()); - /*.append($('', { - //src: '/customize/images/logo_white.png?' + ApiConfig.requireConf.urlArgs - src: '/customize/favicon/main-favicon.png?' + ApiConfig.requireConf.urlArgs - }));*/ var onClick = function (e) { e.preventDefault(); if (e.ctrlKey) { From d21e79733e6ff64862d496ff5151e11b8e4daa04 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 26 Jul 2021 15:24:08 +0530 Subject: [PATCH 26/76] send feedback when self-destructing pads explode --- www/common/sframe-common-outer.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index a532863a2..575971368 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -2003,6 +2003,8 @@ define([ sframeChan.on('EV_BURN_AFTER_READING', function () { startRealtime(); + // feedback fails for users in noDrive mode + Utils.Feedback.send("BURN_AFTER_READING", Boolean(cfg.noDrive)); }); sframeChan.ready(); From ec928334d898d21f3e746ddd52376b220c0254ee Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 26 Jul 2021 15:26:23 +0530 Subject: [PATCH 27/76] don't try to pin channels with invalid lengths --- www/common/proxy-manager.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index 01c22812c..78196cf7c 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -1263,7 +1263,10 @@ define([ Array.prototype.push.apply(result, sfChannels); } - return result; + return result.filter(function (channel) { + if (typeof(channel) !== 'string') { return; } + return [32, 48].indexOf(channel.length) !== -1; + }); }; var addPad = function (Env, path, pad, cb) { From 52d5bb5ae865dddf962f61012a0e7b2f8cb97262 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 26 Jul 2021 15:28:20 +0530 Subject: [PATCH 28/76] add notes to gather feedback about the new link feature --- www/common/common-ui-elements.js | 3 +++ www/common/drive-ui.js | 2 ++ www/common/inner/share.js | 1 + www/common/notifications.js | 1 + 4 files changed, 7 insertions(+) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 6114884b2..8b01ad652 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -3048,6 +3048,7 @@ define([ var buttons = [{ name: Messages.friendRequest_later, onClick: function () { + // XXX feedback if (clicked) { return true; } clicked = true; }, @@ -3056,6 +3057,7 @@ define([ className: 'primary', name: Messages.link_open, onClick: function () { + // XXX feedback if (clicked) { return true; } clicked = true; common.openUnsafeURL(url); @@ -3067,6 +3069,7 @@ define([ onClick: function () { if (clicked) { return; } clicked = true; + // XXX feedback common.getSframeChannel().query("Q_DRIVE_USEROBJECT", { cmd: "addLink", data: { diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index cd456fd41..0e3b340a4 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -1939,6 +1939,7 @@ define([ 'class': 'cp-app-drive-element-ctime cp-app-drive-element-list' }).text(getDate(data.ctime)); $element.append($type).append($adate).append($cdate); + // XXX feedback }; var _addOwnership = function ($span, $state, data) { if (data && Array.isArray(data.owners) && data.owners.indexOf(edPublic) !== -1) { @@ -2780,6 +2781,7 @@ define([ name: n, url: u }, refresh); + // XXX feedback }, keys: [13] }); diff --git a/www/common/inner/share.js b/www/common/inner/share.js index 5225ea818..125dcb5e2 100644 --- a/www/common/inner/share.js +++ b/www/common/inner/share.js @@ -111,6 +111,7 @@ define([ if (mailbox) { // Friend if (friends[curve] && !mailbox.notifications) { return; } if (mailbox.notifications && mailbox.curvePublic) { + // XXX feedback common.mailbox.sendTo("SHARE_PAD", { href: href, isStatic: Boolean(config.static), diff --git a/www/common/notifications.js b/www/common/notifications.js index 24458420e..78c29b90f 100644 --- a/www/common/notifications.js +++ b/www/common/notifications.js @@ -115,6 +115,7 @@ define([ }; content.handler = function() { if (msg.content.isStatic) { + // XXX feedback UIElements.displayOpenLinkModal(common, { curve: msg.author, href: msg.content.href, From f178d4bebc949bae5bda3a230cf70b0c2b582f45 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 26 Jul 2021 15:51:15 +0530 Subject: [PATCH 29/76] update pending changelog --- CHANGELOG.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f98c1ea68..7dd823202 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,29 @@ +# WIP + +* links + * create links in your drive or a team drive + * share with contacts + * when you receive a link, you can "open", "store", "decide later" or dismiss from the notification dropdown + * share with a team (the link is instantly added to the team) + * store in your own drive from your team drive + * embed a link into a pad + * And you can have multiple links to the same target in one drive +* tabs in ckeditor +* fix recognition of premium user tickets in the admin support panel +* forms + * disable usage of the indexedDB cache for form results + * handle empty messages + * fix initial title with form templates + * style improvements + * guard against a typeError with dates + * in the responses page you can click on a user in the polls to get this user's answers to the other questions + * unregistered users can set their username when they don't want to answer anonymously + * improve CSV export with polls + * decrement max choices when it exceeds the number of available options +* remove unused images +* drive + * show the bread-crumb and disable the tree in anon drives + # 4.8.0 ## Goals From 403d922ddd4ceb86cbeecce9a92096824342c77b Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 26 Jul 2021 16:30:49 +0530 Subject: [PATCH 30/76] replace two XXX notes with comments --- www/common/drive-ui.js | 6 +++++- www/common/outer/async-store.js | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index 0e3b340a4..feec8543e 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -1925,7 +1925,11 @@ define([ var $name = $('', {'class': 'cp-app-drive-element-name'}).text(name); $element.append($name); if (getViewMode() === 'grid') { - $element.attr('title', name); // XXX Util.fixHTML + //console.error(name, Util.fixHTML(name)); + // this is only safe because our build of tippy sets titles as + // 'textContent' instead of innerHTML, otherwise + // we would need to use Util.fixHTML + $element.attr('title', name); } var type = Messages.fm_link; // XXX new translation key ("Link") diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 30b71f1bd..d8e558dad 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -2062,10 +2062,12 @@ define([ // Tell all the owners that the pad was deleted from the server var curvePublic; try { + // users in noDrive mode don't have a proxy and + // unregistered users don't have a curvePublic curvePublic = store.proxy.curvePublic; } catch (err) { console.error(err); - return; // XXX anons can't send notifications... + return; } m.forEach(function (obj) { var mb = JSON.parse(obj); From 812d5f7146b48a72928fd172c4e8c11168277f69 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 26 Jul 2021 18:11:45 +0530 Subject: [PATCH 31/76] disable form response message UI until it's been reviewed more --- www/form/inner.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/www/form/inner.js b/www/form/inner.js index 210d8bd68..8de8eb2c3 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -2570,10 +2570,11 @@ define([ var responseMsg = h('div.cp-form-response-msg-container'); var $responseMsg = $(responseMsg); var refreshResponse = function () { + if (true) { return; } // XXX 4.10.0 $responseMsg.empty(); - Messages.form_updateMsg = "Update response message"; // XXX - Messages.form_addMsg = "Add response message"; // XXX - Messages.form_responseMsg = "Add a message that will be displayed in the response page."; // XXX + Messages.form_updateMsg = "Update response message"; // XXX 4.10.0 + Messages.form_addMsg = "Add response message"; // XXX 4.10.0 + Messages.form_responseMsg = "Add a message that will be displayed in the response page."; // XXX 4.10.0 var text = content.answers.msg ? Messages.form_updateMsg : Messages.form_addMsg; var btn = h('button.btn.btn-secondary', text); $(btn).click(function () { @@ -2602,7 +2603,7 @@ define([ name: Messages.settings_save, onClick: function () { var v = editor.getValue(); - content.answers.msg = v.trim(0, 2000); // XXX max length? + content.answers.msg = v.trim(0, 2000); // XXX 4.10.0 max length? framework.localChange(); framework._.cpNfInner.chainpad.onSettle(function () { UI.log(Messages.saved); @@ -2628,9 +2629,9 @@ define([ } UI.openCustomModal(APP.responseModal); }); - $responseMsg.append(btn); + // $responseMsg.append(btn); // XXX 4.10.0 }; - refreshResponse(); + //refreshResponse(); // Allow anonymous answers var privacyContainer = h('div.cp-form-privacy-container'); @@ -2727,7 +2728,7 @@ define([ evOnChange.reg(refreshPublic); evOnChange.reg(refreshPrivacy); evOnChange.reg(refreshEndDate); - evOnChange.reg(refreshResponse); + //evOnChange.reg(refreshResponse); return [ endDateContainer, From 987fb696ed7e904413210f1378944fc602516f39 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 26 Jul 2021 18:12:31 +0530 Subject: [PATCH 32/76] downgrade urgency of unhandled form notes --- www/form/inner.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/www/form/inner.js b/www/form/inner.js index 8de8eb2c3..b3db8ce79 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -994,7 +994,7 @@ define([ printResults: function (answers, uid) { var results = []; var empty = 0; - Object.keys(answers).forEach(function (author) { // XXX deduplicate these? + Object.keys(answers).forEach(function (author) { // TODO deduplicate these? var obj = answers[author]; var answer = obj.msg[uid]; if (!answer || !answer.trim()) { return empty++; } @@ -1006,7 +1006,7 @@ define([ }, icon: h('i.cptools.cptools-form-text') }, - textarea: { // XXX + textarea: { defaultOpts: { maxLength: 1000 }, @@ -1060,7 +1060,7 @@ define([ printResults: function (answers, uid) { var results = []; var empty = 0; - Object.keys(answers).forEach(function (author) { // XXX deduplicate these + Object.keys(answers).forEach(function (author) { // TODO deduplicate these var obj = answers[author]; var answer = obj.msg[uid]; if (!answer || !answer.trim()) { return empty++; } From 4862e9b0ccd2f6ba78be452193c07984e4e0cb37 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 26 Jul 2021 18:14:01 +0530 Subject: [PATCH 33/76] use two translation keys for 'Link' UI in different contexts --- www/common/drive-ui.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index feec8543e..12c4431c8 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -42,8 +42,8 @@ define([ Pages) { - Messages.fm_link = "Link"; // XXX "New Link" ? - // XXX check for all occurrences of `fm_link` before changing it + Messages.fm_link_new = "New Link"; // XXX + Messages.fm_link_type = "Link"; // XXX var APP = window.APP = { editable: false, @@ -450,7 +450,7 @@ define([ 'tabindex': '-1', 'data-icon': AppConfig.applicationsIcon.link, 'data-type': 'link' - }, Messages.fm_link)), + }, Messages.fm_link_new)), ]), ]), $separator.clone()[0], @@ -1932,7 +1932,7 @@ define([ $element.attr('title', name); } - var type = Messages.fm_link; // XXX new translation key ("Link") + var type = Messages.fm_link_type; var $type = $('', { 'class': 'cp-app-drive-element-type cp-app-drive-element-list' }).text(type); @@ -2738,8 +2738,8 @@ define([ }; var showLinkModal = function () { Messages.fm_link_name = "Link name"; // XXX - Messages.fm_link_url = "URL"; - Messages.fm_link_warning = "Warning: URL size..."; + Messages.fm_link_url = "URL"; // XXX + Messages.fm_link_warning = "Warning: URL size..."; // XXX var name, url; var warning = h('div.alert.alert-warning', [ h('i.fa.fa-exclamation-triangle'), @@ -2869,7 +2869,7 @@ define([ options.push({ tag: 'a', attributes: {'class': 'cp-app-drive-new-link'}, - content: $('
    ').append(getIcon('link')).html() + Messages.fm_link + content: $('
    ').append(getIcon('link')).html() + Messages.fm_link_new }); options.push({tag: 'hr'}); } @@ -3194,7 +3194,7 @@ define([ 'cp-app-drive-element-grid' }).prepend(getIcon('link')).appendTo($container); $elementLink.append($('', {'class': 'cp-app-drive-new-name'}) - .text(Messages.fm_link)); + .text(Messages.fm_link_type)); } // Pads getNewPadTypes().forEach(function (type) { From e3150f12848ded2c83990b30c76bddecba8d030f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Benqu=C3=A9?= Date: Mon, 26 Jul 2021 14:28:55 +0100 Subject: [PATCH 34/76] Add margin above anonymous name field --- www/form/app-form.less | 1 + 1 file changed, 1 insertion(+) diff --git a/www/form/app-form.less b/www/form/app-form.less index b037efac2..41ef8ba98 100644 --- a/www/form/app-form.less +++ b/www/form/app-form.less @@ -248,6 +248,7 @@ text-align: center; margin: 20px 0 30px 0; .cp-form-anon-answer-input { + margin-top: 20px; display: flex; white-space: nowrap; align-items: center; From 0534a69f3d5ee4aaff03675a15413dc0909d468d Mon Sep 17 00:00:00 2001 From: Weblate Date: Mon, 26 Jul 2021 15:52:02 +0200 Subject: [PATCH 35/76] Translated using Weblate (Japanese) Currently translated at 99.9% (1375 of 1376 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 100.0% (1373 of 1373 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 99.9% (1371 of 1372 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 100.0% (1370 of 1370 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ --- www/common/translations/messages.ja.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index bab839f09..767ff939a 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -1368,5 +1368,12 @@ "reminder_time": "{0}が今日の{1}にあります", "form_answerWarning": "本人であることが確認されていません", "team_leaveOwner": "チームから退出する前に、オーナーの役割から降格してください。チームには最低1人以上のオーナーが必要です。あなたが唯一のオーナーの場合は、別のオーナーを追加してください。", - "form_exportCSV": "CSVにエクスポート" + "form_exportCSV": "CSVにエクスポート", + "fm_link_new": "新しいリンク", + "notification_openLink": "{1}からリンク「 {0}」を受け取りました:", + "fm_link_type": "リンク", + "fm_link_url": "URL", + "fm_link_name": "リンク名", + "form_anonName": "あなたの名前", + "notification_linkShared": "{0}があなたとリンクを共有しました: {1}" } From b0f7a9488c63e18e2af2cc08d569d54a40f35d0d Mon Sep 17 00:00:00 2001 From: Weblate Date: Mon, 26 Jul 2021 15:52:03 +0200 Subject: [PATCH 36/76] Translated using Weblate (English) Currently translated at 100.0% (1376 of 1376 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1375 of 1375 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1374 of 1374 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1373 of 1373 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1372 of 1372 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1371 of 1371 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1370 of 1370 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1369 of 1369 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ --- www/common/translations/messages.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index 29f415755..e3b53ed4f 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -1368,5 +1368,13 @@ "admin_purpose_business": "For a business or commercial organization", "admin_instancePurposeHint": "Why do you run this instance? Your answer will be used to inform the development roadmap if your telemetry is enabled.", "team_leaveOwner": "Please demote yourself from the owner role before leaving the team. Note that teams must have at least one owner, please add one before proceeding if you are currently the only owner.", - "form_exportCSV": "Export to CSV" + "form_exportCSV": "Export to CSV", + "notification_openLink": "You've received a link {0} from {1}:", + "fm_link_new": "New Link", + "fm_link_type": "Link", + "fm_link_name": "Link name", + "fm_link_url": "URL", + "fm_link_name_placeholder": "My link", + "notification_linkShared": "{0} has shared a link with you: {1}", + "form_anonName": "Your name" } From fc64913392a5ee043d93885887faa4c7692df6ef Mon Sep 17 00:00:00 2001 From: Weblate Date: Mon, 26 Jul 2021 15:53:25 +0200 Subject: [PATCH 37/76] Translated using Weblate (English) Currently translated at 100.0% (1377 of 1377 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ --- www/common/translations/messages.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index e3b53ed4f..4869493a3 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -1376,5 +1376,6 @@ "fm_link_url": "URL", "fm_link_name_placeholder": "My link", "notification_linkShared": "{0} has shared a link with you: {1}", - "form_anonName": "Your name" + "form_anonName": "Your name", + "form_answerAs": "Answer as" } From 55b00409b3612626a05f5bd4416ff635e3d95717 Mon Sep 17 00:00:00 2001 From: Weblate Date: Mon, 26 Jul 2021 15:53:26 +0200 Subject: [PATCH 38/76] Translated using Weblate (Japanese) Currently translated at 100.0% (1376 of 1376 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ --- www/common/translations/messages.ja.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index 767ff939a..76c85b5a1 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -1375,5 +1375,6 @@ "fm_link_url": "URL", "fm_link_name": "リンク名", "form_anonName": "あなたの名前", - "notification_linkShared": "{0}があなたとリンクを共有しました: {1}" + "notification_linkShared": "{0}があなたとリンクを共有しました: {1}", + "fm_link_name_placeholder": "あなたのリンク" } From c35ccfc6bbd0985f1b3c1cee912df2bb9c1bb32a Mon Sep 17 00:00:00 2001 From: Weblate Date: Mon, 26 Jul 2021 16:05:20 +0200 Subject: [PATCH 39/76] Translated using Weblate (English) Currently translated at 100.0% (1378 of 1378 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1378 of 1378 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ --- www/common/translations/messages.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index 4869493a3..012f7b5c5 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -1278,7 +1278,7 @@ "form_submit": "Submit", "form_update": "Update", "form_reset": "Reset", - "form_sent": "Sent", + "form_sent": "Your response was submitted", "form_delete": "Delete", "form_submitWarning": "Submit anyway", "form_updateWarning": "Update anyway", @@ -1377,5 +1377,6 @@ "fm_link_name_placeholder": "My link", "notification_linkShared": "{0} has shared a link with you: {1}", "form_anonName": "Your name", - "form_answerAs": "Answer as" + "form_answerAs": "Answer as", + "fm_link_warning": "Warning: the URL exceeds 200 characters" } From 126a3fff46fe690b71eddba5c58f22b5a3eade1e Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 26 Jul 2021 19:56:11 +0530 Subject: [PATCH 40/76] remove hardcoded translations and rework link name placeholder behaviour --- www/common/drive-ui.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index 12c4431c8..21a2337a7 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -42,9 +42,6 @@ define([ Pages) { - Messages.fm_link_new = "New Link"; // XXX - Messages.fm_link_type = "Link"; // XXX - var APP = window.APP = { editable: false, online: false, @@ -2737,21 +2734,23 @@ define([ $input.click(); }; var showLinkModal = function () { - Messages.fm_link_name = "Link name"; // XXX - Messages.fm_link_url = "URL"; // XXX - Messages.fm_link_warning = "Warning: URL size..."; // XXX var name, url; var warning = h('div.alert.alert-warning', [ h('i.fa.fa-exclamation-triangle'), h('span', Messages.fm_link_warning) ]); var content = h('p', [ - warning, h('label', {for: 'cp-app-drive-link-name'}, Messages.fm_link_name), - name = h('input#cp-app-drive-link-name', { autocomplete: 'off' }), + name = h('input#cp-app-drive-link-name', { autocomplete: 'off', placeholder: Messages.fm_link_name_placeholder }), h('label', {for: 'cp-app-drive-link-url'}, Messages.fm_link_url), - url = h('input#cp-app-drive-link-url', { type: 'url', autocomplete: 'off' }) + url = h('input#cp-app-drive-link-url', { type: 'url', autocomplete: 'off', placeholder: Messages.form_input_ph_url }), + warning, ]); + var setNamePlaceholder = function (val) { + val = val.replace(/https*:\/\//, '').replace(/#.*$/, '').slice(0, 16); + name.setAttribute('placeholder', val) + }; + var $warning = $(warning).hide(); var $url = $(url).on('change keypress keyup keydown', function () { var v = $url.val().trim(); @@ -2759,6 +2758,7 @@ define([ $warning.show(); return; } + setNamePlaceholder(v); $warning.hide(); }); var buttons = [{ @@ -2773,7 +2773,8 @@ define([ iconClass: '.fa.fa-plus', name: Messages.tag_add, onClick: function () { - var n = $(name).val().trim(); + var $name = $(name); + var n = $name.val().trim() || $name.attr('placeholder'); var u = $url.val().trim(); if (!n || !u) { return true; } if (!Util.isValidURL(u)) { From 4e900b18cf5c57060ea8ae996161690d7d1ab25d Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 26 Jul 2021 19:56:49 +0530 Subject: [PATCH 41/76] use more specific 'export to CSV' translation in forms --- www/form/inner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/form/inner.js b/www/form/inner.js index b3db8ce79..2a04eedd2 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -1774,7 +1774,7 @@ define([ var controls = h('div.cp-form-creator-results-controls'); var $controls = $(controls).appendTo($container); - var exportButton = h('button.btn.btn-secondary', Messages.exportButton); // XXX form_exportCSV; + var exportButton = h('button.btn.btn-secondary', Messages.form_exportCSV); var exportCSV = h('div.cp-form-creator-results-export', exportButton); $(exportCSV).appendTo($container); var results = h('div.cp-form-creator-results-content'); From 4f5a04101050e43a9a7c167805a72eabddc1158d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Benqu=C3=A9?= Date: Mon, 26 Jul 2021 15:26:51 +0100 Subject: [PATCH 42/76] Style username in poll results table --- www/form/app-form.less | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/www/form/app-form.less b/www/form/app-form.less index 41ef8ba98..1354cacca 100644 --- a/www/form/app-form.less +++ b/www/form/app-form.less @@ -681,7 +681,11 @@ &.cp-clickable { cursor: pointer; &:hover { - transform: scale(1.1); + color: @cryptpad_color_link; + &::after { + font-family: FontAwesome; + content: "\00a0\f06e"; + } } } } From 04a616f87d43f85e7cd1347565476a770446f158 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Benqu=C3=A9?= Date: Mon, 26 Jul 2021 15:38:21 +0100 Subject: [PATCH 43/76] Add margin to individual response list - prevents response title to be mixed up with first question --- www/form/app-form.less | 1 + 1 file changed, 1 insertion(+) diff --git a/www/form/app-form.less b/www/form/app-form.less index 1354cacca..60da1daff 100644 --- a/www/form/app-form.less +++ b/www/form/app-form.less @@ -548,6 +548,7 @@ .cp-form-individual { background: @cp_form-bg1; padding: 10px; + margin-bottom: 20px; & > *:not(:last-child) { margin-right: 10px; } From 854a635c5f8abda45b415828d42888bdb6b929f7 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 27 Jul 2021 03:40:03 +0530 Subject: [PATCH 44/76] remove hardcoded translations and defer non-blocking issues till the next release --- lib/env.js | 2 +- www/common/common-ui-elements.js | 16 ++++++++++++---- www/common/drive-ui.js | 3 +-- www/common/inner/share.js | 1 - www/common/notifications.js | 2 -- www/common/outer/cache-store.js | 2 +- www/convert/inner.js | 4 ++-- www/form/inner.js | 2 -- www/form/main.js | 2 +- 9 files changed, 18 insertions(+), 16 deletions(-) diff --git a/lib/env.js b/lib/env.js index 3d58f11f7..4db282d77 100644 --- a/lib/env.js +++ b/lib/env.js @@ -123,7 +123,7 @@ module.exports.create = function (config) { maxWorkers: config.maxWorkers, disableIntegratedTasks: config.disableIntegratedTasks || false, - disableIntegratedEviction: typeof(config.disableIntegratedEviction) === 'undefined'? true: config.disableIntegratedEviction, // XXX false, + disableIntegratedEviction: typeof(config.disableIntegratedEviction) === 'undefined'? true: config.disableIntegratedEviction, // XXX 4.10.0 false, lastEviction: +new Date(), evictionReport: {}, commandTimers: {}, diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 8b01ad652..eba151551 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -3034,9 +3034,18 @@ define([ var name = Util.fixHTML(data.title); var url = data.href; var user = data.name; - Messages.notification_openLink = "You've received a link {0} from {1}:"; // XXX - Messages.link_open = "Open URL"; - Messages.link_store = "Store link in drive"; + //Messages.link_open = "Open URL"; + // openLinkInNewTab ("Open Link in New Tab") + // fc_open ("Open") + // share_linkOpen ("Preview") + // resources_openInNewTab ("Open it in a new tab") + Messages.link_open = Messages.fc_open; // XXX 4.10.0 + + //Messages.link_store = "Store link in drive"; + // toolbar_storeInDrive ? ("Store in CryptDrive") + // autostore_store ? ("Store") + Messages.link_store = Messages.toolbar_storeInDrive; // XXX 4.10.0 + var content = h('div', [ UI.setHTML(h('p'), Messages._getKey('notification_openLink', [name, user])), @@ -3069,7 +3078,6 @@ define([ onClick: function () { if (clicked) { return; } clicked = true; - // XXX feedback common.getSframeChannel().query("Q_DRIVE_USEROBJECT", { cmd: "addLink", data: { diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index 21a2337a7..78618f7ed 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -1940,7 +1940,6 @@ define([ 'class': 'cp-app-drive-element-ctime cp-app-drive-element-list' }).text(getDate(data.ctime)); $element.append($type).append($adate).append($cdate); - // XXX feedback }; var _addOwnership = function ($span, $state, data) { if (data && Array.isArray(data.owners) && data.owners.indexOf(edPublic) !== -1) { @@ -2778,7 +2777,7 @@ define([ var u = $url.val().trim(); if (!n || !u) { return true; } if (!Util.isValidURL(u)) { - // XXX add style for invalid input? input:invalid + // XXX 4.10.0 add style for invalid input? input:invalid UI.warn(Messages.error); return true; } diff --git a/www/common/inner/share.js b/www/common/inner/share.js index 125dcb5e2..5225ea818 100644 --- a/www/common/inner/share.js +++ b/www/common/inner/share.js @@ -111,7 +111,6 @@ define([ if (mailbox) { // Friend if (friends[curve] && !mailbox.notifications) { return; } if (mailbox.notifications && mailbox.curvePublic) { - // XXX feedback common.mailbox.sendTo("SHARE_PAD", { href: href, isStatic: Boolean(config.static), diff --git a/www/common/notifications.js b/www/common/notifications.js index 78c29b90f..83052ff68 100644 --- a/www/common/notifications.js +++ b/www/common/notifications.js @@ -92,7 +92,6 @@ define([ (type === 'file' ? 'notification_fileShared' : // Msg.notification_fileSharedTeam 'notification_padShared'); // Msg.notification_padSharedTeam - Messages.notification_linkShared = "{0} has shared a link with you: {1}"; // XXX if (msg.content.isStatic) { key = 'notification_linkShared'; // Msg.notification_linkShared; } @@ -115,7 +114,6 @@ define([ }; content.handler = function() { if (msg.content.isStatic) { - // XXX feedback UIElements.displayOpenLinkModal(common, { curve: msg.author, href: msg.content.href, diff --git a/www/common/outer/cache-store.js b/www/common/outer/cache-store.js index 514e18ab7..93bc0d0c6 100644 --- a/www/common/outer/cache-store.js +++ b/www/common/outer/cache-store.js @@ -97,7 +97,7 @@ define([ var checkCheckpoints = function (array) { if (!Array.isArray(array)) { return; } // Keep the last 100 messages - if (array.length > 100) { // XXX + if (array.length > 100) { // XXX 4.10.0 array.splice(0, array.length - 100); } // Remove every message before the first checkpoint diff --git a/www/convert/inner.js b/www/convert/inner.js index cdcf745ca..ba9870ccf 100644 --- a/www/convert/inner.js +++ b/www/convert/inner.js @@ -192,8 +192,8 @@ define([ }, }; - Messages.convertPage = "Convert"; // XXX - Messages.convert_hint = "Pick the file you want to convert. The list of output format will be visible afterward."; // XXX + Messages.convertPage = "Convert"; // XXX 4.10.0 + Messages.convert_hint = "Pick the file you want to convert. The list of output format will be visible afterward."; // XXX 4.10.0 var createToolbar = function () { var displayed = ['useradmin', 'newpad', 'limit', 'pageTitle', 'notifications']; diff --git a/www/form/inner.js b/www/form/inner.js index 2a04eedd2..1b555be5d 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -1970,8 +1970,6 @@ define([ $(cbox).hide().find('input').attr('disabled', 'disabled').prop('checked', false); } } else { - Messages.form_anonName = "Your username"; // XXX - Messages.form_answerAs = "Answer as"; // XXX anonName = h('div.cp-form-anon-answer-input', [ Messages.form_answerAs, h('input', { diff --git a/www/form/main.js b/www/form/main.js index b25a4b21a..de2c311ef 100644 --- a/www/form/main.js +++ b/www/form/main.js @@ -176,7 +176,7 @@ define([ validateKey: keys.secondaryValidateKey, owners: [myKeys.edPublic], crypto: crypto, - //Cache: Utils.Cache // XXX + //Cache: Utils.Cache // XXX 4.10.0 }; var results = {}; config.onError = function (info) { From 9c373377cfa44fe428c8a4f351930166475afcb8 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 27 Jul 2021 03:40:48 +0530 Subject: [PATCH 45/76] send feedback for UI related to the new link functionality --- www/common/common-ui-elements.js | 5 +++-- www/common/drive-ui.js | 2 +- www/common/inner/share.js | 4 ++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index eba151551..99d506347 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -3057,19 +3057,19 @@ define([ var buttons = [{ name: Messages.friendRequest_later, onClick: function () { - // XXX feedback if (clicked) { return true; } clicked = true; + Feedback.send('LINK_RECEIVED_LATER'); }, keys: [27] }, { className: 'primary', name: Messages.link_open, onClick: function () { - // XXX feedback if (clicked) { return true; } clicked = true; common.openUnsafeURL(url); + Feedback.send("LINK_RECEIVED_OPEN"); }, keys: [13] }, { @@ -3088,6 +3088,7 @@ define([ }, function () { modal.closeModal(); dismiss(); + Feedback.send("LINK_RECEIVED_STORE"); }); return true; }, diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index 78618f7ed..82cabec8f 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -2785,7 +2785,7 @@ define([ name: n, url: u }, refresh); - // XXX feedback + Feedback.send("LINK_CREATED"); }, keys: [13] }); diff --git a/www/common/inner/share.js b/www/common/inner/share.js index 5225ea818..4bcf0d621 100644 --- a/www/common/inner/share.js +++ b/www/common/inner/share.js @@ -124,6 +124,9 @@ define([ channel: mailbox.notifications, curvePublic: mailbox.curvePublic }); + if (config.static) { + Feedback.send("LINK_SHARED_WITH_CONTACT"); + } return; } } @@ -154,6 +157,7 @@ define([ }, function () { UI.log(Messages.saved); }); + Feedback.send("LINK_ADDED_TO_DRIVE"); return; } sframeChan.query('Q_STORE_IN_TEAM', { From ea6d5e8876f008aedbf1956de167756e2de4819e Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 27 Jul 2021 01:23:51 +0200 Subject: [PATCH 46/76] Translated using Weblate (Japanese) Currently translated at 99.8% (1376 of 1378 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ --- www/common/translations/messages.ja.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index 76c85b5a1..83f22925b 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -1376,5 +1376,6 @@ "fm_link_name": "リンク名", "form_anonName": "あなたの名前", "notification_linkShared": "{0}があなたとリンクを共有しました: {1}", - "fm_link_name_placeholder": "あなたのリンク" + "fm_link_name_placeholder": "あなたのリンク", + "fm_link_warning": "注意:URLが200字を超えています" } From 9258d21ef0a66a39df417e18949cb6e869eec705 Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 27 Jul 2021 01:23:51 +0200 Subject: [PATCH 47/76] Translated using Weblate (English) Currently translated at 100.0% (1379 of 1379 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ --- www/common/translations/messages.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index 012f7b5c5..ae5f1e0a5 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -1378,5 +1378,6 @@ "notification_linkShared": "{0} has shared a link with you: {1}", "form_anonName": "Your name", "form_answerAs": "Answer as", - "fm_link_warning": "Warning: the URL exceeds 200 characters" + "fm_link_warning": "Warning: the URL exceeds 200 characters", + "fm_link_invalid": "Invalid URL" } From 3eb2e77ed8f72e2b870f8e9a1f00c573650a15b5 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 27 Jul 2021 05:16:52 +0530 Subject: [PATCH 48/76] update changelog --- CHANGELOG.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dd823202..3c5ca97fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,9 +20,28 @@ * unregistered users can set their username when they don't want to answer anonymously * improve CSV export with polls * decrement max choices when it exceeds the number of available options + * render form results if possible when the form is closed and you have answered + * shuffle form options to limit bias in results * remove unused images * drive * show the bread-crumb and disable the tree in anon drives +* checkup + * http:// for safe/unsafe origin is now an error unless used for an onion or localhost + * and only if you are accessing the test via localhost.. to catch all those instances using localhost on prod config +* feedback keys + * `LINK_RECEIVED_LATER` + * `LINK_RECEIVED_OPEN` + * `LINK_RECEIVED_STORE` + * `LINK_CREATED` + * `LINK_SHARED_WITH_CONTACT` + * `LINK_ADDED_TO_DRIVE` + * `BURN_AFTER_READING` +* teams + * guard against a typeError when initializing +* general + * don't try to pin channels with invalid lengths + * slight optimization when initializing your drive + * Lithuanian translation in progress # 4.8.0 From 921da962d0d22b0dd3280afa92ad324b45a33b65 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 27 Jul 2021 05:18:39 +0530 Subject: [PATCH 49/76] narrow exceptions for use of localhost in checkup --- www/checkup/main.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/www/checkup/main.js b/www/checkup/main.js index 93ead1bbc..90c16a29a 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -705,9 +705,13 @@ define([ var isOnion = function (host) { return /\.onion$/.test(host); }; + var isLocalhost = function (host) { + return /^http:\/\/localhost/.test(host); + }; + assert(function (cb, msg) { // provide an exception for development instances - if (/http:\/\/localhost/.test(trimmedUnsafe)) { return void cb(true); } + if (isLocalhost(trimmedUnsafe) && isLocalhost(window.location.href)) { return void cb(true); } // if both the main and sandbox domains are onion addresses // then the HTTPS requirement is unnecessary From 45b58d622d47b60b8787a10d8be83716ae97e09a Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 27 Jul 2021 05:19:35 +0530 Subject: [PATCH 50/76] rewrite a switch statement as a concise lookup table --- www/common/proxy-manager.js | 51 ++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index 78196cf7c..d6492c68c 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -1045,39 +1045,32 @@ define([ Env.onSync(cb); }; + var COMMANDS = { + move: _move, + restore: _restore, + addFolder: _addFolder, + addSharedFolder: _addSharedFolder, + addLink: _addLink, + restoreSharedFolder: _restoreSharedFolder, + convertFolderToSharedFolder: _convertFolderToSharedFolder, + delete: _delete, + deleteOwned: _deleteOwned, + emptyTrash: _emptyTrash, + rename: _rename, + setFolderData: _setFolderData, + updateStaticAccess: _updateStaticAccess, + }; + var onCommand = function (Env, cmdData, cb) { var cmd = cmdData.cmd; var data = cmdData.data || {}; - switch (cmd) { - case 'move': - _move(Env, data, cb); break; - case 'restore': - _restore(Env, data, cb); break; - case 'addFolder': - _addFolder(Env, data, cb); break; - case 'addSharedFolder': - _addSharedFolder(Env, data, cb); break; - case 'addLink': - _addLink(Env, data, cb); break; - case 'restoreSharedFolder': - _restoreSharedFolder(Env, data, cb); break; - case 'convertFolderToSharedFolder': - _convertFolderToSharedFolder(Env, data, cb); break; - case 'delete': - _delete(Env, data, cb); break; - case 'deleteOwned': - _deleteOwned(Env, data, cb); break; - case 'emptyTrash': - _emptyTrash(Env, data, cb); break; - case 'rename': - _rename(Env, data, cb); break; - case 'setFolderData': - _setFolderData(Env, data, cb); break; - case 'updateStaticAccess': - _updateStaticAccess(Env, data, cb); break; - default: - cb(); + var method = COMMANDS[cmd]; + + if (typeof(method) === 'function') { + return void method(Env, data, cb); } + // if the command was not handled then call back + cb(); }; // Set the value everywhere the given pad is stored (main and shared folders) From 32027f09d6c4b89398ea6d965cda5906255b2703 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 27 Jul 2021 05:21:05 +0530 Subject: [PATCH 51/76] refine link name placeholder suggestion and provide a more descriptive error message --- www/common/drive-ui.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index 82cabec8f..15558cf18 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -2745,9 +2745,15 @@ define([ url = h('input#cp-app-drive-link-url', { type: 'url', autocomplete: 'off', placeholder: Messages.form_input_ph_url }), warning, ]); + + var protocolPattern = /https*:\/\//; + var fragmentPattern = /#.*$/; var setNamePlaceholder = function (val) { - val = val.replace(/https*:\/\//, '').replace(/#.*$/, '').slice(0, 16); - name.setAttribute('placeholder', val) + var temp = val.replace(protocolPattern, '').replace(fragmentPattern, '').trim().slice(0, 48); + if (!protocolPattern.test(val) || !temp) { + temp = Messages.fm_link_name_placeholder; + } + name.setAttribute('placeholder', temp); }; var $warning = $(warning).hide(); @@ -2778,7 +2784,7 @@ define([ if (!n || !u) { return true; } if (!Util.isValidURL(u)) { // XXX 4.10.0 add style for invalid input? input:invalid - UI.warn(Messages.error); + UI.warn(Messages.fm_link_invalid); return true; } manager.addLink(currentPath, { From 7916f36007e1079846a503fc0da63626b64294a5 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 27 Jul 2021 05:27:05 +0530 Subject: [PATCH 52/76] update version string to 4.9.0 --- customize.dist/pages.js | 2 +- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/customize.dist/pages.js b/customize.dist/pages.js index 18632f6ea..18d65c680 100644 --- a/customize.dist/pages.js +++ b/customize.dist/pages.js @@ -105,7 +105,7 @@ define([ var imprintUrl = AppConfig.imprint && (typeof(AppConfig.imprint) === "boolean" ? '/imprint.html' : AppConfig.imprint); - Pages.versionString = "v4.8.0"; + Pages.versionString = "v4.9.0"; // used for the about menu diff --git a/package-lock.json b/package-lock.json index 4d7992f82..42136e238 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "cryptpad", - "version": "4.8.0", + "version": "4.9.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 9e18f05f0..68a315891 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "cryptpad", "description": "realtime collaborative visual editor with zero knowlege server", - "version": "4.8.0", + "version": "4.9.0", "license": "AGPL-3.0+", "repository": { "type": "git", From 673ed629d662b5f6ed6628e3ace140e99bddb866 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 27 Jul 2021 17:14:53 +0530 Subject: [PATCH 53/76] update changelog for 4.9.0 --- CHANGELOG.md | 86 +++++++++++++++++++++++++--------------------------- 1 file changed, 42 insertions(+), 44 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c5ca97fa..26dc534d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,47 +1,45 @@ -# WIP - -* links - * create links in your drive or a team drive - * share with contacts - * when you receive a link, you can "open", "store", "decide later" or dismiss from the notification dropdown - * share with a team (the link is instantly added to the team) - * store in your own drive from your team drive - * embed a link into a pad - * And you can have multiple links to the same target in one drive -* tabs in ckeditor -* fix recognition of premium user tickets in the admin support panel -* forms - * disable usage of the indexedDB cache for form results - * handle empty messages - * fix initial title with form templates - * style improvements - * guard against a typeError with dates - * in the responses page you can click on a user in the polls to get this user's answers to the other questions - * unregistered users can set their username when they don't want to answer anonymously - * improve CSV export with polls - * decrement max choices when it exceeds the number of available options - * render form results if possible when the form is closed and you have answered - * shuffle form options to limit bias in results -* remove unused images -* drive - * show the bread-crumb and disable the tree in anon drives -* checkup - * http:// for safe/unsafe origin is now an error unless used for an onion or localhost - * and only if you are accessing the test via localhost.. to catch all those instances using localhost on prod config -* feedback keys - * `LINK_RECEIVED_LATER` - * `LINK_RECEIVED_OPEN` - * `LINK_RECEIVED_STORE` - * `LINK_CREATED` - * `LINK_SHARED_WITH_CONTACT` - * `LINK_ADDED_TO_DRIVE` - * `BURN_AFTER_READING` -* teams - * guard against a typeError when initializing -* general - * don't try to pin channels with invalid lengths - * slight optimization when initializing your drive - * Lithuanian translation in progress +# 4.9.0 + +## Goals and announcements + +We allocated most of this release cycle towards a schedule of one-on-one user interviews and some broad usage studies leveraging our new Form app. The remainder of our time was spent on some minor improvements. We'll continue at a slightly slower pace of implementation for the coming weeks while we complete our scheduled interviews and take some much-needed vacations. + +## Update notes + +It appears our promotion of the checkup page through our recent release notes and the inclusion of a link to it from the instance admin have been moderately successful. We've observed that more instance admins are noticing and fixing some common configuration issues. + +This release features some minor changes to one instance configuration test which incorrectly provided an exemption for the use of `http://localhost:3000` as an `httpUnsafeOrigin` value. This exemption was provided because it's valid for local development, however, it suppressed errors when this configuration was used for production instances where it could cause a variety of problems. As usual, we recommend checking your instance's admin page after updating to confirm that you are passing the latest tests. Information about the checkup page is included in [our documentation](https://docs.cryptpad.fr/en/admin_guide/admin_panel.html#network). + +To update from 4.8.0 to 4.9.0: + +1. Stop your server +2. Get the latest code with git +3. Install the latest dependencies with `bower update` and `npm i` +4. Restart your server +5. Confirm that your instance is passing all the tests included on the `/checkup/` page + +## Features + +* We've added the ability to store URLs in user and team drives as requested in a private support ticket and [this issue](https://github.com/xwiki-labs/cryptpad/issues/732). Links can be shared directly with contacts. Unlike pads, links are not collaborative objects, so updating a link's name will not update the entry in another user's drive if you've already shared it with them. Links are integrated into our apps' _insert_ menu to facilitate quick insertion of links you've stored into your documents. We're interested in measuring how this functionality is used in practice so we can decide whether it's worth spending more time on it, so we've added some telemetry to measure (in aggregate) how often its components are used. We anonymize IP addresses in the logs for CryptPad.fr, but as always, you can disable telemetry via your settings panel. +* Our rich text editor now supports indentation with the tab key, as per [this ticket](https://github.com/xwiki-labs/cryptpad/issues/634). +* Forms received another round of improvements to styles, workflows, and some basic survey functionality to yield more accurate results. + * Ordered lists are now shuffled for each survey participant so that their initial order has less effect on the final results. + * CSV export now uses a layout that makes poll options easier to read. + * Unregistered users can now add a name to their response. + * Form results are displayed automatically (when available) to those who have answered. + * Authors and auditors can now click on some types of answers to jump directly to other answers from the same user. +* Users with very large drives might notice that their account loads slightly faster now, due to some minor optimizations in an integrity check that the client performs when loading accounts. + +## Bugs + +* We've added a guard against a type error that could be triggered when loading teams under certain rare conditions. +* Unregistered users' drives now show the "bread-crumb" UI for navigating between folders when viewing a shared folder in read-only mode. We've also suppressed the "Files" button for displaying the tree view which was non-functional for such users. +* A change in the format of support tickets caused tickets recently created by premium users to not be recognized as such. We've fixed the categorization in the admin panel's support ticket view. +* We've fixed a number of minor issues with forms: + * The maximum number of selectable choices for checkbox questions can no longer exceed the number of available choices. + * We guard against a type error that could occur when parsing dates. + * Forms imported from templates now have their initial title corrected. + * We've disabled the use of our indexedDB caching system for form results, since it was quietly dropping older responses when more than 100 responses had been submitted. We plan to re-enable caching for results once we've updated the eviction metric to better handle the response format. # 4.8.0 From dc74df0ac505717be69b70efdefb4b341e897e97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Benqu=C3=A9?= Date: Tue, 27 Jul 2021 16:31:05 +0100 Subject: [PATCH 54/76] Minor edits to the changelog --- CHANGELOG.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26dc534d9..23f48dc01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ We allocated most of this release cycle towards a schedule of one-on-one user in It appears our promotion of the checkup page through our recent release notes and the inclusion of a link to it from the instance admin have been moderately successful. We've observed that more instance admins are noticing and fixing some common configuration issues. -This release features some minor changes to one instance configuration test which incorrectly provided an exemption for the use of `http://localhost:3000` as an `httpUnsafeOrigin` value. This exemption was provided because it's valid for local development, however, it suppressed errors when this configuration was used for production instances where it could cause a variety of problems. As usual, we recommend checking your instance's admin page after updating to confirm that you are passing the latest tests. Information about the checkup page is included in [our documentation](https://docs.cryptpad.fr/en/admin_guide/admin_panel.html#network). +This release features some minor changes to one instance configuration test which incorrectly provided an exemption for the use of `http://localhost:3000` as an `httpUnsafeOrigin` value. This exemption was provided because this value is valid for local development. However, it suppressed errors when this configuration was used for production instances where it could cause a variety of problems. As usual, we recommend checking your instance's admin page after updating to confirm that you are passing the latest tests. Information about the checkup page is included in [our documentation](https://docs.cryptpad.fr/en/admin_guide/admin_panel.html#network). To update from 4.8.0 to 4.9.0: @@ -20,14 +20,14 @@ To update from 4.8.0 to 4.9.0: ## Features -* We've added the ability to store URLs in user and team drives as requested in a private support ticket and [this issue](https://github.com/xwiki-labs/cryptpad/issues/732). Links can be shared directly with contacts. Unlike pads, links are not collaborative objects, so updating a link's name will not update the entry in another user's drive if you've already shared it with them. Links are integrated into our apps' _insert_ menu to facilitate quick insertion of links you've stored into your documents. We're interested in measuring how this functionality is used in practice so we can decide whether it's worth spending more time on it, so we've added some telemetry to measure (in aggregate) how often its components are used. We anonymize IP addresses in the logs for CryptPad.fr, but as always, you can disable telemetry via your settings panel. -* Our rich text editor now supports indentation with the tab key, as per [this ticket](https://github.com/xwiki-labs/cryptpad/issues/634). +* We've added the ability to store URLs in user and team drives as requested in a private support ticket and [this issue](https://github.com/xwiki-labs/cryptpad/issues/732). Links can be shared directly with contacts. Unlike pads, links are not collaborative objects, so updating a link's name will not update the entry in another user's drive if you've already shared it with them. Links are integrated into our apps' _insert_ menu to facilitate quick insertion of links you've stored into your documents. We're interested in measuring how this functionality is used in practice so we can decide whether it's worth spending more time on it. We have added some telemetry to measure (in aggregate) how often its components are used. We anonymize IP addresses in the logs for CryptPad.fr, but as always, you can disable telemetry via your settings panel. +* Our rich text editor now supports indentation with the tab key, as per [issue #634](https://github.com/xwiki-labs/cryptpad/issues/634). * Forms received another round of improvements to styles, workflows, and some basic survey functionality to yield more accurate results. * Ordered lists are now shuffled for each survey participant so that their initial order has less effect on the final results. - * CSV export now uses a layout that makes poll options easier to read. + * CSV export now uses one column for each option in polls, making them easier to read. * Unregistered users can now add a name to their response. * Form results are displayed automatically (when available) to those who have answered. - * Authors and auditors can now click on some types of answers to jump directly to other answers from the same user. + * Authors and auditors can now click on usernames in polls to jump directly to other answers from the same user. * Users with very large drives might notice that their account loads slightly faster now, due to some minor optimizations in an integrity check that the client performs when loading accounts. ## Bugs From 4fe5b11370a893f017741d4789831c4a49cf4c2c Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 27 Jul 2021 17:47:04 +0200 Subject: [PATCH 55/76] Translated using Weblate (French) Currently translated at 100.0% (1379 of 1379 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/fr/ --- www/common/translations/messages.fr.json | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/www/common/translations/messages.fr.json b/www/common/translations/messages.fr.json index 1ea01009b..5974401e7 100644 --- a/www/common/translations/messages.fr.json +++ b/www/common/translations/messages.fr.json @@ -1315,7 +1315,7 @@ "form_updateWarning": "Mettre à jour avec erreurs", "form_submitWarning": "Envoyer avec erreurs", "form_delete": "Supprimer", - "form_sent": "Envoyé", + "form_sent": "Votre réponse a été envoyée", "form_reset": "Effacer", "form_update": "Mettre à jour", "form_submit": "Envoyer", @@ -1368,5 +1368,16 @@ "admin_purpose_business": "Usage en entreprise", "admin_instancePurposeHint": "À quel usage cette instance est-elle destinée ? Votre réponse sera utilisée pour définir la planification de nouvelles fonctionnalités (si votre télémétrie est activée).", "team_leaveOwner": "Veuillez vous rétrograder de votre rôle de propriétaire avant de quitter l'équipe. Notez que les équipes doivent avoir au moins un propriétaire, veuillez en ajouter un autre avant de poursuivre si vous êtes actuellement le seul propriétaire.", - "form_exportCSV": "Exporter en CSV" + "form_exportCSV": "Exporter en CSV", + "fm_link_invalid": "URL invalide", + "fm_link_warning": "Attention : l'URL dépasse 200 caractères", + "form_answerAs": "Répondre en tant que", + "form_anonName": "Votre nom", + "notification_linkShared": "{0} a partagé un lien avec vous : {1}", + "fm_link_name_placeholder": "Nouveau lien", + "fm_link_url": "URL", + "fm_link_name": "Titre du lien", + "fm_link_type": "Lien", + "fm_link_new": "Nouveau Lien", + "notification_openLink": "Vous avez reçu un lien {0} de {1} :" } From 9256c45a264727b4afebe220e045b9ea96dbfd28 Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 27 Jul 2021 17:47:04 +0200 Subject: [PATCH 56/76] Translated using Weblate (German) Currently translated at 100.0% (1379 of 1379 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/de/ --- www/common/translations/messages.de.json | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/www/common/translations/messages.de.json b/www/common/translations/messages.de.json index 226e57c7c..259a19928 100644 --- a/www/common/translations/messages.de.json +++ b/www/common/translations/messages.de.json @@ -1332,7 +1332,7 @@ "form_cantFindAnswers": "Deine vorigen Antworten für dieses Formular konnten nicht geladen werden.", "form_updateWarning": "Trotzdem aktualisieren", "form_submitWarning": "Trotzdem absenden", - "form_sent": "Gesendet", + "form_sent": "Deine Antwort wurde gesendet", "form_update": "Aktualisieren", "form_submit": "Absenden", "form_type_checkbox": "Mehrfachauswahl", @@ -1368,5 +1368,16 @@ "admin_purpose_public": "Zur Bereitstellung eines kostenlosen Dienstes für die Allgemeinheit", "resources_learnWhy": "Mehr über die Gründe erfahren", "team_leaveOwner": "Bitte entferne dich von der Rolle des Eigentümers, bevor du das Teams verlässt. Beachte, dass Teams mindestens einen Eigentümer haben müssen. Bitte füge daher zunächst einen weiteren Eigentümer hinzu, sofern du derzeit der alleinige Eigentümer bist.", - "form_exportCSV": "Als CSV exportieren" + "form_exportCSV": "Als CSV exportieren", + "form_answerAs": "Antworten als", + "notification_openLink": "Du hast einen Link {0} von {1} erhalten:", + "fm_link_warning": "Warnung: URL ist länger als 200 Zeichen", + "notification_linkShared": "{0} hat einen Link mit dir geteilt: {1}", + "fm_link_name": "Bezeichnung des Links", + "fm_link_invalid": "Ungültige URL", + "form_anonName": "Dein Name", + "fm_link_name_placeholder": "Mein Link", + "fm_link_url": "URL", + "fm_link_type": "Link", + "fm_link_new": "Neuer Link" } From ef56a8f863ccceb8492dd1ad3d10717f55709fa8 Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 27 Jul 2021 17:47:04 +0200 Subject: [PATCH 57/76] Translated using Weblate (Japanese) Currently translated at 99.8% (1377 of 1379 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ --- www/common/translations/messages.ja.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index 83f22925b..3d68dbab9 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -1377,5 +1377,6 @@ "form_anonName": "あなたの名前", "notification_linkShared": "{0}があなたとリンクを共有しました: {1}", "fm_link_name_placeholder": "あなたのリンク", - "fm_link_warning": "注意:URLが200字を超えています" + "fm_link_warning": "注意:URLが200字を超えています", + "fm_link_invalid": "URLが無効です" } From a613b64b77c0e01f9b5dfb98a1ec655fae834745 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 28 Jul 2021 03:43:25 +0530 Subject: [PATCH 58/76] use brand link color for links in the form app --- www/form/app-form.less | 3 +++ 1 file changed, 3 insertions(+) diff --git a/www/form/app-form.less b/www/form/app-form.less index 60da1daff..ad26863bb 100644 --- a/www/form/app-form.less +++ b/www/form/app-form.less @@ -561,6 +561,9 @@ margin-right: 5px; } } + a, a:visited { + color: @cryptpad_color_link; + } } } } From f80aacc1770d9f4401fe4f364387beb15037c1af Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 28 Jul 2021 15:17:25 +0530 Subject: [PATCH 59/76] prevent incorrect removal of form submission buttons ...by guarding against overflow of a setTimeout delay --- www/form/inner.js | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/www/form/inner.js b/www/form/inner.js index 1b555be5d..cdd99e512 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -2784,6 +2784,11 @@ define([ var endDateEl = h('div.alert.alert-warning.cp-burn-after-reading'); var endDate; var endDateTo; + + // numbers greater than this overflow the maximum delay for a setTimeout + // which results in it being executed immediately (oops) + // https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout#maximum_delay_value + var MAX_TIMEOUT_DELAY = 2147483647; var refreshEndDateBanner = function (force) { if (APP.isEditor) { return; } var _endDate = content.answers.endDate; @@ -2804,10 +2809,21 @@ define([ APP.isClosed = endDate && endDate < (+new Date()); clearTimeout(endDateTo); if (!APP.isClosed && endDate) { - setTimeout(function () { + // calculate how many ms in the future the poll will be closed + var diff = (endDate - +new Date() + 100); + // if that value would overflow, then check again in a day + // (if the tab is still open) + if (diff > MAX_TIMEOUT_DELAY) { + endDateTo = setTimeout(function () { + refreshEndDateBanner(true); + }, 1000 * 3600 * 24); + return; + } + + endDateTo = setTimeout(function () { refreshEndDateBanner(true); - $('.cp-form-send-container').find('.cp-open').remove(); - },(endDate - +new Date() + 100)); + $('.cp-form-send-container').find('.cp-open').hide(); + }, diff); } }; From b3a7d5c42c6504b99149e6d6257268d7afda0fd5 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 28 Jul 2021 15:19:05 +0530 Subject: [PATCH 60/76] factor out some duplicated code for handling 24 dates --- www/admin/inner.js | 5 +---- www/common/common-ui-elements.js | 7 +++++++ www/form/inner.js | 6 +----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/www/admin/inner.js b/www/admin/inner.js index b35059df0..e8d567d41 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -1472,11 +1472,8 @@ define([ var end = h('input'); var $start = $(start); var $end = $(end); - var is24h = false; + var is24h = UIElements.is24h(); var dateFormat = "Y-m-d H:i"; - try { - is24h = !new Intl.DateTimeFormat(navigator.language, { hour: 'numeric' }).format(0).match(/AM/); - } catch (e) {} if (!is24h) { dateFormat = "Y-m-d h:i K"; } var endPickr = Flatpickr(end, { diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 99d506347..c0b052737 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -3696,6 +3696,13 @@ define([ return (pos.bottom < size) && (pos.y > 0); }; + UIElements.is24h = function () { + try { + return !new Intl.DateTimeFormat(navigator.language, { hour: 'numeric' }).format(0).match(/AM/); + } catch (e) {} + return false; + }; + UIElements.openSnapshotsModal = function (common, load, make, remove) { var modal; var readOnly = common.getMetadataMgr().getPrivateData().readOnly; diff --git a/www/form/inner.js b/www/form/inner.js index cdd99e512..410918787 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -68,13 +68,9 @@ define([ var APP = window.APP = { }; - var is24h = false; + var is24h = UIElements.is24h(); var dateFormat = "Y-m-d H:i"; var timeFormat = "H:i"; - try { - is24h = !new Intl.DateTimeFormat(navigator.language, { hour: 'numeric' }).format(0).match(/AM/); - } catch (e) {} - is24h = false; if (!is24h) { dateFormat = "Y-m-d h:i K"; timeFormat = "h:i K"; From 1247ed0b6bd456d7125b80c595a4433f0697e5a0 Mon Sep 17 00:00:00 2001 From: Weblate Date: Thu, 29 Jul 2021 09:53:49 +0200 Subject: [PATCH 61/76] Translated using Weblate (Japanese) Currently translated at 100.0% (1379 of 1379 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 99.9% (1378 of 1379 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ --- www/common/translations/messages.ja.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index 3d68dbab9..84fe9a3ae 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -560,7 +560,7 @@ "form_form": "フォーム", "form_editor": "エディタ", "form_delete": "削除", - "form_sent": "送信しました", + "form_sent": "回答を送信しました", "form_reset": "リセット", "form_update": "更新", "form_submit": "送信", @@ -1378,5 +1378,6 @@ "notification_linkShared": "{0}があなたとリンクを共有しました: {1}", "fm_link_name_placeholder": "あなたのリンク", "fm_link_warning": "注意:URLが200字を超えています", - "fm_link_invalid": "URLが無効です" + "fm_link_invalid": "URLが無効です", + "form_answerAs": "名前を記入してください" } From c6fefd73d846ae72eab8261a91ba1223d8148c34 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 30 Jul 2021 19:23:48 +0530 Subject: [PATCH 62/76] fix sheet conversion in Chrome by instantiating SharedArrayBuffers in a more portable way --- www/common/onlyoffice/inner.js | 25 ++++++++++++++++++++++++- www/common/onlyoffice/x2t/x2t.js | 15 ++++++++++----- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/www/common/onlyoffice/inner.js b/www/common/onlyoffice/inner.js index 4a0a56be0..5c57fbecc 100644 --- a/www/common/onlyoffice/inner.js +++ b/www/common/onlyoffice/inner.js @@ -72,8 +72,31 @@ define([ return JSONSortify(obj); }; + /* Chrome 92 dropped support for SharedArrayBuffer in cross-origin contexts + where window.crossOriginIsolated is false. + + Their blog (https://blog.chromium.org/2021/02/restriction-on-sharedarraybuffers.html) + isn't clear about why they're doing this, but since it's related to site-isolation + it seems they're trying to do vague security things. + + In any case, there seems to be a workaround where you can still create them + by using `new WebAssembly.Memory({shared: true, ...})` instead of `new SharedArrayBuffer`. + + This seems unreliable, but it's better than not being able to export, since + we actively rely on postMessage between iframes and therefore can't afford + to opt for full isolation. + */ + var supportsSharedArrayBuffers = function () { + try { + return Object.prototype.toString.call(new WebAssembly.Memory({shared: true, initial: 0, maximum: 0}).buffer) === '[object SharedArrayBuffer]'; + } catch (err) { + console.error(err); + } + return false; + }; + var supportsXLSX = function () { - return !(typeof(Atomics) === "undefined" || typeof (SharedArrayBuffer) === "undefined" || typeof(WebAssembly) === 'undefined'); + return !(typeof(Atomics) === "undefined" || !supportsSharedArrayBuffers() /* || typeof (SharedArrayBuffer) === "undefined" */ || typeof(WebAssembly) === 'undefined'); }; diff --git a/www/common/onlyoffice/x2t/x2t.js b/www/common/onlyoffice/x2t/x2t.js index 181b2db8f..9c1289c56 100644 --- a/www/common/onlyoffice/x2t/x2t.js +++ b/www/common/onlyoffice/x2t/x2t.js @@ -1,3 +1,8 @@ +function SUPPORTS_SHARED_MEMORY() { + return typeof(SharedArrayBuffer) !== 'undefined'; +} + + // Support for growable heap + pthreads, where the buffer may change, so JS views // must be updated. function GROWABLE_HEAP_STORE_I8(ptr, value) { @@ -1030,7 +1035,7 @@ if (ENVIRONMENT_IS_PTHREAD) { "maximum": 1073741824 / WASM_PAGE_SIZE, "shared": true }); - if (!(wasmMemory.buffer instanceof SharedArrayBuffer)) { + if (Object.prototype.toString.call(wasmMemory.buffer) !== '[object SharedArrayBuffer]') { err("requested a shared WebAssembly.Memory but the returned buffer is not a SharedArrayBuffer, indicating that while the browser has SharedArrayBuffer it does not have WebAssembly threads support - you may need to set a flag"); if (ENVIRONMENT_HAS_NODE) { console.log("(on node you may need: --experimental-wasm-threads --experimental-wasm-bulk-memory and also use a recent version)"); @@ -2161,7 +2166,7 @@ var PThread = { }), receiveObjectTransfer: (function(data) {}), allocateUnusedWorkers: (function(numWorkers, onFinishedLoading) { - if (typeof SharedArrayBuffer === "undefined") return; + if (!SUPPORTS_SHARED_MEMORY()) return; var workers = []; var numWorkersToCreate = numWorkers; if (PThread.preallocatedWorkers.length > 0) { @@ -2276,7 +2281,7 @@ var PThread = { } }), createNewWorkers: (function(numWorkers) { - if (typeof SharedArrayBuffer === "undefined") return []; + if (!SUPPORTS_SHARED_MEMORY()) return []; var pthreadMainJs = "x2t.worker.js"; pthreadMainJs = locateFile(pthreadMainJs); var newWorkers = []; @@ -5683,7 +5688,7 @@ function _emscripten_get_sbrk_ptr() { } Module["_emscripten_get_sbrk_ptr"] = _emscripten_get_sbrk_ptr; function _emscripten_has_threading_support() { - return typeof SharedArrayBuffer !== "undefined"; + return SUPPORTS_SHARED_MEMORY(); } Module["_emscripten_has_threading_support"] = _emscripten_has_threading_support; function _emscripten_is_main_browser_thread() { @@ -6761,7 +6766,7 @@ function _pthread_self() { } Module["_pthread_self"] = _pthread_self; function _pthread_create(pthread_ptr, attr, start_routine, arg) { - if (typeof SharedArrayBuffer === "undefined") { + if (!SUPPORTS_SHARED_MEMORY()) { err("Current environment does not support SharedArrayBuffer, pthreads are not available!"); return 6; } From b6cc4ef8cf9fe447823cea18d1099f1347a61008 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 2 Aug 2021 17:36:51 +0530 Subject: [PATCH 63/76] test browser-dependent SharedArrayBuffer support in checkup include debugging information in final report for when browser vendors inevitably break APIs again --- www/checkup/app-checkup.less | 17 ++++++- www/checkup/checkup-tools.js | 36 +++++++++++++ www/checkup/main.js | 97 ++++++++++++++++++++++++++++++++++-- www/checkup/sandbox/main.js | 24 ++++++++- 4 files changed, 166 insertions(+), 8 deletions(-) create mode 100644 www/checkup/checkup-tools.js diff --git a/www/checkup/app-checkup.less b/www/checkup/app-checkup.less index a475d5983..df8cef8d8 100644 --- a/www/checkup/app-checkup.less +++ b/www/checkup/app-checkup.less @@ -14,11 +14,15 @@ html, body { .report { font-size: 30px; - max-width: 50%; + max-width: 26em; margin: auto; padding-top: 15px; } + .summary, .failure, .error, .success { + margin-bottom: 1em; + } + .pending { border: 1px solid @cryptpad_text_col; .fa { @@ -46,6 +50,10 @@ html, body { td { padding: 5px; border: 1px solid @cryptpad_text_col; + font-size: 60%; + } + td:nth-child(2) { + word-break: break-word; } } @@ -72,7 +80,12 @@ html, body { color: @cryptpad_color_link; } } - .cp-app-checkup-version { + + .cp-notice-browser, .cp-notice-details, .cp-notice-other { + font-size: 70%; + } + + .cp-app-checkup-version, .cp-app-checkup-browser { text-decoration: underline; } diff --git a/www/checkup/checkup-tools.js b/www/checkup/checkup-tools.js new file mode 100644 index 000000000..79fe1c4b3 --- /dev/null +++ b/www/checkup/checkup-tools.js @@ -0,0 +1,36 @@ +define([ +], function () { + var Tools = {}; + Tools.supportsSharedArrayBuffers = function () { + try { + return Object.prototype.toString.call(new window.WebAssembly.Memory({ + shared: true, + initial: 0, + maximum: 0, + }).buffer) === '[object SharedArrayBuffer]'; + } catch (err) { + console.error(err); + } + return false; + }; + + + Tools.isSafari = function () { + return navigator.vendor.match(/apple/i); + }; + + Tools.isChrome = function () { + return navigator.vendor.match(/google/i); + }; + + Tools.guessBrowser = function () { + if (Tools.isChrome()) { return 'chrome/blink'; } + if (Tools.isSafari()) { return 'safari/webkit'; } + if (navigator.userAgent.match(/firefox\//i)) { return 'firefox/gecko'; } + if (navigator.userAgent.match(/edge\//i)) { return 'edge/edgehtml'; } + if (navigator.userAgent.match(/trident\//i)) { return 'ie/trident'; } + return navigator.userAgent + "\n" + navigator.vendor; + }; + + return Tools; +}); diff --git a/www/checkup/main.js b/www/checkup/main.js index 4413d3b18..0addabaa2 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -13,13 +13,14 @@ define([ '/common/pinpad.js', '/common/outer/network-config.js', '/customize/pages.js', + '/checkup/checkup-tools.js', '/bower_components/tweetnacl/nacl-fast.min.js', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', 'less!/checkup/app-checkup.less', ], function ($, ApiConfig, Assertions, h, Messages, DomReady, nThen, SFCommonO, Login, Hash, Util, Pinpad, - NetConfig, Pages) { + NetConfig, Pages, Tools) { var Assert = Assertions(); var trimSlashes = function (s) { if (typeof(s) !== 'string') { return s; } @@ -703,6 +704,81 @@ define([ }); }); + var safariGripe = function () { + return h('p.cp-notice-other', 'This is expected because Safari and platforms that use its engine lack commonly supported functionality.'); + }; + + var chromeGripe = function () { + return h('p.cp-notice-other', "This is expected because the developers of Google chrome's engine intentionally disabled support in cross-origin contexts. We are working on an alternate solution."); + }; + + var browserIssue = function () { + return h('p.cp-notice-other', 'This test checks for the presence of features in your browser and is not necessarily caused by server misconfiguration.'); + }; + + assert(function (cb, msg) { + cb = Util.once(cb); + setWarningClass(msg); + var notice = h('span', [ + h('p', 'It appears that some features required for Office file format conversion are not present.'), + ]); + + msg.appendChild(notice); + + var expected = [ + 'Atomics', + 'SharedArrayBuffer', + 'WebAssembly', + ['WebAssembly', 'Memory'], + ['WebAssembly', 'instantiate'], + ['WebAssembly', 'instantiateStreaming'], + ['Buffer', 'from'], + + 'SharedWorker', + 'worker', + 'crossOriginIsolated', + ]; + + var responses = {}; + + nThen(function (w) { + deferredPostMessage({ + command: 'CHECK_JS_APIS', + content: { + globals: expected, + }, + }, w(function (response) { + Util.extend(responses, response); + })); + + deferredPostMessage({ + command: 'FANCY_API_CHECKS', + content: { + }, + }, w(function (response) { + Util.extend(responses, response); + })); + }).nThen(function () { + if (!responses.Atomics || !responses.WebAssembly) { + return void cb(responses); + } + if (responses.SharedArrayBuffer || responses.SharedArrayBufferFallback) { + return cb(true); + } + + if (Tools.isSafari()) { + notice.appendChild(safariGripe()); + } + if (Tools.isChrome()) { + notice.appendChild(chromeGripe()); + } + + notice.appendChild(browserIssue()); + + return void cb(response); + }); + }); + var isHTTPS = function (host) { return /^https:\/\//.test(host); }; @@ -831,7 +907,7 @@ define([ var failureReport = function (obj) { var printableValue = obj.output; try { - printableValue = JSON.stringify(obj.output); + printableValue = JSON.stringify(obj.output, null, ' '); } catch (err) { console.error(err); } @@ -840,7 +916,7 @@ define([ h('h5', obj.message), h('table', [ row(["Failed test number", obj.test + 1]), - row(["Returned value", code(printableValue)]), + row(["Returned value", h('pre', code(printableValue))]), ]), ]); }; @@ -849,7 +925,7 @@ define([ var $progress = $('#cp-progress'); var versionStatement = function () { - return h('p', [ + return h('p.cp--notice-version', [ "This instance is running ", h('span.cp-app-checkup-version',[ "CryptPad", @@ -860,6 +936,16 @@ define([ ]); }; + var browserStatement = function () { + var name = Tools.guessBrowser(); + if (!name) { return; } + return h('p.cp-notice-browser', [ + "You appear to be using a ", + h('span.cp-app-checkup-browser', name), + ' browser to view this page.', + ]); + }; + Assert.run(function (state) { var errors = state.errors; var failed = errors.length; @@ -870,10 +956,11 @@ define([ var failedDetails = "Details found below"; var successDetails = "This checkup only tests the most common configuration issues. You may still experience errors or incorrect behaviour."; - var details = h('p', failed? failedDetails: successDetails); + var details = h('p.cp-notice-details', failed? failedDetails: successDetails); var summary = h('div.summary.' + statusClass, [ versionStatement(), + browserStatement(), h('p', Messages._getKey('assert_numberOfTestsPassed', [ state.passed, state.total diff --git a/www/checkup/sandbox/main.js b/www/checkup/sandbox/main.js index e11aa1d52..272db91a4 100644 --- a/www/checkup/sandbox/main.js +++ b/www/checkup/sandbox/main.js @@ -1,10 +1,12 @@ define([ 'jquery', + '/common/common-util.js', + '/checkup/checkup-tools.js', '/bower_components/tweetnacl/nacl-fast.min.js', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', 'less!/checkup/app-checkup.less', -], function ($) { +], function ($, Util, Tools) { var postMessage = function (content) { window.parent.postMessage(JSON.stringify(content), '*'); }; @@ -26,6 +28,26 @@ define([ }); }; + COMMANDS.CHECK_JS_APIS = function (content, cb) { + var globalAPIs = content['globals'] || []; + var response = {}; + globalAPIs.forEach(function (key) { + if (Array.isArray(key)) { + response[key.join('.')] = Boolean(Util.find(window, key)); + return; + } + + response[key] = Boolean(window[key]); + }); + cb(response); + }; + + COMMANDS.FANCY_API_CHECKS = function (content, cb) { + cb({ + SharedArrayBufferFallback: Tools.supportsSharedArrayBuffers(), + }); + }; + window.addEventListener("message", function (event) { var txid, command; if (event && event.data) { From f4e2e505fe3f187d020f99f77dec433d744cfe61 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 2 Aug 2021 17:37:06 +0530 Subject: [PATCH 64/76] lint compliance --- www/common/onlyoffice/inner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/onlyoffice/inner.js b/www/common/onlyoffice/inner.js index 5c57fbecc..ff738e636 100644 --- a/www/common/onlyoffice/inner.js +++ b/www/common/onlyoffice/inner.js @@ -88,7 +88,7 @@ define([ */ var supportsSharedArrayBuffers = function () { try { - return Object.prototype.toString.call(new WebAssembly.Memory({shared: true, initial: 0, maximum: 0}).buffer) === '[object SharedArrayBuffer]'; + return Object.prototype.toString.call(new window.WebAssembly.Memory({shared: true, initial: 0, maximum: 0}).buffer) === '[object SharedArrayBuffer]'; } catch (err) { console.error(err); } From 7ed41aa8e673fe26e5d29d71ee5a2a73398d7c06 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 2 Aug 2021 17:38:13 +0530 Subject: [PATCH 65/76] make a note to update a translation key --- www/common/sframe-common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index 5d3738cbb..6a7e3effd 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -921,7 +921,7 @@ define([ }); ctx.sframeChan.on('EV_WORKER_TIMEOUT', function () { - UI.errorLoadingScreen(Messages.timeoutError, false, function () { + UI.errorLoadingScreen(Messages.timeoutError, false, function () { // XXX mobile users can't necessarily hit 'ESC' as this message suggests. provice a click option funcs.gotoURL(''); }); }); From 613868bbdef43ba20dff938e5091dc2f492834d1 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 2 Aug 2021 17:59:53 +0530 Subject: [PATCH 66/76] fix safari-specific warnings in checkup --- www/checkup/main.js | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/www/checkup/main.js b/www/checkup/main.js index 0addabaa2..6fd085464 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -708,10 +708,6 @@ define([ return h('p.cp-notice-other', 'This is expected because Safari and platforms that use its engine lack commonly supported functionality.'); }; - var chromeGripe = function () { - return h('p.cp-notice-other', "This is expected because the developers of Google chrome's engine intentionally disabled support in cross-origin contexts. We are working on an alternate solution."); - }; - var browserIssue = function () { return h('p.cp-notice-other', 'This test checks for the presence of features in your browser and is not necessarily caused by server misconfiguration.'); }; @@ -721,6 +717,8 @@ define([ setWarningClass(msg); var notice = h('span', [ h('p', 'It appears that some features required for Office file format conversion are not present.'), + Tools.isSafari()? safariGripe(): undefined, + browserIssue(), ]); msg.appendChild(notice); @@ -765,16 +763,6 @@ define([ if (responses.SharedArrayBuffer || responses.SharedArrayBufferFallback) { return cb(true); } - - if (Tools.isSafari()) { - notice.appendChild(safariGripe()); - } - if (Tools.isChrome()) { - notice.appendChild(chromeGripe()); - } - - notice.appendChild(browserIssue()); - return void cb(response); }); }); From dd53b6fa72b917445013c59719e94a3a0d7ddc43 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 2 Aug 2021 18:05:46 +0530 Subject: [PATCH 67/76] constrain table width in checkup summaries --- www/checkup/app-checkup.less | 20 ++++++++++++-------- www/checkup/main.js | 10 ++++++---- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/www/checkup/app-checkup.less b/www/checkup/app-checkup.less index df8cef8d8..026d1952c 100644 --- a/www/checkup/app-checkup.less +++ b/www/checkup/app-checkup.less @@ -46,14 +46,18 @@ html, body { padding: 15px; } - table { - td { - padding: 5px; - border: 1px solid @cryptpad_text_col; - font-size: 60%; - } - td:nth-child(2) { - word-break: break-word; + .table-container { + overflow-x: auto; + width: 100%; + table { + td { + padding: 5px; + border: 1px solid @cryptpad_text_col; + font-size: 60%; + } + td:nth-child(2) { + word-break: break-word; + } } } diff --git a/www/checkup/main.js b/www/checkup/main.js index 6fd085464..171b9ac3b 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -902,10 +902,12 @@ define([ return h('div.error', [ h('h5', obj.message), - h('table', [ - row(["Failed test number", obj.test + 1]), - row(["Returned value", h('pre', code(printableValue))]), - ]), + h('div.table-container', + h('table', [ + row(["Failed test number", obj.test + 1]), + row(["Returned value", h('pre', code(printableValue))]), + ]), + ), ]); }; From ceab8fe2df09649d55b99d3f8ad08699e9582b84 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 2 Aug 2021 18:16:22 +0530 Subject: [PATCH 68/76] disable broken CSV export --- www/common/onlyoffice/inner.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/www/common/onlyoffice/inner.js b/www/common/onlyoffice/inner.js index ff738e636..2afef4978 100644 --- a/www/common/onlyoffice/inner.js +++ b/www/common/onlyoffice/inner.js @@ -1938,7 +1938,9 @@ define([ var exportXLSXFile = function() { var text = getContent(); var suggestion = Title.suggestTitle(Title.defaultTitle); - var ext = ['.xlsx', '.ods', '.bin', '.csv', '.pdf']; + var ext = ['.xlsx', '.ods', '.bin', + //'.csv', // XXX + '.pdf']; var type = common.getMetadataMgr().getPrivateData().ooType; var warning = ''; if (type==="presentation") { From 7885a3ff5b3d6f21f14b5ff51f389eef6b2c948f Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 2 Aug 2021 19:55:19 +0530 Subject: [PATCH 69/76] update changelog with latest hotfixes --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23f48dc01..764a1f290 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# WIP + +* Sheet export + * most exports broken by Chrome 92, mostly fixed + * we discovered that CSV export was not working in any major browser, though it's unclear why. We've disabled CSV export in the meantime +* some new browser-specific checkup tests to make it easier to detect future regressions in the APIs needed for sheet export + # 4.9.0 ## Goals and announcements From d67d6069d472fef60c66690ec402484696b1c2b5 Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 3 Aug 2021 08:33:26 +0200 Subject: [PATCH 70/76] Translated using Weblate (English) Currently translated at 100.0% (1379 of 1379 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ --- www/common/translations/messages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index ae5f1e0a5..035275177 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -1230,7 +1230,7 @@ "genericCopySuccess": "Copied to clipboard", "mediatag_defaultImageName": "image", "register_registrationIsClosed": "Registration is closed.", - "oo_conversionSupport": "Your browser cannot handle conversion to and from Microsoft Office formats. We suggest using a recent version of Firefox or Chrome.", + "oo_conversionSupport": "Your browser cannot handle conversion to and from office formats. We suggest using a recent version of Firefox or Chrome.", "oo_importBin": "Click OK to import CryptPad's internal .bin format.", "admin_emailTitle": "Admin contact email", "admin_emailHint": "Set the contact email for your instance here", From a20bfbf6c1286c8e36cf27019d6504a308e6ffb3 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 3 Aug 2021 12:15:30 +0530 Subject: [PATCH 71/76] lint compliance --- www/checkup/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/checkup/main.js b/www/checkup/main.js index 171b9ac3b..a1e458f34 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -906,7 +906,7 @@ define([ h('table', [ row(["Failed test number", obj.test + 1]), row(["Returned value", h('pre', code(printableValue))]), - ]), + ]) ), ]); }; From 22357f882b3f4e425277e95e92343901819a49c8 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 3 Aug 2021 12:17:42 +0530 Subject: [PATCH 72/76] guard against a type error in user-object when FILES_DATA doesn't exist --- www/common/userObject.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/www/common/userObject.js b/www/common/userObject.js index 9de3ea918..c3960ebfd 100644 --- a/www/common/userObject.js +++ b/www/common/userObject.js @@ -316,13 +316,24 @@ define([ // Get data from AllFiles (Cryptpad_RECENTPADS) var getFileData = exp.getFileData = function (file, editable) { if (!file) { return; } - var link = (files[STATIC_DATA] || {})[file]; + var link; + try { + link = (files[STATIC_DATA] || {})[file]; + } catch (err) { + console.error(err); + } if (link) { var _link = editable ? link : Util.clone(link); if (!editable) { _link.static = true; } return _link; } - var data = files[FILES_DATA][file] || {}; + var data; + try { + data = files[FILES_DATA][file] || {}; + } catch (err) { + console.error(err); + data = {}; + } if (!editable) { data = JSON.parse(JSON.stringify(data)); if (data.href && data.href.indexOf('#') === -1) { From 298d69e9144c4480aeeae609f400cce5c23cda36 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 3 Aug 2021 12:23:10 +0530 Subject: [PATCH 73/76] guard against another possible type error (in the user object) --- www/common/userObject.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/www/common/userObject.js b/www/common/userObject.js index c3960ebfd..9e033f5c0 100644 --- a/www/common/userObject.js +++ b/www/common/userObject.js @@ -367,8 +367,13 @@ define([ return '??'; } var data = getFileData(file); + if (!data) { + error("unable to retrieve data about the requested file: ", file, data); + return; + } + // handle links if (data.static) { return data.name; } - if (!file || !data || !(data.href || data.roHref)) { + if (!file || !(data.href || data.roHref)) { error("getTitle called with a non-existing file id: ", file, data); return; } From d8a7e4aa2a6b0d648c8d10a165f35e918519bd7a Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 3 Aug 2021 12:35:02 +0530 Subject: [PATCH 74/76] update changelog --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 764a1f290..fe07777de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,10 @@ * Sheet export * most exports broken by Chrome 92, mostly fixed * we discovered that CSV export was not working in any major browser, though it's unclear why. We've disabled CSV export in the meantime -* some new browser-specific checkup tests to make it easier to detect future regressions in the APIs needed for sheet export + * updated translation to stop referring to Microsoft since we support OpenDocument formats + * some new browser-specific checkup tests to make it easier to detect future regressions in the APIs +* drive bug fixes + * guard against a few possible type errors # 4.9.0 From f141fdef3b9d6348cf65bca66eff005a729067ed Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 3 Aug 2021 13:51:16 +0530 Subject: [PATCH 75/76] set a smaller width on the kanban's 'addboard' button --- www/kanban/app-kanban.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/kanban/app-kanban.less b/www/kanban/app-kanban.less index 9fd06a510..f0aa82d62 100644 --- a/www/kanban/app-kanban.less +++ b/www/kanban/app-kanban.less @@ -545,7 +545,7 @@ #kanban-addboard { order: 2; - width: 300px; + width: 50px; margin: 10px 5px; border: 1px solid @cp_kanban-fg; color: @cp_kanban-fg; From 51b57f03410e2cb28df26c6fc0390d2ff0928132 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 3 Aug 2021 13:55:39 +0530 Subject: [PATCH 76/76] update changelog with kanban improvements --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe07777de..488113540 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ * some new browser-specific checkup tests to make it easier to detect future regressions in the APIs * drive bug fixes * guard against a few possible type errors +* kanban screen real-estate + * narrower 'add board' button + * 'Tools' menu to collapse the tag and view mode UI # 4.9.0