Suggest tags based on existing ones. Display existing tags in the drive.

This commit is contained in:
yflory
2018-05-15 18:18:56 +02:00
parent e2052b4510
commit 65a2083afc
15 changed files with 268 additions and 154 deletions

View File

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

View File

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

File diff suppressed because one or more lines are too long

6
www/common/jquery-ui/jquery-ui.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

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

View File

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

View File

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