Merge branch 'kanban' into staging
This commit is contained in:
@@ -9,7 +9,7 @@ define(function() {
|
||||
/* Select the buttons displayed on the main page to create new collaborative sessions
|
||||
* Existing types : pad, code, poll, slide
|
||||
*/
|
||||
config.availablePadTypes = ['drive', 'pad', 'code', 'slide', 'poll', 'whiteboard', 'file', 'todo', 'contacts'];
|
||||
config.availablePadTypes = ['drive', 'pad', 'code', 'slide', 'poll', 'kanban', 'whiteboard', 'file', 'todo', 'contacts'];
|
||||
config.registeredOnlyTypes = ['file', 'contacts'];
|
||||
|
||||
/* Cryptpad apps use a common API to display notifications to users
|
||||
@@ -81,6 +81,7 @@ define(function() {
|
||||
whiteboard: 'fa-paint-brush',
|
||||
todo: 'fa-tasks',
|
||||
contacts: 'fa-users',
|
||||
kanban: 'fa-list-alt',
|
||||
};
|
||||
|
||||
// Ability to create owned pads and expiring pads through a new pad creation screen.
|
||||
|
||||
@@ -12,8 +12,10 @@ define([
|
||||
'/customize/loading.js',
|
||||
'/common/test.js',
|
||||
|
||||
'/common/jquery-ui/jquery-ui.min.js',
|
||||
'/bower_components/bootstrap-tokenfield/dist/bootstrap-tokenfield.js',
|
||||
'css!/common/tippy/tippy.css',
|
||||
'css!/common/jquery-ui/jquery-ui.min.css'
|
||||
], function ($, Messages, Util, Hash, Notifier, AppConfig,
|
||||
Alertify, Tippy, Pages, h, Loading, Test) {
|
||||
var UI = {};
|
||||
@@ -183,11 +185,17 @@ define([
|
||||
]);
|
||||
};
|
||||
|
||||
UI.tokenField = function (target) {
|
||||
UI.tokenField = function (target, autocomplete) {
|
||||
var t = {
|
||||
element: target || h('input'),
|
||||
};
|
||||
var $t = t.tokenfield = $(t.element).tokenfield();
|
||||
var $t = t.tokenfield = $(t.element).tokenfield({
|
||||
autocomplete: {
|
||||
source: autocomplete,
|
||||
delay: 100
|
||||
},
|
||||
showAutocompleteOnFocus: false
|
||||
});
|
||||
|
||||
t.getTokens = function (ignorePending) {
|
||||
var tokens = $t.tokenfield('getTokens').map(function (token) {
|
||||
@@ -210,10 +218,17 @@ define([
|
||||
|
||||
t.preventDuplicates = function (cb) {
|
||||
$t.on('tokenfield:createtoken', function (ev) {
|
||||
// Close the suggest list when a token is added because we're going to wipe the input
|
||||
var $input = $t.closest('.tokenfield').find('.token-input');
|
||||
$input.autocomplete('close');
|
||||
|
||||
var val;
|
||||
ev.attrs.value = ev.attrs.value.toLowerCase();
|
||||
if (t.getTokens(true).some(function (t) {
|
||||
if (t === ev.attrs.value) { return ((val = t)); }
|
||||
if (t === ev.attrs.value) {
|
||||
ev.preventDefault();
|
||||
return ((val = t));
|
||||
}
|
||||
})) {
|
||||
ev.preventDefault();
|
||||
if (typeof(cb) === 'function') { cb(val); }
|
||||
@@ -241,7 +256,7 @@ define([
|
||||
return t;
|
||||
};
|
||||
|
||||
dialog.tagPrompt = function (tags, cb) {
|
||||
dialog.tagPrompt = function (tags, existing, cb) {
|
||||
var input = dialog.textInput();
|
||||
|
||||
var tagger = dialog.frame([
|
||||
@@ -255,7 +270,7 @@ define([
|
||||
dialog.nav(),
|
||||
]);
|
||||
|
||||
var field = UI.tokenField(input).preventDuplicates(function (val) {
|
||||
var field = UI.tokenField(input, existing).preventDuplicates(function (val) {
|
||||
UI.warn(Messages._getKey('tags_duplicate', [val]));
|
||||
});
|
||||
|
||||
@@ -396,7 +411,7 @@ define([
|
||||
stopListening(listener);
|
||||
cb();
|
||||
});
|
||||
listener = listenForKeys(close, close, ok);
|
||||
listener = listenForKeys(close, close);
|
||||
var $ok = $(ok).click(close);
|
||||
|
||||
document.body.appendChild(frame);
|
||||
|
||||
@@ -23,20 +23,27 @@ define([
|
||||
}
|
||||
|
||||
UIElements.updateTags = function (common, href) {
|
||||
var sframeChan = common.getSframeChannel();
|
||||
sframeChan.query('Q_TAGS_GET', href || null, function (err, res) {
|
||||
if (err || res.error) {
|
||||
if (res.error === 'NO_ENTRY') {
|
||||
UI.alert(Messages.tags_noentry);
|
||||
var existing, tags;
|
||||
NThen(function(waitFor) {
|
||||
common.getSframeChannel().query("Q_GET_ALL_TAGS", null, waitFor(function(err, res) {
|
||||
if (err || res.error) { return void console.error(err || res.error); }
|
||||
existing = Object.keys(res.tags).sort();
|
||||
}));
|
||||
}).nThen(function (waitFor) {
|
||||
common.getPadAttribute('tags', waitFor(function (err, res) {
|
||||
if (err) {
|
||||
if (err === 'NO_ENTRY') {
|
||||
UI.alert(Messages.tags_noentry);
|
||||
}
|
||||
waitFor.abort();
|
||||
return void console.error(err);
|
||||
}
|
||||
return void console.error(err || res.error);
|
||||
}
|
||||
UI.dialog.tagPrompt(res.data, function (tags) {
|
||||
if (!Array.isArray(tags)) { return; }
|
||||
sframeChan.event('EV_TAGS_SET', {
|
||||
tags: tags,
|
||||
href: href,
|
||||
});
|
||||
tags = res || [];
|
||||
}), href);
|
||||
}).nThen(function () {
|
||||
UI.dialog.tagPrompt(tags, existing, function (newTags) {
|
||||
if (!Array.isArray(newTags)) { return; }
|
||||
common.setPadAttribute('tags', newTags, null, href);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
7
www/common/jquery-ui/jquery-ui.min.css
vendored
Normal file
7
www/common/jquery-ui/jquery-ui.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
6
www/common/jquery-ui/jquery-ui.min.js
vendored
Normal file
6
www/common/jquery-ui/jquery-ui.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -636,18 +636,7 @@ define([
|
||||
|
||||
// Tags
|
||||
Store.listAllTags = function (data, cb) {
|
||||
var all = [];
|
||||
var files = Util.find(store.proxy, ['drive', 'filesData']);
|
||||
|
||||
if (typeof(files) !== 'object') { return cb({error: 'invalid_drive'}); }
|
||||
Object.keys(files).forEach(function (k) {
|
||||
var file = files[k];
|
||||
if (!Array.isArray(file.tags)) { return; }
|
||||
file.tags.forEach(function (tag) {
|
||||
if (all.indexOf(tag) === -1) { all.push(tag); }
|
||||
});
|
||||
});
|
||||
cb(all);
|
||||
cb(store.userObject.getTagsList());
|
||||
};
|
||||
|
||||
// Templates
|
||||
|
||||
@@ -393,6 +393,7 @@ define([
|
||||
// If we have a stronger hash, use it for pad attributes
|
||||
href = window.location.pathname + '#' + hashes.editHash;
|
||||
}
|
||||
if (data.href) { href = data.href; }
|
||||
Cryptpad.getPadAttribute(data.key, function (e, data) {
|
||||
cb({
|
||||
error: e,
|
||||
@@ -406,6 +407,7 @@ define([
|
||||
// If we have a stronger hash, use it for pad attributes
|
||||
href = window.location.pathname + '#' + hashes.editHash;
|
||||
}
|
||||
if (data.href) { href = data.href; }
|
||||
Cryptpad.setPadAttribute(data.key, data.value, function (e) {
|
||||
cb({error:e});
|
||||
}, href);
|
||||
@@ -573,19 +575,6 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
sframeChan.on('Q_TAGS_GET', function (data, cb) {
|
||||
Cryptpad.getPadTags(data, function (err, data) {
|
||||
cb({
|
||||
error: err,
|
||||
data: data
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
sframeChan.on('EV_TAGS_SET', function (data) {
|
||||
Cryptpad.resetTags(data.href, data.tags);
|
||||
});
|
||||
|
||||
sframeChan.on('Q_PIN_GET_USAGE', function (data, cb) {
|
||||
Cryptpad.isOverPinLimit(function (err, overLimit, data) {
|
||||
cb({
|
||||
@@ -606,6 +595,15 @@ define([
|
||||
Cryptpad.removeOwnedChannel(channel, cb);
|
||||
});
|
||||
|
||||
sframeChan.on('Q_GET_ALL_TAGS', function (data, cb) {
|
||||
Cryptpad.listAllTags(function (err, tags) {
|
||||
cb({
|
||||
error: err,
|
||||
tags: tags
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (cfg.addRpc) {
|
||||
cfg.addRpc(sframeChan, Cryptpad, Utils);
|
||||
}
|
||||
|
||||
@@ -235,17 +235,20 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
funcs.getPadAttribute = function (key, cb) {
|
||||
// href is optional here: if not provided, we use the href of the current tab
|
||||
funcs.getPadAttribute = function (key, cb, href) {
|
||||
ctx.sframeChan.query('Q_GET_PAD_ATTRIBUTE', {
|
||||
key: key
|
||||
key: key,
|
||||
href: href
|
||||
}, function (err, res) {
|
||||
cb (err || res.error, res.data);
|
||||
});
|
||||
};
|
||||
funcs.setPadAttribute = function (key, value, cb) {
|
||||
funcs.setPadAttribute = function (key, value, cb, href) {
|
||||
cb = cb || $.noop;
|
||||
ctx.sframeChan.query('Q_SET_PAD_ATTRIBUTE', {
|
||||
key: key,
|
||||
href: href,
|
||||
value: value
|
||||
}, cb);
|
||||
};
|
||||
|
||||
@@ -165,10 +165,6 @@ define({
|
||||
// Put one entry in the parent sessionStorage
|
||||
'Q_SESSIONSTORAGE_PUT': true,
|
||||
|
||||
// Set and get the tags using the tag prompt button
|
||||
'Q_TAGS_GET': true,
|
||||
'EV_TAGS_SET': true,
|
||||
|
||||
// Merge the anonymous drive (FS_hash) into the current logged in user's drive, to keep the pads
|
||||
// in the drive at registration.
|
||||
'Q_MERGE_ANON_DRIVE': true,
|
||||
@@ -237,4 +233,7 @@ define({
|
||||
|
||||
// Loading events to display in the loading screen
|
||||
'EV_LOADING_INFO': true,
|
||||
|
||||
// Get all existing tags
|
||||
'Q_GET_ALL_TAGS': true,
|
||||
});
|
||||
|
||||
@@ -627,6 +627,21 @@ define([
|
||||
if (typeof cb === "function") { cb(); }
|
||||
};
|
||||
|
||||
// Tags
|
||||
exp.getTagsList = function () {
|
||||
var tags = {};
|
||||
var data;
|
||||
var pushTag = function (tag) {
|
||||
tags[tag] = tags[tag] ? ++tags[tag] : 1;
|
||||
};
|
||||
for (var id in files[FILES_DATA]) {
|
||||
data = files[FILES_DATA][id];
|
||||
if (!data.tags || !Array.isArray(data.tags)) { continue; }
|
||||
data.tags.forEach(pushTag);
|
||||
}
|
||||
return tags;
|
||||
};
|
||||
|
||||
return exp;
|
||||
};
|
||||
return module;
|
||||
|
||||
Reference in New Issue
Block a user