From b6ccff28db30ff5daab4e517020be13fd4144ca0 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 2 Feb 2021 17:12:29 +0100 Subject: [PATCH 01/19] Throttle kanban refresh on remote changes --- www/kanban/inner.js | 23 ++++++++++++++--------- www/kanban/jkanban_cp.js | 19 ++++++++++++++----- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/www/kanban/inner.js b/www/kanban/inner.js index 61a7ad23d..036a563b0 100644 --- a/www/kanban/inner.js +++ b/www/kanban/inner.js @@ -133,6 +133,12 @@ define([ return tags; }; + var updateBoards = Util.throttle(function (framework, kanban, boards) { + kanban.setBoards(Util.clone(boards)); + kanban.inEditMode = false; + addEditItemButton(framework, kanban); + }, 500); + var addEditItemButton = function () {}; var onRemoteChange = Util.mkEvent(); var editModal; @@ -146,10 +152,9 @@ define([ var isBoard, id; var offline = false; - var update = Util.throttle(function () { - kanban.setBoards(kanban.options.boards); - addEditItemButton(framework, kanban); - }, 400); + var update = function () { + updateBoards(framework, kanban, kanban.options.boards); + }; var commit = function () { framework.localChange(); @@ -830,7 +835,8 @@ define([ openLink: openLink, getTags: getExistingTags, cursors: remoteCursors, - boards: boards + boards: boards, + _boards: Util.clone(boards), }); framework._.cpNfInner.metadataMgr.onChange(function () { @@ -841,7 +847,7 @@ define([ // If the rendering has changed, update the value and redraw kanban.options.tagsAnd = tagsAnd; _tagsAnd = tagsAnd; - kanban.setBoards(kanban.options.boards); + updateBoards(kanban.options.boards); }); if (migrated) { framework.localChange(); } @@ -1166,9 +1172,8 @@ define([ if (Sortify(currentContent) !== Sortify(remoteContent)) { var cursor = getCursor(); verbose("Content is different.. Applying content"); - kanban.setBoards(remoteContent); - kanban.inEditMode = false; - addEditItemButton(framework, kanban); + kanban.options.boards = remoteContent; + updateBoards(framework, kanban, remoteContent); restoreCursor(cursor); onRemoteChange.fire(); } diff --git a/www/kanban/jkanban_cp.js b/www/kanban/jkanban_cp.js index f122eed59..bddbfd704 100644 --- a/www/kanban/jkanban_cp.js +++ b/www/kanban/jkanban_cp.js @@ -32,7 +32,8 @@ define([ data: {}, items: {}, list: [] - }, + }, // The realtime kanban + _boards: {}, // The displayed kanban. We need to remember the old columns when we redraw getAvatar: function () {}, openLink: function () {}, getTags: function () {}, @@ -707,21 +708,29 @@ define([ }; this.addBoard = function (board) { if (!board || !board.id) { return; } + // We need to store all the columns in _boards too because it's used to + // remember what columns were already displayed when we redraw (in order to + // preserve their scroll value) var boards = self.options.boards; boards.data = boards.data || {}; boards.list = boards.list || []; + var _boards = self.options._boards; + _boards.data = _boards.data || {}; + _boards.list = _boards.list || []; // If it already there, abort boards.data[board.id] = board; + _boards.data[board.id] = board; if (boards.list.indexOf(board.id) !== -1) { return; } boards.list.push(board.id); + _boards.list.push(board.id); var boardNode = getBoardNode(board); self.container.appendChild(boardNode); }; this.addBoards = function() { //for on all the boards - var boards = self.options.boards; + var boards = self.options._boards; boards.list = boards.list || []; boards.data = boards.data || {}; var toRemove = []; @@ -759,10 +768,10 @@ define([ var $el = $(self.element); var scrollLeft = $el.scrollLeft(); // Get existing boards list - var list = Util.clone(this.options.boards.list); + var list = Util.clone(this.options._boards.list); // Update memory - this.options.boards = boards; + this.options._boards = boards; // If the tab is not focused but a handler already exists: abort if (!Visible.currently() && onVisibleHandler) { return; } @@ -779,7 +788,7 @@ define([ self.addBoards(); self.options.refresh(); // Preserve scroll - self.options.boards.list.forEach(function (id) { + self.options._boards.list.forEach(function (id) { if (!scroll[id]) { return; } $('.kanban-board[data-id="'+id+'"] .kanban-drag').scrollTop(scroll[id]); }); From 6f399eb298f09417ecabbb0783f83073c01ef6f0 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 2 Feb 2021 17:47:11 +0100 Subject: [PATCH 02/19] Fix drive search throttle --- www/common/drive-ui.js | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index 972675487..39cb80556 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -3259,6 +3259,7 @@ define([ var $spinnerContainer = $(h('div.cp-app-drive-search-spinner')); var spinner = UI.makeSpinner($spinnerContainer); + var searching = true; var $input = APP.Search.$input = $('', { id: 'cp-app-drive-search-input', placeholder: Messages.fm_searchName, @@ -3266,21 +3267,19 @@ define([ draggable: false, tabindex: 1, }).keyup(function (e) { - var lastValue = search.value; - search.value = $input.val().trim(); - if (lastValue === search.value) { return; } - - if (search.to) { window.clearTimeout(search.to); } - if (search.value === "") { - search.cursor = 0; - APP.displayDirectory([SEARCH]); + if (searching) { + e.preventDefault(); + e.stopPropagation(); return; } - spinner.spin(); + var currentValue = $input.val().trim(); + if (search.to) { window.clearTimeout(search.to); } if (e.which === 13) { + spinner.spin(); var newLocation = [SEARCH, $input.val()]; search.cursor = $input[0].selectionStart; if (!manager.comparePath(newLocation, currentPath.slice())) { + searching = true; APP.displayDirectory(newLocation); } return; @@ -3288,27 +3287,30 @@ define([ if (e.which === 27) { $input.val(''); search.cursor = 0; + searching = true; APP.displayDirectory([SEARCH]); return; } - if ($input.val()) { - if (!$input.hasClass('cp-app-drive-search-active')) { - $input.addClass('cp-app-drive-search-active'); - } - } else { - $input.removeClass('cp-app-drive-search-active'); + + if (currentValue === "") { + search.cursor = 0; + APP.displayDirectory([SEARCH]); + return; } + + if (currentValue.length < 2) { return; } // Don't autosearch 1 character search.to = window.setTimeout(function () { var newLocation = [SEARCH, $input.val()]; search.cursor = $input[0].selectionStart; + if (currentValue === search.value) { return; } if (!manager.comparePath(newLocation, currentPath.slice())) { + searching = true; APP.displayDirectory(newLocation); } }, 500); }).on('click mousedown mouseup', function (e) { e.stopPropagation(); }).val(value || '').appendTo($div); - if (value) { $input.addClass('cp-app-drive-search-active'); } $input[0].selectionStart = search.cursor || 0; $input[0].selectionEnd = search.cursor || 0; @@ -3329,6 +3331,7 @@ define([ if (typeof(value) === "string" && value.trim()) { spinner.spin(); } else { + searching = false; return; } @@ -3402,6 +3405,7 @@ define([ }); setTimeout(collapseDrivePath); spinner.hide(); + searching = false; }); }; From 3fdaf25429aa3cc81752f485e1f8b14ad31db35d Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 2 Feb 2021 17:58:51 +0100 Subject: [PATCH 03/19] Fix offline race condition in the user menu --- www/common/common-ui-elements.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 7f080d9df..78fc4ba68 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -1849,6 +1849,13 @@ define([ var oldUrl = ''; var updateButton = function () { var myData = metadataMgr.getUserData(); + var privateData = metadataMgr.getPrivateData(); + if (!priv.plan && privateData.plan) { + config.$initBlock.empty(); + metadataMgr.off('change', updateButton); + UIElements.createUserAdminMenu(Common, config); + return; + } if (!myData) { return; } if (loadingAvatar) { // Try again in 200ms From c18f6eafdc1a02739ccc595e672c36a3a385532e Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 2 Feb 2021 18:29:36 +0100 Subject: [PATCH 04/19] Fix usage bar race condition in offline mode --- www/common/common-ui-elements.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 78fc4ba68..7fdc3e957 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -1180,6 +1180,12 @@ define([ // so we can just use those and only check for errors var $container = $('', {'class':'cp-limit-container'}); var todo = function (err, data) { + if (err === 'RPC_NOT_READY') { + setTimeout(function () { + common.getPinUsage(teamId, todo); + }, 1000); + return; + } if (err || !data) { return void console.error(err || 'No data'); } var usage = data.usage; From ec4b95687cd9e3730fad2bd3fae0d6d7bff798f8 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 3 Feb 2021 11:51:15 +0100 Subject: [PATCH 05/19] Implement undo/redo for whiteboard #195 --- www/whiteboard/app-whiteboard.less | 2 +- www/whiteboard/inner.js | 40 ++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/www/whiteboard/app-whiteboard.less b/www/whiteboard/app-whiteboard.less index 972e4fee2..bfc9823a1 100644 --- a/www/whiteboard/app-whiteboard.less +++ b/www/whiteboard/app-whiteboard.less @@ -87,7 +87,7 @@ #cp-app-whiteboard-delete { min-width: 40px; } - .cp-whiteboard-type { + .cp-whiteboard-type, .cp-whiteboard-history { button { min-width: 40px; text-align: center; diff --git a/www/whiteboard/inner.js b/www/whiteboard/inner.js index e0492309f..79862ffef 100644 --- a/www/whiteboard/inner.js +++ b/www/whiteboard/inner.js @@ -53,6 +53,9 @@ define([ var $type = $('.cp-whiteboard-type'); var $brush = $('.cp-whiteboard-type .brush'); var $move = $('.cp-whiteboard-type .move'); + var $history = $('.cp-whiteboard-history'); + var $undo = $('.cp-whiteboard-history .undo'); + var $redo = $('.cp-whiteboard-history .redo'); var $deleteButton = $('#cp-app-whiteboard-delete'); var metadataMgr = framework._.cpNfInner.metadataMgr; @@ -137,6 +140,27 @@ define([ $deleteButton.prop('disabled', ''); }); + $undo.click(function () { + if (typeof(APP.canvas.undo) !== "function") { return; } + APP.canvas.undo(); + APP.onLocal(); + }); + $redo.click(function () { + if (typeof(APP.canvas.undo) !== "function") { return; } + APP.canvas.redo(); + APP.onLocal(); + }); + $('body').on('keydown', function (e) { + if (e.which === 90 && e.ctrlKey) { + $undo.click(); + return; + } + if (e.which === 89 && e.ctrlKey) { + $redo.click(); + return; + } + }); + var deleteSelection = function () { if (APP.draw) { return; } if (canvas.getActiveObject()) { @@ -436,7 +460,15 @@ define([ }; }); + var cleanHistory = function () { + if (Array.isArray(canvas.historyUndo)) { + canvas.historyUndo = canvas.historyUndo.slice(-100); + canvas.historyRedo = canvas.historyRedo.slice(-100); + } + }; + framework.onContentUpdate(function (newContent, waitFor) { + cleanHistory(); var content = newContent.content; canvas.loadFromJSON(content, waitFor(function () { canvas.renderAll(); @@ -445,6 +477,7 @@ define([ }); framework.setContentGetter(function () { + cleanHistory(); var content = canvas.toDatalessJSON(); return { content: content @@ -475,6 +508,8 @@ define([ }; + Messages.undo = "Undo"; // XXX + Messages.redo = "Redo"; // XXX var initialContent = function () { return [ h('div#cp-toolbar.cp-toolbar-container'), @@ -494,6 +529,10 @@ define([ h('button.btn.brush.fa.fa-paint-brush.btn-primary', {title: Messages.canvas_brush}), h('button.btn.move.fa.fa-arrows', {title: Messages.canvas_select}), ]), + h('div.cp-whiteboard-history', [ + h('button.btn.undo.fa.fa-undo', {title: Messages.undo}), + h('button.btn.redo.fa.fa-repeat', {title: Messages.redo}), + ]), h('button.btn.fa.fa-trash#cp-app-whiteboard-delete', { disabled: 'disabled', title: Messages.canvas_delete @@ -560,6 +599,7 @@ define([ $('body').append($div.html()); })); }).nThen(function (waitFor) { + require(['/lib/fabric-history.min.js'], waitFor()); // Framework initialization Framework.create({ From d17b17c2e3fbd67e4c42945903b4328ea4200b95 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 3 Feb 2021 12:14:05 +0100 Subject: [PATCH 06/19] Better kanban throttle --- www/kanban/inner.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/www/kanban/inner.js b/www/kanban/inner.js index 036a563b0..d32042780 100644 --- a/www/kanban/inner.js +++ b/www/kanban/inner.js @@ -133,13 +133,24 @@ define([ return tags; }; - var updateBoards = Util.throttle(function (framework, kanban, boards) { + var addEditItemButton = function () {}; + + var now = function () { return +new Date(); }; + var _lastUpdate = 0; + var _updateBoards = function (framework, kanban, boards) { + _lastUpdate = now(); kanban.setBoards(Util.clone(boards)); kanban.inEditMode = false; addEditItemButton(framework, kanban); - }, 500); + }; + var _updateBoardsThrottle = Util.throttle(_updateBoards, 500); + var updateBoards = function (framework, kanban, boards) { + if ((now() - _lastUpdate) > 5000) { + _updateBoards(framework, kanban, boards); + } + _updateBoardsThrottle(); + }; - var addEditItemButton = function () {}; var onRemoteChange = Util.mkEvent(); var editModal; var PROPERTIES = ['title', 'body', 'tags', 'color']; From f8ae3a8c8e3775d3506bd739d7d18adf3b385231 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 3 Feb 2021 12:14:54 +0100 Subject: [PATCH 07/19] Add missing return --- www/kanban/inner.js | 1 + 1 file changed, 1 insertion(+) diff --git a/www/kanban/inner.js b/www/kanban/inner.js index d32042780..8dea40415 100644 --- a/www/kanban/inner.js +++ b/www/kanban/inner.js @@ -147,6 +147,7 @@ define([ var updateBoards = function (framework, kanban, boards) { if ((now() - _lastUpdate) > 5000) { _updateBoards(framework, kanban, boards); + return; } _updateBoardsThrottle(); }; From ea13b4069860bfd65378c10afc4aaaf803688f10 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 3 Feb 2021 12:41:22 +0100 Subject: [PATCH 08/19] Fix kanban undefined --- www/kanban/inner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/kanban/inner.js b/www/kanban/inner.js index 8dea40415..8c00ae3dc 100644 --- a/www/kanban/inner.js +++ b/www/kanban/inner.js @@ -149,7 +149,7 @@ define([ _updateBoards(framework, kanban, boards); return; } - _updateBoardsThrottle(); + _updateBoardsThrottle(framework, kanban, boards); }; var onRemoteChange = Util.mkEvent(); From f8add72f63d30d7a21246c0d5b8d2a615189bb59 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 3 Feb 2021 12:52:54 +0100 Subject: [PATCH 09/19] Increase throttle value --- www/kanban/inner.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/www/kanban/inner.js b/www/kanban/inner.js index 8c00ae3dc..8344a4b26 100644 --- a/www/kanban/inner.js +++ b/www/kanban/inner.js @@ -143,7 +143,7 @@ define([ kanban.inEditMode = false; addEditItemButton(framework, kanban); }; - var _updateBoardsThrottle = Util.throttle(_updateBoards, 500); + var _updateBoardsThrottle = Util.throttle(_updateBoards, 1000); var updateBoards = function (framework, kanban, boards) { if ((now() - _lastUpdate) > 5000) { _updateBoards(framework, kanban, boards); @@ -859,7 +859,7 @@ define([ // If the rendering has changed, update the value and redraw kanban.options.tagsAnd = tagsAnd; _tagsAnd = tagsAnd; - updateBoards(kanban.options.boards); + updateBoards(framework, kanban, kanban.options.boards); }); if (migrated) { framework.localChange(); } From cd417d38260d1cf8b70e7e4d3e41a557d6b97aba Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 3 Feb 2021 13:05:30 +0100 Subject: [PATCH 10/19] Fix search stuck with no results --- www/common/drive-ui.js | 1 + 1 file changed, 1 insertion(+) diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index 39cb80556..b121348a5 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -3341,6 +3341,7 @@ define([ if (!filesList.length) { $list.append(h('div.cp-app-drive-search-noresult', Messages.fm_noResult)); spinner.hide(); + searching = false; return; } var sortable = {}; From 7b666119c56c9c051290a14c581f94fbe419a786 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 3 Feb 2021 13:17:57 +0100 Subject: [PATCH 11/19] Add missing file --- www/lib/fabric-history.min.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 www/lib/fabric-history.min.js diff --git a/www/lib/fabric-history.min.js b/www/lib/fabric-history.min.js new file mode 100644 index 000000000..5dd7ebd4f --- /dev/null +++ b/www/lib/fabric-history.min.js @@ -0,0 +1 @@ +fabric.Canvas.prototype.initialize=function(t){return function(...i){return t.call(this,...i),this._historyInit(),this}}(fabric.Canvas.prototype.initialize),fabric.Canvas.prototype.dispose=function(t){return function(...i){return t.call(this,...i),this._historyDispose(),this}}(fabric.Canvas.prototype.dispose),fabric.Canvas.prototype._historyNext=function(){return JSON.stringify(this.toDatalessJSON(this.extraProps))},fabric.Canvas.prototype._historyEvents=function(){return{"object:added":this._historySaveAction,"object:removed":this._historySaveAction,"object:modified":this._historySaveAction,"object:skewing":this._historySaveAction}},fabric.Canvas.prototype._historyInit=function(){this.historyUndo=[],this.historyRedo=[],this.extraProps=["selectable"],this.historyNextState=this._historyNext(),this.on(this._historyEvents())},fabric.Canvas.prototype._historyDispose=function(){this.off(this._historyEvents())},fabric.Canvas.prototype._historySaveAction=function(){if(this.historyProcessing)return;const t=this.historyNextState;this.historyUndo.push(t),this.historyNextState=this._historyNext(),this.fire("history:append",{json:t})},fabric.Canvas.prototype.undo=function(t){this.historyProcessing=!0;const i=this.historyUndo.pop();i?(this.historyRedo.push(this._historyNext()),this.historyNextState=i,this._loadHistory(i,"history:undo",t)):this.historyProcessing=!1},fabric.Canvas.prototype.redo=function(t){this.historyProcessing=!0;const i=this.historyRedo.pop();i?(this.historyUndo.push(this._historyNext()),this.historyNextState=i,this._loadHistory(i,"history:redo",t)):this.historyProcessing=!1},fabric.Canvas.prototype._loadHistory=function(t,i,s){var o=this;this.loadFromJSON(t,function(){o.renderAll(),o.fire(i),o.historyProcessing=!1,s&&"function"==typeof s&&s()})},fabric.Canvas.prototype.clearHistory=function(){this.historyUndo=[],this.historyRedo=[],this.fire("history:clear")},fabric.Canvas.prototype.offHistory=function(){this.historyProcessing=!0},fabric.Canvas.prototype.onHistory=function(){this.historyProcessing=!1,this._historySaveAction()}; \ No newline at end of file From 553559509613047dcdb7bef604a736a7123e862e Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 3 Feb 2021 13:32:53 +0100 Subject: [PATCH 12/19] Make sure we don't create multiple timeouts for the usage bar --- www/common/common-ui-elements.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 7fdc3e957..5d33f09ef 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -1179,9 +1179,14 @@ define([ // getPinnedUsage updates common.account.usage, and other values // so we can just use those and only check for errors var $container = $('', {'class':'cp-limit-container'}); + var to; var todo = function (err, data) { + if (to) { + clearTimeout(to); + to = undefined; + } if (err === 'RPC_NOT_READY') { - setTimeout(function () { + to = setTimeout(function () { common.getPinUsage(teamId, todo); }, 1000); return; From 780e554cc8243e3eecc28052843f9824fcec4c49 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 3 Feb 2021 16:35:25 +0100 Subject: [PATCH 13/19] Add textbox in whiteboard --- www/whiteboard/inner.js | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/www/whiteboard/inner.js b/www/whiteboard/inner.js index 79862ffef..3fbd097e8 100644 --- a/www/whiteboard/inner.js +++ b/www/whiteboard/inner.js @@ -56,12 +56,13 @@ define([ var $history = $('.cp-whiteboard-history'); var $undo = $('.cp-whiteboard-history .undo'); var $redo = $('.cp-whiteboard-history .redo'); + var $text = $('.cp-whiteboard-text button'); var $deleteButton = $('#cp-app-whiteboard-delete'); var metadataMgr = framework._.cpNfInner.metadataMgr; var brush = { - color: '#000000', + color: window.CryptPad_theme === "dark" ? '#FFFFFF' : '#000000', opacity: 1 }; @@ -140,6 +141,14 @@ define([ $deleteButton.prop('disabled', ''); }); + $text.click(function () { + $move.click(); + canvas.add(new fabric.Textbox('My Text', { + fill: brush.color, + top: 5, + left: 5 + })); + }); $undo.click(function () { if (typeof(APP.canvas.undo) !== "function") { return; } APP.canvas.undo(); @@ -199,6 +208,16 @@ define([ c = Colors.rgb2hex(c); brush.color = c; canvas.freeDrawingBrush.color = Colors.hex2rgba(brush.color, brush.opacity); + if (!APP.draw) { + var active = canvas.getActiveObject(); + if (active) { + var col = Colors.hex2rgba(brush.color, brush.opacity); + if (active.text) { active.set('fill', col); } + else { active.set('stroke', col); } + canvas.renderAll(); + APP.onLocal(); + } + } createCursor(); }; @@ -533,6 +552,9 @@ define([ h('button.btn.undo.fa.fa-undo', {title: Messages.undo}), h('button.btn.redo.fa.fa-repeat', {title: Messages.redo}), ]), + h('div.cp-whiteboard-text', [ + h('button.btn.fa.fa-font') + ]), h('button.btn.fa.fa-trash#cp-app-whiteboard-delete', { disabled: 'disabled', title: Messages.canvas_delete From 1c9d36d9ea420e69c47304ad4727875c88717e3b Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 3 Feb 2021 17:27:38 +0100 Subject: [PATCH 14/19] Fix drag&drop in kanban for mobile --- www/kanban/app-kanban.less | 46 +++++++++++++++++++++++++++++++++++--- www/kanban/jkanban_cp.js | 2 +- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/www/kanban/app-kanban.less b/www/kanban/app-kanban.less index 524d414b4..02eb529e8 100644 --- a/www/kanban/app-kanban.less +++ b/www/kanban/app-kanban.less @@ -143,6 +143,9 @@ border: 0; background: transparent; align-self: flex-start; + @media (hover: none) { + margin-right: 20px; + } } .cp-kanban-cursors { @@ -167,6 +170,21 @@ padding: 5px; flex-wrap: wrap; touch-action: none; + .tools_unselectable(); + touch-action: none; + cursor: move; + cursor: grab; + + margin-bottom: 10px; + &:last-child { + margin: 0; + } + &.is-moving.gu-mirror { + transform: rotate(3deg); + height: auto !important; + opacity: 0.8; + } + .cp-kanban-cursors { margin-top: 10px; } @@ -240,6 +258,26 @@ } .kanban-board { + position: relative; + transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1); + vertical-align: top; + display: flex; + flex-flow: column; + width: 300px; + margin: 10px 5px; + @media (hover: none) { + margin-bottom: 30px; + } + + &.is-moving.gu-mirror { + transform: rotate(3deg); + opacity: 0.8; + .kanban-drag { + overflow: hidden; + padding-right: 50px; + } + } + main { padding: 0 10px; margin: 10px 0; @@ -247,12 +285,17 @@ overflow-y: auto; justify-content: space-around; min-height: 38px; // Size of one card + @media (hover: none) { + padding-right: 30px; + } } header { display: flex; flex-wrap: wrap; align-items: center; padding: 5px 10px; + cursor: move; + cursor: grab; .kanban-title-board { flex: 1; margin-right: 10px; @@ -264,9 +307,6 @@ #kanban-edit { font-weight: bold; } - &:hover { - cursor: move; - } } footer { margin: 10px; diff --git a/www/kanban/jkanban_cp.js b/www/kanban/jkanban_cp.js index bddbfd704..56dcfaa60 100644 --- a/www/kanban/jkanban_cp.js +++ b/www/kanban/jkanban_cp.js @@ -26,7 +26,7 @@ define([ element: '', gutter: '15px', widthBoard: '250px', - responsive: '700', + responsive: 0, //'700', responsivePercentage: false, boards: { data: {}, From dbba45e67e7e25d4e63b830fff15cdc71b2e4be1 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 4 Feb 2021 16:23:26 +0100 Subject: [PATCH 15/19] Don't remove both kanban items when a duplicate is deleted --- www/kanban/inner.js | 13 +++++++++++-- www/kanban/jkanban_cp.js | 22 +++++++++++++++++----- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/www/kanban/inner.js b/www/kanban/inner.js index 8344a4b26..e9c4e30b8 100644 --- a/www/kanban/inner.js +++ b/www/kanban/inner.js @@ -145,7 +145,7 @@ define([ }; var _updateBoardsThrottle = Util.throttle(_updateBoards, 1000); var updateBoards = function (framework, kanban, boards) { - if ((now() - _lastUpdate) > 5000) { + if ((now() - _lastUpdate) > 5000 || framework.isLocked()) { _updateBoards(framework, kanban, boards); return; } @@ -1207,8 +1207,17 @@ define([ var items = boards.items || {}; var data = boards.data || {}; var list = boards.list || []; + + // Remove duplicate boards + list = boards.list = Util.deduplicateString(list); + Object.keys(data).forEach(function (id) { - if (list.indexOf(Number(id)) === -1) { delete data[id]; } + if (list.indexOf(Number(id)) === -1) { + list.push(Number(id)); + } + // Remove duplicate items + var b = data[id]; + b.item = Util.deduplicateString(b.item || []); }); Object.keys(items).forEach(function (eid) { var exists = Object.keys(data).some(function (id) { diff --git a/www/kanban/jkanban_cp.js b/www/kanban/jkanban_cp.js index 56dcfaa60..742fbc379 100644 --- a/www/kanban/jkanban_cp.js +++ b/www/kanban/jkanban_cp.js @@ -299,7 +299,9 @@ define([ // Move to trash? if (target.classList.contains('kanban-trash')) { list.splice(index1, 1); - delete self.options.boards.data[id]; + if (list.indexOf(id) === -1) { + delete self.options.boards.data[id]; + } self.onChange(); return; } @@ -444,6 +446,14 @@ define([ }); return res; }; + this.checkItem = function (eid) { + var boards = self.options.boards; + var data = boards.data || {}; + var exists = Object.keys(data).some(function (id) { + return (data[id].item || []).indexOf(Number(eid)) !== -1; + }); + return exists; + }; this.moveItem = function (eid, board, pos) { var boards = self.options.boards; var same = -1; @@ -453,11 +463,13 @@ define([ obj.board.item.splice(obj.pos, 1); if (obj.board === board) { same = obj.pos; } }); - // If it's a deletion, remove the item data + // If it's a deletion and not a duplicate, remove the item data if (!board) { - delete boards.items[eid]; - delete self.cache[eid]; - removeUnusedTags(boards); + if (!self.checkItem(eid)) { + delete boards.items[eid]; + delete self.cache[eid]; + removeUnusedTags(boards); + } self.options.refresh(); return; } From 0ab6d4d995f55db569e3318e3af37bde303e8a7f Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 4 Feb 2021 17:26:18 +0100 Subject: [PATCH 16/19] Fix duplicate in kanban --- www/kanban/inner.js | 4 +++- www/kanban/jkanban_cp.js | 36 +++++++++++++++++++++++++----------- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/www/kanban/inner.js b/www/kanban/inner.js index e9c4e30b8..2432c9d8a 100644 --- a/www/kanban/inner.js +++ b/www/kanban/inner.js @@ -416,7 +416,9 @@ define([ framework.onEditableChange(function (unlocked) { editor.setOption('readOnly', !unlocked); $title.prop('disabled', unlocked ? '' : 'disabled'); - $(_field.element).tokenfield(unlocked ? 'enable' : 'disable'); + if (_field) { + $(_field.element).tokenfield(unlocked ? 'enable' : 'disable'); + } $modal.find('nav button.danger').prop('disabled', unlocked ? '' : 'disabled'); offline = !unlocked; diff --git a/www/kanban/jkanban_cp.js b/www/kanban/jkanban_cp.js index 742fbc379..2a3c6991b 100644 --- a/www/kanban/jkanban_cp.js +++ b/www/kanban/jkanban_cp.js @@ -396,10 +396,11 @@ define([ console.log("In drop"); var id1 = Number($(el).attr('data-eid')); + var boardId = Number($(source).closest('.kanban-board').data('id')); // Move to trash? if (target.classList.contains('kanban-trash')) { - self.moveItem(id1); + self.moveItem(boardId, id1); self.onChange(); return; } @@ -419,7 +420,7 @@ define([ } // Move the item - self.moveItem(id1, board2, pos2); + self.moveItem(boardId, id1, board2, pos2); // send event that board has changed self.onChange(); @@ -454,23 +455,36 @@ define([ }); return exists; }; - this.moveItem = function (eid, board, pos) { + this.moveItem = function (source, eid, board, pos) { var boards = self.options.boards; var same = -1; - var from = findItem(eid); - // Remove the item from its board - from.forEach(function (obj) { - obj.board.item.splice(obj.pos, 1); - if (obj.board === board) { same = obj.pos; } - }); + console.error(source, eid, board, pos); + if (source && boards.data[source]) { + // Remove from this board only + var l = boards.data[source].item; + var idx = l.indexOf(eid); + if (idx !== -1) { l.splice(idx, 1); } + if (source === board) { same = idx; } + } else { + // Remove the item from all its board + var from = findItem(eid); + from.forEach(function (obj) { + obj.board.item.splice(obj.pos, 1); + if (obj.board === board) { same = obj.pos; } + }); + } // If it's a deletion and not a duplicate, remove the item data if (!board) { if (!self.checkItem(eid)) { delete boards.items[eid]; delete self.cache[eid]; removeUnusedTags(boards); + self.options.refresh(); } - self.options.refresh(); + return; + } + // If the item already exists in the target board, abort (duplicate) + if (board.item.indexOf(eid) !== -1) { return; } // If it's moved to the same board at a bigger index, decrement the index by one @@ -783,7 +797,7 @@ define([ var list = Util.clone(this.options._boards.list); // Update memory - this.options._boards = boards; + this.options._boards = Util.clone(boards); // If the tab is not focused but a handler already exists: abort if (!Visible.currently() && onVisibleHandler) { return; } From d74b2b631682d0c6d79b7a32f201bd294d7cb7b2 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 4 Feb 2021 17:31:37 +0100 Subject: [PATCH 17/19] Make sure we can't request edit access to ourselves --- www/common/inner/access.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/www/common/inner/access.js b/www/common/inner/access.js index f06028d8e..1dd0c2600 100644 --- a/www/common/inner/access.js +++ b/www/common/inner/access.js @@ -992,8 +992,10 @@ define([ // Also stop for shared folders if (parsed.hashData.type !== 'pad' || parsed.type === 'drive') { return h('div', content); } + var owned = Modal.isOwned(Env, data); + // Request edit access - if (common.isLoggedIn() && ((data.roHref && !data.href) || data.fakeHref)) { + if (common.isLoggedIn() && ((data.roHref && !data.href) || data.fakeHref) && !owned) { var requestButton = h('button.btn.btn-secondary.no-margin.cp-access-margin-right', Messages.requestEdit_button); var requestBlock = h('p', requestButton); @@ -1028,7 +1030,6 @@ define([ // Mute access requests var edPublic = priv.edPublic; - var owned = Modal.isOwned(Env, data); var canMute = data.mailbox && owned === true && ( (typeof (data.mailbox) === "string" && data.owners[0] === edPublic) || data.mailbox[edPublic]); From 3952b2f0131cdb0ebd5f9a9671a5f643ef7ed57e Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 4 Feb 2021 18:12:56 +0100 Subject: [PATCH 18/19] Fix PCS issues: duplicate templates and offline PCS --- www/common/common-ui-elements.js | 10 ++++++++++ www/common/outer/async-store.js | 1 + 2 files changed, 11 insertions(+) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 5d33f09ef..3a514eae7 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -2105,6 +2105,16 @@ define([ var sframeChan = common.getSframeChannel(); var metadataMgr = common.getMetadataMgr(); var privateData = metadataMgr.getPrivateData(); + + if (privateData.offline) { + metadataMgr.onChange(function () { + var privateData = metadataMgr.getPrivateData(); + if (privateData.offline) { return; } + UIElements.getPadCreationScreen(common, cfg, appCfg, cb); + }); + return; + } + var type = metadataMgr.getMetadataLazy().type || privateData.app; var fromFileData = privateData.fromFileData; diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index bb6f02938..900172f16 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -1229,6 +1229,7 @@ define([ var data = obj.data; if (channels.indexOf(data.channel) !== -1) { return; } var id = obj.id; + if (data.channel) { channels.push(data.channel); } var parsed = Hash.parsePadUrl(data.href || data.roHref); if ((!types || types.length === 0 || types.indexOf(parsed.type) !== -1) && !isFiltered(parsed.type, data)) { From 96362b20b1e0c697431d5ff8dfd37f2c085941b4 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 4 Feb 2021 18:16:48 +0100 Subject: [PATCH 19/19] lint compliance --- www/whiteboard/inner.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/www/whiteboard/inner.js b/www/whiteboard/inner.js index 3fbd097e8..5de1f1eb1 100644 --- a/www/whiteboard/inner.js +++ b/www/whiteboard/inner.js @@ -53,7 +53,6 @@ define([ var $type = $('.cp-whiteboard-type'); var $brush = $('.cp-whiteboard-type .brush'); var $move = $('.cp-whiteboard-type .move'); - var $history = $('.cp-whiteboard-history'); var $undo = $('.cp-whiteboard-history .undo'); var $redo = $('.cp-whiteboard-history .redo'); var $text = $('.cp-whiteboard-text button'); @@ -143,7 +142,7 @@ define([ $text.click(function () { $move.click(); - canvas.add(new fabric.Textbox('My Text', { + canvas.add(new Fabric.Textbox('My Text', { fill: brush.color, top: 5, left: 5