From fdea16d6013ed32fd0978129366cf22d4a4c4b93 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 5 Mar 2020 12:06:35 +0100 Subject: [PATCH] Tag filter --- .../src/less2/include/alertify.less | 3 + www/kanban/app-kanban.less | 34 ++++- www/kanban/inner.js | 126 ++++++++++++++---- www/kanban/jkanban.js | 2 + 4 files changed, 135 insertions(+), 30 deletions(-) diff --git a/customize.dist/src/less2/include/alertify.less b/customize.dist/src/less2/include/alertify.less index e40c1aa14..f668f1735 100644 --- a/customize.dist/src/less2/include/alertify.less +++ b/customize.dist/src/less2/include/alertify.less @@ -293,6 +293,9 @@ &:not(:first-child) { margin-left: @alertify_padding-base !important; } + &.left { + float: left; + } } } } diff --git a/www/kanban/app-kanban.less b/www/kanban/app-kanban.less index 8014f0f6a..2d10ca6ce 100644 --- a/www/kanban/app-kanban.less +++ b/www/kanban/app-kanban.less @@ -219,7 +219,6 @@ } } #cp-kanban-controls { - height: 40px; padding: 10px; display: flex; position: relative; @@ -228,9 +227,36 @@ position: relative; .cp-kanban-filterTags { display: inline-flex; - width: 250px; - height: 40px; - align-items: center; + align-items: baseline; + flex: 1; + max-width: 80%; + min-width: 150px; + + &> i { + margin-left: 10px; + } + .cp-kanban-filterTags-name { + flex-shrink: 0; + } + .cp-kanban-filterTags-list { + margin-left: 10px; + display: flex; + flex-wrap: wrap; + span { + .tools_unselectable(); + padding: 0 5px; + margin-right: 5px; + margin-top: 5px; + background-color: rgba(0,0,0,0.1); + display: inline-block; + font-size: 14px; + cursor: pointer; + &.active { + background-color: @cryptpad_text_col; + color: #fff; + } + } + } &> .tokenfield { border-radius: 0px; diff --git a/www/kanban/inner.js b/www/kanban/inner.js index a0f4e100e..3fdb09cd2 100644 --- a/www/kanban/inner.js +++ b/www/kanban/inner.js @@ -51,6 +51,7 @@ define([ var verbose = function (x) { console.log(x); }; verbose = function () {}; // comment out to enable verbose logging + var onRedraw = Util.mkEvent(); Messages.kanban_title = "Title"; // XXX Messages.kanban_body = "Body"; // XXX @@ -60,9 +61,9 @@ define([ Messages.kanban_tags = "Filter tags"; // XXX // XXX -// Tag filter: -// remember tags in padAttribute -// click on a tag ==> add it to the list +// Conflicts +// use cursor channel to tell others what you are editing +// add outline + warning inside the modal? var setValueAndCursor = function (input, val, _cursor) { if (!input) { return; } @@ -259,7 +260,7 @@ define([ }; var button = [{ - className: 'danger', // XXX align left + className: 'danger left', name: Messages.kanban_delete, onClick: function () { var boards = kanban.options.boards || {}; @@ -432,6 +433,9 @@ define([ widthBoard: '300px', buttonContent: '❌', readOnly: framework.isReadOnly(), + refresh: function () { + onRedraw.fire(); + }, onChange: function () { verbose("Board object has changed"); framework.localChange(); @@ -607,7 +611,7 @@ define([ } kanban.inEditMode = "new"; // create a form to enter element - var boardId = $(el.parentNode.parentNode).attr("data-id"); + var boardId = $(el).closest('.kanban-board').attr("data-id"); var $item = $('
', {'class': 'kanban-item new-item'}); var $input = getInput().val(name).appendTo($item); kanban.addForm(boardId, $item[0]); @@ -620,10 +624,14 @@ define([ kanban.inEditMode = false; if (!$input.val()) { return; } var id = Util.createRandomInteger(); - kanban.addElement(boardId, { + var item = { "id": id, "title": $input.val(), - }); + }; + if (kanban.options.tags && kanban.options.tags.length) { + item.tags = kanban.options.tags; + } + kanban.addElement(boardId, item); }; $input.blur(save); $input.keydown(function (e) { @@ -673,6 +681,7 @@ define([ var $container = $('#cp-app-kanban-content'); var addControls = function () { + // Quick or normal mode var small = h('span.cp-kanban-view-small.fa.fa-minus'); var big = h('span.cp-kanban-view.fa.fa-bars'); $(small).click(function () { @@ -686,42 +695,108 @@ define([ framework._.sfCommon.setPadAttribute('quickMode', false); }); + // Tags filter var existing = getExistingTags(kanban.options.boards); - var input = UI.dialog.textInput(); + var list = h('div.cp-kanban-filterTags-list'); + var reset = h('i.cp-kanban-filterTags-reset.fa.fa-times'); var tags = h('div.cp-kanban-filterTags', [ - Messages.kanban_tags, - input + h('span.cp-kanban-filterTags-name', Messages.kanban_tags), + reset, + list ]); - var field = UI.tokenField(input, existing).preventDuplicates(function (val) { - UI.warn(Messages._getKey('tags_duplicate', [val])); - }); - field.setTokens([]); + var $reset = $(reset); + var $list = $(list); + + var getTags = function () { + return $list.find('span.active').map(function () { + return $(this).data('tag'); + }).get(); + }; var commitTags = function () { - var t = field.getTokens(); + var t = getTags(); + if (t.length) { + $reset.show(); + } else { + $reset.hide(); + } + framework._.sfCommon.setPadAttribute('tagsFilter', t); kanban.options.tags = t; kanban.setBoards(kanban.options.boards); addEditItemButton(framework, kanban); }; - field.tokenfield.on('tokenfield:createdtoken', commitTags); - field.tokenfield.on('tokenfield:editedoken', commitTags); - field.tokenfield.on('tokenfield:removedtoken', commitTags); + + var redrawList = function (allTags) { + if (!Array.isArray(allTags)) { return; } + $list.empty(); + allTags.forEach(function (t) { + var tag; + $list.append(tag = h('span', { + 'data-tag': t + }, t)); + var $tag = $(tag).click(function () { + if ($tag.hasClass('active')) { + $tag.removeClass('active'); + } else { + $tag.addClass('active'); + } + commitTags(); + }); + }); + }; + redrawList(existing); + + var setTags = function (tags) { + $list.find('span').removeClass('active'); + if (!Array.isArray(tags)) { return; } + tags.forEach(function (t, i) { + if (existing.indexOf(t) === -1) { + // This tag doesn't exist anymore + tags.splice(i, 1); + return; + } + $list.find('span').filter(function () { + return $(this).data('tag') === t; + }).addClass('active'); + }); + framework._.sfCommon.setPadAttribute('tagsFilter', tags); + }; + $reset.hide().click(function () { + setTags([]); + commitTags(); + }); var container = h('div#cp-kanban-controls', [ - tags, // XXX + tags, h('div.cp-kanban-changeView', [ small, big ]) ]); $container.prepend(container); - return container; + + onRedraw.reg(function () { + // Redraw if new tags have been added to items + var old = Sortify(existing); + var t = getTags(); + existing = getExistingTags(kanban.options.boards); + if (old === Sortify(existing)) { return; } // No change + // New tags: + redrawList(existing); + setTags(t); + }); + framework._.sfCommon.getPadAttribute('tagsFilter', function (err, res) { + if (!err && Array.isArray(res)) { + setTags(res); + commitTags(); + } + }); + framework._.sfCommon.getPadAttribute('quickMode', function (err, res) { + if (!err && res) { + $container.addClass('cp-kanban-quick'); + } + }); }; addControls(); - framework._.sfCommon.getPadAttribute('quickMode', function (err, res) { - if (!err && res) { - $container.addClass('cp-kanban-quick'); - } - }); return kanban; }; @@ -795,7 +870,6 @@ define([ var end = input.selectionEnd; var json = kanban.getBoardJSON(id) || kanban.getItemJSON(id); - // XXX only title for now... var oldVal = json && json.title; return { diff --git a/www/kanban/jkanban.js b/www/kanban/jkanban.js index 1678328fb..38ceb99bd 100644 --- a/www/kanban/jkanban.js +++ b/www/kanban/jkanban.js @@ -73,6 +73,7 @@ colorClick: function (el, type) {}, addItemClick: function (el, boardId) {}, renderMd: function (md) {}, + refresh: function () {}, onChange: function () {} }; @@ -526,6 +527,7 @@ } this.options.boards = boards; this.addBoards(); + self.options.refresh(); } this.findBoard = function (id) {