cryptpad/www/kanban/inner.js

856 lines
31 KiB
JavaScript
Raw Normal View History

2018-04-01 16:52:21 +00:00
define([
'jquery',
2018-05-22 16:22:25 +00:00
'json.sortify',
2018-04-01 16:52:21 +00:00
'/bower_components/nthen/index.js',
'/common/sframe-common.js',
'/common/sframe-app-framework.js',
2020-03-03 16:40:01 +00:00
'/common/sframe-common-codemirror.js',
'/common/common-util.js',
'/common/common-hash.js',
2018-05-16 10:22:43 +00:00
'/common/common-interface.js',
'/common/modes.js',
2018-04-01 16:52:21 +00:00
'/customize/messages.js',
2020-03-03 15:20:45 +00:00
'/common/hyperscript.js',
2020-03-03 16:40:01 +00:00
'/common/text-cursor.js',
'/bower_components/chainpad/chainpad.dist.js',
2020-03-03 15:20:45 +00:00
'/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',
2018-04-01 16:52:21 +00:00
'/kanban/jkanban.js',
'/common/jscolor.js',
'css!/kanban/jkanban.css',
2018-07-14 13:15:23 +00:00
'less!/kanban/app-kanban.less'
2018-04-01 16:52:21 +00:00
], function (
$,
2018-05-22 16:22:25 +00:00
Sortify,
2018-04-01 16:52:21 +00:00
nThen,
SFCommon,
Framework,
2020-03-03 16:40:01 +00:00
SFCodeMirror,
Util,
Hash,
2018-05-16 10:22:43 +00:00
UI,
Modes,
2020-03-03 15:20:45 +00:00
Messages,
h,
2020-03-03 16:40:01 +00:00
TextCursor,
ChainPad,
2020-03-03 15:20:45 +00:00
Marked,
CodeMirror)
2018-05-16 10:22:43 +00:00
{
2018-05-17 08:27:16 +00:00
var verbose = function (x) { console.log(x); };
verbose = function () {}; // comment out to enable verbose logging
2020-03-03 15:20:45 +00:00
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
2020-03-03 16:40:01 +00:00
var addEditItemButton = function () {};
var onRemoteChange = Util.mkEvent();
2020-03-03 15:20:45 +00:00
var editModal;
var PROPERTIES = ['title', 'body', 'tags', 'color'];
var BOARD_PROPERTIES = ['title', 'color'];
var createEditModal = function (framework, kanban) {
2020-03-03 16:40:01 +00:00
var dataObject = {};
var isBoard, id;
var commit = function () {
framework.localChange();
kanban.setBoards(kanban.options.boards);
addEditItemButton(framework, kanban);
};
2020-03-03 15:20:45 +00:00
if (editModal) { return editModal; }
2020-03-03 16:42:08 +00:00
var titleInput, tagsDiv, colors, text;
2020-03-03 15:20:45 +00:00
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);
2020-03-03 16:40:01 +00:00
$title.on('change keyup', function () {
dataObject.title = $title.val();
commit();
});
2020-03-03 15:20:45 +00:00
var title = {
getValue: function () {
return $title.val();
},
2020-03-03 16:40:01 +00:00
setValue: function (val, preserveCursor) {
if (!preserveCursor) {
$title.val(val);
} else {
var focus = $title.is(':focus');
var oldVal = $title.val();
var ops = ChainPad.Diff.diff(oldVal, val);
var selects = ['selectionStart', 'selectionEnd'].map(function (attr) {
return TextCursor.transformCursor(titleInput[attr], ops);
});
$title.val(val);
if (focus) { $title.focus(); }
titleInput.selectionStart = selects[0];
titleInput.selectionEnd = selects[1];
}
2020-03-03 15:20:45 +00:00
}
};
// Body
var editor = CodeMirror.fromTextArea(text, {
2020-03-03 16:40:01 +00:00
lineWrapping: true,
2020-03-03 15:20:45 +00:00
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();
},
2020-03-03 16:40:01 +00:00
setValue: function (val, preserveCursor) {
if (isBoard) { return; }
if (!preserveCursor) {
setTimeout(function () {
editor.setValue(val || ' ');
editor.setValue(val || '');
editor.save();
});
} else {
SFCodeMirror.setValueAndCursor(editor, editor.getValue(), val || '');
}
2020-03-03 15:20:45 +00:00
}
};
2020-03-03 16:40:01 +00:00
editor.on('change', function () {
dataObject.body = editor.getValue();
commit();
});
2020-03-03 15:20:45 +00:00
// 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);
2020-03-03 16:40:01 +00:00
var _field, initialTags;
2020-03-03 15:20:45 +00:00
var tags = {
getValue: function () {
if (!_field) { return; }
return _field.getTokens();
},
2020-03-03 16:40:01 +00:00
setValue: function (tags, preserveCursor) {
if (isBoard) { return; }
if (preserveCursor && initialTags && Sortify(tags || []) === initialTags) {
// Don't redraw if there is no change
return;
}
initialTags = Sortify(tags || []);
2020-03-03 15:20:45 +00:00
$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);
2020-03-03 16:40:01 +00:00
_field.setTokens(tags || []);
var commitTags = function () {
dataObject.tags = _field.getTokens();
initialTags = Sortify(dataObject.tags);
commit();
};
_field.tokenfield.on('tokenfield:createdtoken', commitTags);
_field.tokenfield.on('tokenfield:editedoken', commitTags);
_field.tokenfield.on('tokenfield:removedtoken', commitTags);
2020-03-03 15:20:45 +00:00
}
2020-03-03 16:42:08 +00:00
};
2020-03-03 15:20:45 +00:00
// 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 () {
2020-03-03 16:40:01 +00:00
if (color === selectedColor) { return; }
2020-03-03 15:20:45 +00:00
selectedColor = color;
$colors.find('.cp-kanban-palette').removeClass('fa-check');
var $col = $colors.find('.cp-kanban-palette-'+(color || 'nocolor'));
$col.addClass('fa-check');
2020-03-03 16:40:01 +00:00
dataObject.color = color;
commit();
2020-03-03 15:20:45 +00:00
}).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 setId = function (_isBoard, _id) {
isBoard = _isBoard;
id = _id;
2020-03-03 16:40:01 +00:00
var boards = kanban.options.boards || {};
2020-03-03 15:20:45 +00:00
if (_isBoard) {
2020-03-03 16:40:01 +00:00
dataObject = (boards.data || {})[id];
2020-03-03 15:20:45 +00:00
$(content)
.find('#cp-kanban-edit-body, #cp-kanban-edit-tags, [for="cp-kanban-edit-body"], [for="cp-kanban-edit-tags"]')
.hide();
} else {
2020-03-03 16:40:01 +00:00
dataObject = (boards.items || {})[id];
2020-03-03 15:20:45 +00:00
$(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 () {
2020-03-03 16:40:01 +00:00
var boards = kanban.options.boards || {};
if (isBoard) {
var list = boards.list || [];
var idx = list.indexOf(id);
if (idx !== -1) { list.splice(idx, 1); }
delete (boards.data || {})[id];
return void commit();
}
Object.keys(boards.data || {}).forEach(function (boardId) {
var board = boards.data[boardId];
if (!board) { return; }
var items = board.item || [];
var idx = items.indexOf(id);
if (idx !== -1) { items.splice(idx, 1); }
});
delete (boards.items || {})[id];
commit();
2020-03-03 15:20:45 +00:00
},
keys: []
}, {
className: 'primary',
2020-03-03 16:40:01 +00:00
name: Messages.filePicker_close,
2020-03-03 15:20:45 +00:00
onClick: function () {
},
keys: []
}];
var modal = UI.dialog.customModal(content, {
buttons: button
});
2020-03-03 16:40:01 +00:00
onRemoteChange.reg(function () {
var boards = kanban.options.boards || {};
if (isBoard) {
dataObject = (boards.data || {})[id];
} else {
dataObject = (boards.items || {})[id];
}
// Check if our itme has been deleted
if (!dataObject) {
var $frame = $(modal).parents('.alertify').first();
if ($frame[0] && $frame[0].closeModal) {
$frame[0].closeModal();
}
return;
}
// Not deleted, apply updates
PROPERTIES.forEach(function (type) {
editModal[type].setValue(dataObject[type], true);
});
});
2020-03-03 15:20:45 +00:00
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);
};
2020-03-03 16:40:01 +00:00
addEditItemButton = function (framework, kanban) {
2018-05-25 09:49:43 +00:00
if (!kanban) { return; }
if (framework.isReadOnly() || framework.isLocked()) { return; }
2018-05-22 16:22:25 +00:00
var $container = $(kanban.element);
2020-03-02 11:05:09 +00:00
$container.find('.kanban-edit-item').remove();
$container.find('.kanban-item').each(function (i, el) {
var itemId = $(el).attr('data-eid');
2018-05-23 12:24:18 +00:00
$('<button>', {
2020-03-02 11:05:09 +00:00
'class': 'kanban-edit-item btn btn-default fa fa-pencil',
2018-05-23 12:24:18 +00:00
}).click(function (e) {
2020-03-03 15:20:45 +00:00
getItemEditModal(framework, kanban, itemId);
2018-05-22 16:22:25 +00:00
e.stopPropagation();
2018-05-30 13:00:26 +00:00
}).appendTo($(el));
2018-05-22 16:22:25 +00:00
});
2020-03-02 11:05:09 +00:00
$container.find('.kanban-board').each(function (i, el) {
var itemId = $(el).attr('data-id');
$('<button>', {
'class': 'kanban-edit-item btn btn-default fa fa-pencil',
}).click(function (e) {
2020-03-03 15:20:45 +00:00
getBoardEditModal(framework, kanban, itemId);
2020-03-02 11:05:09 +00:00
e.stopPropagation();
}).appendTo($(el).find('.kanban-board-header'));
});
2018-05-22 16:22:25 +00:00
};
// Kanban code
var initKanban = function (framework, boards) {
var items = {};
for (var i=1; i<=6; i++) {
2020-03-02 14:03:32 +00:00
items[i] = {
id: i,
title: Messages._getKey('kanban_item', [i])
};
}
var defaultBoards = {
2020-03-02 14:03:32 +00:00
list: [11, 12, 13],
data: {
2020-03-02 14:03:32 +00:00
"11": {
"id": 11,
"title": Messages.kanban_todo,
"color": "blue",
2020-03-02 14:03:32 +00:00
"item": [1, 2]
},
2020-03-02 14:03:32 +00:00
"12": {
"id": 12,
"title": Messages.kanban_working,
"color": "orange",
2020-03-02 14:03:32 +00:00
"item": [3, 4]
},
2020-03-02 14:03:32 +00:00
"13": {
"id": 13,
"title": Messages.kanban_done,
"color": "green",
2020-03-02 14:03:32 +00:00
"item": [5, 6]
}
},
items: items
};
2018-04-01 16:52:21 +00:00
2018-05-16 10:22:43 +00:00
if (!boards) {
2018-05-17 08:27:16 +00:00
verbose("Initializing with default boards content");
boards = defaultBoards;
} else if (Array.isArray(boards)) {
// XXX also migrate colors!
throw new Error("NEED MIGRATION"); // XXX
} else {
2018-05-17 08:27:16 +00:00
verbose("Initializing with boards content " + boards);
}
// Remove any existing elements
$(".kanban-container-outer").remove();
2018-05-16 17:28:30 +00:00
var getInput = function () {
return $('<input>', {
'type': 'text',
'id': 'kanban-edit',
'size': '30'
2018-05-30 13:00:26 +00:00
}).click(function (e) { e.stopPropagation(); });
2018-05-16 17:28:30 +00:00
};
2018-05-16 10:22:43 +00:00
var kanban = new window.jKanban({
element: '#cp-app-kanban-content',
gutter: '5px',
widthBoard: '300px',
buttonContent: '❌',
readOnly: framework.isReadOnly(),
onChange: function () {
2018-05-17 08:27:16 +00:00
verbose("Board object has changed");
framework.localChange();
2018-05-22 16:22:25 +00:00
if (kanban) {
2020-03-02 11:05:09 +00:00
addEditItemButton(framework, kanban);
2018-05-22 16:22:25 +00:00
}
},
click: function (el) {
if (framework.isReadOnly() || framework.isLocked()) { return; }
if (kanban.inEditMode) {
2018-05-30 13:00:26 +00:00
$(el).focus();
2018-05-17 08:27:16 +00:00
verbose("An edit is already active");
2018-05-30 13:00:26 +00:00
//return;
}
var eid = $(el).attr('data-eid');
kanban.inEditMode = eid;
var name = $(el).text();
$(el).html('');
// Add input
2018-05-16 17:28:30 +00:00
var $input = getInput().val(name).appendTo(el).focus();
$input[0].select();
2018-05-16 17:28:30 +00:00
var save = function () {
// Store the value
var name = $input.val();
// Remove the input
$(el).text(name);
2018-05-16 17:28:30 +00:00
// Save the value for the correct board
var item = kanban.getItemJSON(eid);
item.title = name;
kanban.onChange();
2018-05-16 17:28:30 +00:00
// Unlock edit mode
kanban.inEditMode = false;
2018-05-16 17:28:30 +00:00
};
$input.blur(save);
$input.keydown(function (e) {
if (e.which === 13) {
e.preventDefault();
e.stopPropagation();
save();
if (!$input.val()) { return; }
if (!$(el).closest('.kanban-item').is(':last-child')) { return; }
$(el).closest('.kanban-board').find('.kanban-title-button.fa-plus').click();
2018-05-16 17:28:30 +00:00
return;
}
if (e.which === 27) {
e.preventDefault();
e.stopPropagation();
$(el).text(name);
kanban.inEditMode = false;
2020-03-02 11:05:09 +00:00
addEditItemButton(framework, kanban);
2018-05-16 17:28:30 +00:00
return;
}
});
2018-04-01 16:52:21 +00:00
},
2018-05-16 17:28:30 +00:00
boardTitleClick: function (el, e) {
e.stopPropagation();
if (framework.isReadOnly() || framework.isLocked()) { return; }
if (kanban.inEditMode) {
2018-05-30 13:00:26 +00:00
$(el).focus();
2018-05-17 08:27:16 +00:00
verbose("An edit is already active");
2018-05-30 13:00:26 +00:00
//return;
}
var boardId = $(el).closest('.kanban-board').attr("data-id");
kanban.inEditMode = boardId;
var name = $(el).text();
$(el).html('');
2018-05-16 17:28:30 +00:00
var $input = getInput().val(name).appendTo(el).focus();
$input[0].select();
2018-05-16 17:28:30 +00:00
var save = function () {
// Store the value
var name = $input.val();
2019-12-12 15:09:07 +00:00
if (!name || !name.trim()) {
return kanban.onChange();
}
2018-05-16 17:28:30 +00:00
// Remove the input
$(el).text(name);
2018-05-16 17:28:30 +00:00
// Save the value for the correct board
kanban.getBoardJSON(boardId).title = name;
kanban.onChange();
2018-05-16 17:28:30 +00:00
// Unlock edit mode
kanban.inEditMode = false;
2018-05-16 17:28:30 +00:00
};
$input.blur(save);
$input.keydown(function (e) {
if (e.which === 13) {
e.preventDefault();
e.stopPropagation();
save();
return;
}
if (e.which === 27) {
e.preventDefault();
e.stopPropagation();
$(el).text(name);
kanban.inEditMode = false;
return;
}
});
},
2018-09-13 14:08:27 +00:00
colorClick: function (el, type) {
if (framework.isReadOnly() || framework.isLocked()) { return; }
2018-09-13 14:08:27 +00:00
verbose("on color click");
var boardJSON;
var board;
if (type === "board") {
verbose("board color click");
board = $(el.parentNode).attr("data-id");
boardJSON = kanban.getBoardJSON(board);
} else {
verbose("item color click");
board = $(el.parentNode.parentNode).attr("data-id");
var pos = kanban.findElementPosition(el);
boardJSON = kanban.getBoardJSON(board).item[pos];
}
var onchange = function (colorL) {
var elL = el;
2018-09-13 14:08:27 +00:00
var typeL = type;
var boardJSONL;
var boardL;
if (typeL === "board") {
verbose("board color change");
boardL = $(elL.parentNode).attr("data-id");
boardJSONL = kanban.getBoardJSON(boardL);
} else {
verbose("item color change");
boardL = $(elL.parentNode.parentNode).attr("data-id");
var pos = kanban.findElementPosition(elL);
boardJSONL = kanban.getBoardJSON(boardL).item[pos];
}
var currentColor = boardJSONL.color;
verbose("Current color " + currentColor);
if (currentColor !== colorL.toString()) {
$(elL).removeClass("kanban-header-" + currentColor);
boardJSONL.color = colorL.toString();
kanban.onChange();
}
};
var jscolorL;
el._jscLinkedInstance = undefined;
jscolorL = new window.jscolor(el,{showOnClick: false, onFineChange: onchange, valueElement:undefined});
jscolorL.show();
var currentColor = boardJSON.color;
if (currentColor === undefined) {
currentColor = '';
2018-09-13 14:08:27 +00:00
}
jscolorL.fromString(currentColor);
},
2018-05-22 16:22:25 +00:00
addItemClick: function (el) {
if (framework.isReadOnly() || framework.isLocked()) { return; }
2018-05-16 17:28:30 +00:00
if (kanban.inEditMode) {
2018-05-30 13:00:26 +00:00
$(el).focus();
2018-05-17 08:27:16 +00:00
verbose("An edit is already active");
2018-05-30 13:00:26 +00:00
//return;
2018-05-16 17:28:30 +00:00
}
kanban.inEditMode = "new";
// create a form to enter element
2018-05-22 16:22:25 +00:00
var boardId = $(el.parentNode.parentNode).attr("data-id");
2019-12-09 10:03:11 +00:00
var $item = $('<div>', {'class': 'kanban-item new-item'});
2018-05-16 17:28:30 +00:00
var $input = getInput().val(name).appendTo($item);
kanban.addForm(boardId, $item[0]);
$input.focus();
var save = function () {
$item.remove();
2018-05-22 16:22:25 +00:00
kanban.inEditMode = false;
if (!$input.val()) { return; }
2020-03-02 14:03:32 +00:00
var id = Util.createRandomInteger();
kanban.addElement(boardId, {
"id": id,
2018-05-16 17:28:30 +00:00
"title": $input.val(),
2018-05-16 10:22:43 +00:00
});
};
2018-05-16 17:28:30 +00:00
$input.blur(save);
$input.keydown(function (e) {
if (e.which === 13) {
e.preventDefault();
e.stopPropagation();
save();
if (!$input.val()) { return; }
$(el).closest('.kanban-board').find('.kanban-title-button.fa-plus').click();
2018-05-16 17:28:30 +00:00
return;
}
if (e.which === 27) {
e.preventDefault();
e.stopPropagation();
$item.remove();
2018-05-16 17:28:30 +00:00
kanban.inEditMode = false;
return;
}
});
},
addItemButton: true,
2018-05-23 12:24:18 +00:00
boards: boards
});
2018-04-01 16:52:21 +00:00
var addBoardDefault = document.getElementById('kanban-addboard');
2018-05-23 12:24:18 +00:00
$(addBoardDefault).attr('title', Messages.kanban_addBoard);
addBoardDefault.addEventListener('click', function () {
if (framework.isReadOnly()) { return; }
/*var counter = 1;
2018-05-16 10:22:43 +00:00
// Get the new board id
2018-05-22 16:22:25 +00:00
var boardExists = function (b) { return b.id === "board" + counter; };
while (kanban.options.boards.some(boardExists)) { counter++; }
*/
2020-03-02 14:03:32 +00:00
var id = Util.createRandomInteger();
2018-04-01 16:52:21 +00:00
kanban.addBoard({
"id": id,
2018-05-16 14:45:16 +00:00
"title": Messages.kanban_newBoard,
"item": []
});
kanban.onChange();
});
2018-04-01 16:52:21 +00:00
return kanban;
};
2018-04-01 16:52:21 +00:00
2018-05-23 12:24:18 +00:00
var mkHelpMenu = function (framework) {
var $toolbarContainer = $('#cp-app-kanban-container');
2020-01-09 16:30:15 +00:00
$toolbarContainer.prepend(framework._.sfCommon.getBurnAfterReadingWarning());
2018-05-23 12:24:18 +00:00
var helpMenu = framework._.sfCommon.createHelpMenu(['kanban']);
$toolbarContainer.prepend(helpMenu.menu);
framework._.toolbar.$drawer.append(helpMenu.button);
};
// Start of the main loop
var andThen2 = function (framework) {
2018-04-01 16:52:21 +00:00
2018-05-22 16:22:25 +00:00
var kanban;
var $container = $('#cp-app-kanban-content');
2018-05-23 12:24:18 +00:00
mkHelpMenu(framework);
if (framework.isReadOnly()) {
$container.addClass('cp-app-readonly');
2018-07-11 08:50:42 +00:00
} else {
2018-07-11 09:35:44 +00:00
framework.setFileImporter({}, function (content /*, file */) {
2018-07-11 08:50:42 +00:00
var parsed;
try { parsed = JSON.parse(content); }
catch (e) { return void console.error(e); }
return { content: parsed };
});
}
2018-07-11 08:50:42 +00:00
framework.setFileExporter('.json', function () {
2018-10-18 16:50:38 +00:00
return new Blob([JSON.stringify(kanban.getBoardsJSON(), 0, 2)], {
2018-07-11 08:50:42 +00:00
type: 'application/json',
});
});
framework.onEditableChange(function (unlocked) {
if (framework.isReadOnly()) { return; }
2018-05-25 09:49:43 +00:00
if (!kanban) { return; }
if (unlocked) {
2020-03-02 11:05:09 +00:00
addEditItemButton(framework, kanban);
kanban.options.readOnly = false;
return void $container.removeClass('cp-app-readonly');
}
kanban.options.readOnly = true;
$container.addClass('cp-app-readonly');
});
2018-04-01 16:52:21 +00:00
var getCursor = function () {
if (!kanban || !kanban.inEditMode) { return; }
try {
var id = kanban.inEditMode;
var newBoard;
var $el = $container.find('[data-id="'+id+'"]');
if (id === "new") {
$el = $container.find('.kanban-item.new-item');
newBoard = $el.closest('.kanban-board').attr('data-id');
} else if (!$el.length) {
$el = $container.find('[data-eid="'+id+'"]');
}
if (!$el.length) { return; }
var $input = $el.find('input');
if (!$input.length) { return; }
var input = $input[0];
var val = ($input.val && $input.val()) || '';
var start = input.selectionStart;
var end = input.selectionEnd;
var json = kanban.getBoardJSON(id) || kanban.getItemJSON(id);
// XXX only title for now...
var oldVal = json && json.title;
return {
id: id,
newBoard: newBoard,
value: val,
start: start,
end: end,
oldValue: oldVal
};
} catch (e) {
console.error(e);
return {};
}
};
var restoreCursor = function (data) {
2020-03-02 14:03:32 +00:00
if (!data) { return; }
try {
var id = data.id;
// An item was being added: add a new item
if (id === "new" && !data.oldValue) {
var $newBoard = $('.kanban-board[data-id="'+data.newBoard+'"]');
$newBoard.find('.kanban-title-button.fa-plus').click();
var $newInput = $newBoard.find('.kanban-item:last-child input');
$newInput.val(data.value);
$newInput[0].selectionStart = data.start;
$newInput[0].selectionEnd = data.end;
return;
}
// Edit a board title or a card title
var $el = $container.find('.kanban-board[data-id="'+id+'"]');
if (!$el.length) {
$el = $container.find('.kanban-item[data-eid="'+id+'"]');
}
if (!$el.length) { return; }
var json = kanban.getBoardJSON(id) || kanban.getItemJSON(id);
// if the value was changed by a remote user, abort
if (data.oldValue !== json.title) { return; }
// Editing a board title...
$el.find('.kanban-title-board, .kanban-item-text').click();
var $input = $el.find('input');
if ($input.length) {
$input.val(data.value);
$input[0].selectionStart = data.start;
$input[0].selectionEnd = data.end;
}
} catch (e) {
console.error(e);
return;
}
};
framework.onContentUpdate(function (newContent) {
2018-05-22 16:22:25 +00:00
// Init if needed
if (!kanban) {
kanban = initKanban(framework, (newContent || {}).content);
2020-03-02 11:05:09 +00:00
addEditItemButton(framework, kanban);
2018-05-22 16:22:25 +00:00
return;
}
// Need to update the content
2018-05-17 08:27:16 +00:00
verbose("Content should be updated to " + newContent);
var currentContent = kanban.getBoardsJSON();
var remoteContent = newContent.content;
2018-05-16 10:22:43 +00:00
2018-05-22 16:22:25 +00:00
if (Sortify(currentContent) !== Sortify(remoteContent)) {
var cursor = getCursor();
verbose("Content is different.. Applying content");
kanban.setBoards(remoteContent);
kanban.inEditMode = false;
2020-03-02 11:05:09 +00:00
addEditItemButton(framework, kanban);
restoreCursor(cursor);
2020-03-03 16:40:01 +00:00
onRemoteChange.fire();
}
2018-04-01 16:52:21 +00:00
});
framework.setContentGetter(function () {
2018-05-25 09:49:43 +00:00
if (!kanban) {
return {
content: {}
2018-05-25 09:49:43 +00:00
};
}
var content = kanban.getBoardsJSON();
2018-05-17 08:27:16 +00:00
verbose("Content current value is " + content);
return {
content: content
};
2018-04-01 16:52:21 +00:00
});
2020-03-02 11:05:09 +00:00
var cleanData = function (boards) {
if (typeof(boards) !== "object") { return; }
var items = boards.items || {};
var data = boards.data || {};
var list = boards.list || [];
Object.keys(data).forEach(function (id) {
2020-03-02 14:03:32 +00:00
if (list.indexOf(Number(id)) === -1) { delete data[id]; }
2020-03-02 11:05:09 +00:00
});
Object.keys(items).forEach(function (eid) {
var exists = Object.keys(data).some(function (id) {
2020-03-02 14:03:32 +00:00
return (data[id].item || []).indexOf(Number(eid)) !== -1;
2020-03-02 11:05:09 +00:00
});
if (!exists) { delete items[eid]; }
});
framework.localChange();
};
2018-05-16 10:22:43 +00:00
framework.onReady(function () {
$("#cp-app-kanban-content").focus();
2020-03-02 11:05:09 +00:00
var content = kanban.getBoardsJSON();
cleanData(content);
});
2018-04-01 16:52:21 +00:00
2018-05-25 09:49:43 +00:00
framework.onDefaultContentNeeded(function () {
kanban = initKanban(framework);
});
framework.start();
2018-04-01 16:52:21 +00:00
};
var main = function () {
// var framework;
2018-04-01 16:52:21 +00:00
nThen(function (waitFor) {
// Framework initialization
Framework.create({
toolbarContainer: '#cme_toolbox',
contentContainer: '#cp-app-kanban-editor',
2018-05-16 10:22:43 +00:00
}, waitFor(function (framework) {
andThen2(framework);
2018-04-01 16:52:21 +00:00
}));
});
};
main();
});