Merge branch 'staging' into dark

pull/1/head
yflory 4 years ago
commit 42dfa9a941

@ -1179,7 +1179,18 @@ define([
// getPinnedUsage updates common.account.usage, and other values
// so we can just use those and only check for errors
var $container = $('<span>', {'class':'cp-limit-container'});
var to;
var todo = function (err, data) {
if (to) {
clearTimeout(to);
to = undefined;
}
if (err === 'RPC_NOT_READY') {
to = setTimeout(function () {
common.getPinUsage(teamId, todo);
}, 1000);
return;
}
if (err || !data) { return void console.error(err || 'No data'); }
var usage = data.usage;
@ -1849,6 +1860,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
@ -2087,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;

@ -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 = $('<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;
}
@ -3338,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 = {};
@ -3402,6 +3406,7 @@ define([
});
setTimeout(collapseDrivePath);
spinner.hide();
searching = false;
});
};

@ -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]);

@ -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)) {

@ -141,6 +141,9 @@
border: 0;
background: transparent;
align-self: flex-start;
@media (hover: none) {
margin-right: 20px;
}
}
.cp-kanban-cursors {
@ -166,7 +169,10 @@
flex-wrap: wrap;
touch-action: none;
background: @cp_kanban-item-bg;
.tools_unselectable();
touch-action: none;
cursor: move;
cursor: grab;
margin-bottom: 10px;
&:last-child {
@ -259,12 +265,14 @@
.kanban-board {
position: relative;
transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
margin: 10px;
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);
@ -282,12 +290,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;
min-width: 0;
@ -305,9 +318,6 @@
#kanban-edit {
font-weight: bold;
}
&:hover {
cursor: move;
}
}
footer {
margin: 10px;

@ -134,6 +134,24 @@ define([
};
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);
};
var _updateBoardsThrottle = Util.throttle(_updateBoards, 1000);
var updateBoards = function (framework, kanban, boards) {
if ((now() - _lastUpdate) > 5000 || framework.isLocked()) {
_updateBoards(framework, kanban, boards);
return;
}
_updateBoardsThrottle(framework, kanban, boards);
};
var onRemoteChange = Util.mkEvent();
var editModal;
var PROPERTIES = ['title', 'body', 'tags', 'color'];
@ -146,10 +164,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();
@ -400,7 +417,9 @@ define([
framework.onEditableChange(function (unlocked) {
editor.setOption('readOnly', !unlocked);
$title.prop('disabled', unlocked ? '' : 'disabled');
if (_field) {
$(_field.element).tokenfield(unlocked ? 'enable' : 'disable');
}
$modal.find('nav button.danger').prop('disabled', unlocked ? '' : 'disabled');
offline = !unlocked;
@ -831,7 +850,8 @@ define([
openLink: openLink,
getTags: getExistingTags,
cursors: remoteCursors,
boards: boards
boards: boards,
_boards: Util.clone(boards),
});
framework._.cpNfInner.metadataMgr.onChange(function () {
@ -842,7 +862,7 @@ define([
// If the rendering has changed, update the value and redraw
kanban.options.tagsAnd = tagsAnd;
_tagsAnd = tagsAnd;
kanban.setBoards(kanban.options.boards);
updateBoards(framework, kanban, kanban.options.boards);
});
if (migrated) { framework.localChange(); }
@ -1167,9 +1187,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();
}
@ -1191,8 +1210,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) {

@ -26,13 +26,14 @@ define([
element: '',
gutter: '15px',
widthBoard: '250px',
responsive: '700',
responsive: 0, //'700',
responsivePercentage: false,
boards: {
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 () {},
@ -298,7 +299,9 @@ define([
// Move to trash?
if (target.classList.contains('kanban-trash')) {
list.splice(index1, 1);
if (list.indexOf(id) === -1) {
delete self.options.boards.data[id];
}
self.onChange();
return;
}
@ -393,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;
}
@ -416,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();
@ -443,21 +447,44 @@ define([
});
return res;
};
this.moveItem = function (eid, board, pos) {
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 (source, eid, board, pos) {
var boards = self.options.boards;
var same = -1;
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);
// Remove the item from its board
from.forEach(function (obj) {
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) {
if (!self.checkItem(eid)) {
delete boards.items[eid];
delete self.cache[eid];
removeUnusedTags(boards);
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
@ -707,21 +734,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 +794,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 = Util.clone(boards);
// If the tab is not focused but a handler already exists: abort
if (!Visible.currently() && onVisibleHandler) { return; }
@ -779,7 +814,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]);
});

@ -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()};

@ -88,7 +88,7 @@
#cp-app-whiteboard-delete {
min-width: 40px;
}
.cp-whiteboard-type {
.cp-whiteboard-type, .cp-whiteboard-history {
button {
min-width: 40px;
text-align: center;

@ -53,12 +53,15 @@ define([
var $type = $('.cp-whiteboard-type');
var $brush = $('.cp-whiteboard-type .brush');
var $move = $('.cp-whiteboard-type .move');
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
};
@ -137,6 +140,35 @@ 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();
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()) {
@ -175,6 +207,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();
};
@ -436,7 +478,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 +495,7 @@ define([
});
framework.setContentGetter(function () {
cleanHistory();
var content = canvas.toDatalessJSON();
return {
content: content
@ -475,6 +526,8 @@ define([
};
Messages.undo = "Undo"; // XXX
Messages.redo = "Redo"; // XXX
var initialContent = function () {
return [
h('div#cp-toolbar.cp-toolbar-container'),
@ -494,6 +547,13 @@ 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('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
@ -560,6 +620,7 @@ define([
$('body').append($div.html());
}));
}).nThen(function (waitFor) {
require(['/lib/fabric-history.min.js'], waitFor());
// Framework initialization
Framework.create({

Loading…
Cancel
Save