From c8cca350736216f47bb1cbd7595e698fc2667d33 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 3 Mar 2020 16:20:45 +0100 Subject: [PATCH] Add edit modal in kanban --- .../src/less2/include/alertify.less | 2 +- www/kanban/app-kanban.less | 72 +++++ www/kanban/inner.js | 249 +++++++++++++++++- www/kanban/jkanban.js | 1 - 4 files changed, 308 insertions(+), 16 deletions(-) diff --git a/customize.dist/src/less2/include/alertify.less b/customize.dist/src/less2/include/alertify.less index 2960c1c3b..e40c1aa14 100644 --- a/customize.dist/src/less2/include/alertify.less +++ b/customize.dist/src/less2/include/alertify.less @@ -277,7 +277,7 @@ margin-bottom: 15px; } - button { + button:not('.pure-button') { display: inline-block; position: relative; margin: 6px 8px; diff --git a/www/kanban/app-kanban.less b/www/kanban/app-kanban.less index 615a5c904..5596ee978 100644 --- a/www/kanban/app-kanban.less +++ b/www/kanban/app-kanban.less @@ -15,6 +15,78 @@ max-height: 100%; min-height: auto; + @palette1: #FFD4D4; + @palette2: #FFDECA; + @palette3: #FFE69C; + @palette4: #DBFFB7; + @palette5: #AFFDC2; + @palette6: #C9FFFE; + @palette7: #C8D6FF; + @palette8: #E4CAFF; + + + .cp-kanban-palette-color1 { + background-color: @palette1; + } + .cp-kanban-palette-color2 { + background-color: @palette2; + } + .cp-kanban-palette-color3 { + background-color: @palette3; + } + .cp-kanban-palette-color4 { + background-color: @palette4; + } + .cp-kanban-palette-color5 { + background-color: @palette5; + } + .cp-kanban-palette-color6 { + background-color: @palette6; + } + .cp-kanban-palette-color7 { + background-color: @palette7; + } + .cp-kanban-palette-color8 { + background-color: @palette8; + } + + #cp-kanban-edit-body { + border: 1px solid @colortheme_modal-input; + .CodeMirror { + height: 105px; + } + .CodeMirror-scroll { + box-sizing: content-box; + } + .cp-markdown-toolbar { + background-color: #eee; + color: @cryptpad_text_col; + } + margin-bottom: 15px; + } + #cp-kanban-edit-colors { + display: flex; + justify-content: space-between; + .cp-kanban-palette { + display: inline-block; + border-radius: 50%; + height: 30px; + width: 30px; + text-align: center; + line-height: 30px; + color: @cryptpad_text_col; + } + .cp-kanban-palette-nocolor { + border: 1px solid @cryptpad_text_col; + } + } + #cp-kanban-edit-tags { + .tokenfield { + margin: 0; + } + margin-bottom: 15px; + } + #cp-app-kanban-container { flex: 1; display: flex; diff --git a/www/kanban/inner.js b/www/kanban/inner.js index 0d3e52a35..99a36dde7 100644 --- a/www/kanban/inner.js +++ b/www/kanban/inner.js @@ -9,10 +9,21 @@ define([ '/common/common-interface.js', '/common/modes.js', '/customize/messages.js', + '/common/hyperscript.js', + '/bower_components/marked/marked.min.js', + 'cm/lib/codemirror', + + 'cm/mode/gfm/gfm', + + 'css!/bower_components/codemirror/lib/codemirror.css', + 'css!/bower_components/codemirror/addon/dialog/dialog.css', + 'css!/bower_components/codemirror/addon/fold/foldgutter.css', + + + '/kanban/jkanban.js', '/common/jscolor.js', 'css!/kanban/jkanban.css', - 'less!/kanban/app-kanban.less' ], function ( $, @@ -24,7 +35,10 @@ define([ Hash, UI, Modes, - Messages) + Messages, + h, + Marked, + CodeMirror) { var verbose = function (x) { console.log(x); }; @@ -32,6 +46,222 @@ define([ var COLORS = ['yellow', 'green', 'orange', 'blue', 'red', 'purple', 'cyan', 'lightgreen', 'lightblue']; + Messages.kanban_title = "Title"; // XXX + Messages.kanban_body = "Body"; // XXX + Messages.kanban_color = "Color"; // XXX + Messages.kanban_submit = "Submit"; // XXX + Messages.kanban_delete = "Delete"; // XXX + + + var editModal; + var PROPERTIES = ['title', 'body', 'tags', 'color']; + var BOARD_PROPERTIES = ['title', 'color']; + var createEditModal = function (framework, kanban) { + if (editModal) { return editModal; } + var titleInput, tagsDiv, color, text; + var content = h('div', [ + h('label', {for:'cp-kanban-edit-title'}, Messages.kanban_title), + titleInput = h('input#cp-kanban-edit-title'), + h('label', {for:'cp-kanban-edit-body'}, Messages.kanban_body), + h('div#cp-kanban-edit-body', [ + text = h('textarea') + ]), + h('label', {for:'cp-kanban-edit-tags'}, Messages.fm_tagsName), + tagsDiv = h('div#cp-kanban-edit-tags'), + h('label', {for:'cp-kanban-edit-color'}, Messages.kanban_color), + colors = h('div#cp-kanban-edit-colors'), + ]); + + // Title + var $title = $(titleInput); + var title = { + getValue: function () { + return $title.val(); + }, + setValue: function (val) { + $title.val(val); + } + }; + + // Body + var editor = CodeMirror.fromTextArea(text, { + lineNumbers: true, + styleActiveLine : true, + mode: "gfm" + }); + var common = framework._.sfCommon; + var markdownTb = common.createMarkdownToolbar(editor); + $(text).before(markdownTb.toolbar); + $(markdownTb.toolbar).show(); + editor.refresh(); + var body = { + getValue: function () { + return editor.getValue(); + }, + setValue: function (val) { + console.log(val); + setTimeout(function () { + editor.setValue(val || ' '); + editor.setValue(val || ''); + editor.save(); + }); + } + }; + + // Tags + var getExisting = function () { + var tags = []; + var boards = kanban.options.boards || {}; + Object.keys(boards.items || {}).forEach(function (id) { + var data = boards.items[id]; + if (!Array.isArray(data.tags)) { return; } + data.tags.forEach(function (tag) { + if (tags.indexOf(tag) === -1) { tags.push(tag); } + }); + }); + tags.sort(); + return tags; + }; + var $tags = $(tagsDiv); + var _field; + var tags = { + getValue: function () { + if (!_field) { return; } + return _field.getTokens(); + }, + setValue: function (tags) { + $tags.empty(); + var input = UI.dialog.textInput(); + $tags.append(input); + var existing = getExisting(); + _field = UI.tokenField(input, existing).preventDuplicates(function (val) { + UI.warn(Messages._getKey('tags_duplicate', [val])); + }); + $tags.append(_field); + setTimeout(function () { + _field.setTokens(tags || []); + }); + } + } + + // Colors + var $colors = $(colors); + var palette = ['']; + for (var i=1; i<=8; i++) { palette.push('color'+i); } + var selectedColor = ''; + palette.forEach(function (color) { + var $color = $(h('span.cp-kanban-palette.fa')); + $color.addClass('cp-kanban-palette-'+(color || 'nocolor')); + $color.click(function () { + selectedColor = color; + $colors.find('.cp-kanban-palette').removeClass('fa-check'); + var $col = $colors.find('.cp-kanban-palette-'+(color || 'nocolor')); + $col.addClass('fa-check'); + }).appendTo($colors); + }); + var color = { + getValue: function () { + return selectedColor; + }, + setValue: function (color) { + $colors.find('.cp-kanban-palette').removeClass('fa-check'); + var $col = $colors.find('.cp-kanban-palette-'+(color || 'nocolor')); + $col.addClass('fa-check'); + } + }; + + var isBoard, id; + var setId = function (_isBoard, _id) { + isBoard = _isBoard; + id = _id; + if (_isBoard) { + $(content) + .find('#cp-kanban-edit-body, #cp-kanban-edit-tags, [for="cp-kanban-edit-body"], [for="cp-kanban-edit-tags"]') + .hide(); + } else { + $(content) + .find('#cp-kanban-edit-body, #cp-kanban-edit-tags, [for="cp-kanban-edit-body"], [for="cp-kanban-edit-tags"]') + .show(); + } + }; + + var button = [{ + className: 'danger', // XXX align left + name: Messages.kanban_delete, + onClick: function () { + // XXX + }, + keys: [] + }, { + className: 'cancel', + name: Messages.cancel, + onClick: function () {}, + keys: [] + }, { + className: 'primary', + name: Messages.kanban_submit, + onClick: function () { + var boards = kanban.options.boards || {}; + if (isBoard) { + var data = (boards.data || {})[id]; + if (!data) { return; } // XXX deleted by someone else? + BOARD_PROPERTIES.forEach(function (type) { + if (!editModal[type]) { return; } + data[type] = editModal[type].getValue(); + }); + framework.localChange(); + return; + } + var item = (boards.items || {})[id]; + if (!item) { return; } // XXX deleted by someone else? + PROPERTIES.forEach(function (type) { + if (!editModal[type]) { return; } + item[type] = editModal[type].getValue(); + }); + framework.localChange(); + }, + keys: [] + }]; + var modal = UI.dialog.customModal(content, { + buttons: button + }); + return { + modal: modal, + setId: setId, + title: title, + body: body, + tags: tags, + color: color + }; + }; + var getItemEditModal = function (framework, kanban, eid) { + // Create modal if needed + if (!editModal) { editModal = createEditModal(framework, kanban); } + editModal.setId(false, eid); + var boards = kanban.options.boards || {}; + var item = (boards.items || {})[eid]; + if (!item) { return void UI.warn(Messages.error); } + PROPERTIES.forEach(function (type) { + if (!editModal[type]) { return; } + editModal[type].setValue(item[type]); + }); + UI.openCustomModal(editModal.modal); + }; + var getBoardEditModal = function (framework, kanban, id) { + // Create modal if needed + if (!editModal) { editModal = createEditModal(framework, kanban); } + + editModal.setId(true, id); + var boards = kanban.options.boards || {}; + var board = (boards.data || {})[id]; + if (!board) { return void UI.warn(Messages.error); } + BOARD_PROPERTIES.forEach(function (type) { + if (!editModal[type]) { return; } + editModal[type].setValue(board[type]); + }); + UI.openCustomModal(editModal.modal); + }; + var addEditItemButton = function (framework, kanban) { if (!kanban) { return; } if (framework.isReadOnly() || framework.isLocked()) { return; } @@ -42,16 +272,8 @@ define([ $('