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

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

No files matched your search

+21 -6
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);
+20 -13
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);
});
});
};
+7
View File
@@ -0,0 +1,7 @@
/*! jQuery UI - v1.12.1 - 2018-05-15
* http://jqueryui.com
* Includes: core.css, autocomplete.css, menu.css, theme.css
* To view and modify this theme, visit http://jqueryui.com/themeroller/?scope=&folderName=base&cornerRadiusShadow=8px&offsetLeftShadow=0px&offsetTopShadow=0px&thicknessShadow=5px&opacityShadow=30&bgImgOpacityShadow=0&bgTextureShadow=flat&bgColorShadow=666666&opacityOverlay=30&bgImgOpacityOverlay=0&bgTextureOverlay=flat&bgColorOverlay=aaaaaa&iconColorError=cc0000&fcError=5f3f3f&borderColorError=f1a899&bgTextureError=flat&bgColorError=fddfdf&iconColorHighlight=777620&fcHighlight=777620&borderColorHighlight=dad55e&bgTextureHighlight=flat&bgColorHighlight=fffa90&iconColorActive=ffffff&fcActive=ffffff&borderColorActive=003eff&bgTextureActive=flat&bgColorActive=007fff&iconColorHover=555555&fcHover=2b2b2b&borderColorHover=cccccc&bgTextureHover=flat&bgColorHover=ededed&iconColorDefault=777777&fcDefault=454545&borderColorDefault=c5c5c5&bgTextureDefault=flat&bgColorDefault=f6f6f6&iconColorContent=444444&fcContent=333333&borderColorContent=dddddd&bgTextureContent=flat&bgColorContent=ffffff&iconColorHeader=444444&fcHeader=333333&borderColorHeader=dddddd&bgTextureHeader=flat&bgColorHeader=e9e9e9&cornerRadius=3px&fwDefault=normal&fsDefault=1em&ffDefault=Arial%2CHelvetica%2Csans-serif
* Copyright jQuery Foundation and other contributors; Licensed MIT */
.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important;pointer-events:none}.ui-icon{display:inline-block;vertical-align:middle;margin-top:-.25em;position:relative;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-icon-block{left:50%;margin-left:-8px;display:block}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:0}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{margin:0;cursor:pointer;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-item-wrapper{position:relative;padding:3px 1em 3px .4em}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item-wrapper{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-widget{font-family:Arial,Helvetica,sans-serif;font-size:1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Arial,Helvetica,sans-serif;font-size:1em}.ui-widget.ui-widget-content{border:1px solid #c5c5c5}.ui-widget-content{border:1px solid #ddd;background:#fff;color:#333}.ui-widget-content a{color:#333}.ui-widget-header{border:1px solid #ddd;background:#e9e9e9;color:#333;font-weight:bold}.ui-widget-header a{color:#333}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default,.ui-button,html .ui-button.ui-state-disabled:hover,html .ui-button.ui-state-disabled:active{border:1px solid #c5c5c5;background:#f6f6f6;font-weight:normal;color:#454545}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited,a.ui-button,a:link.ui-button,a:visited.ui-button,.ui-button{color:#454545;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus,.ui-button:hover,.ui-button:focus{border:1px solid #ccc;background:#ededed;font-weight:normal;color:#2b2b2b}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited,a.ui-button:hover,a.ui-button:focus{color:#2b2b2b;text-decoration:none}.ui-visual-focus{box-shadow:0 0 3px 1px rgb(94,158,214)}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active,a.ui-button:active,.ui-button:active,.ui-button.ui-state-active:hover{border:1px solid #003eff;background:#007fff;font-weight:normal;color:#fff}.ui-icon-background,.ui-state-active .ui-icon-background{border:#003eff;background-color:#fff}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#fff;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #dad55e;background:#fffa90;color:#777620}.ui-state-checked{border:1px solid #dad55e;background:#fffa90}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#777620}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #f1a899;background:#fddfdf;color:#5f3f3f}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#5f3f3f}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#5f3f3f}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_444444_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_444444_256x240.png")}.ui-staLine truncated
+6
View File
@@ -0,0 +1,6 @@
/*! jQuery UI - v1.12.1 - 2018-05-15
* http://jqueryui.com
* Includes: widget.js, position.js, keycode.js, unique-id.js, widgets/autocomplete.js, widgets/menu.js
* Copyright jQuery Foundation and other contributors; Licensed MIT */
(function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)})(function(t){t.ui=t.ui||{},t.ui.version="1.12.1";var e=0,i=Array.prototype.slice;t.cleanData=function(e){return function(i){var s,n,o;for(o=0;null!=(n=i[o]);o++)try{s=t._data(n,"events"),s&&s.remove&&t(n).triggerHandler("remove")}catch(a){}e(i)}}(t.cleanData),t.widget=function(e,i,s){var n,o,a,r={},l=e.split(".")[0];e=e.split(".")[1];var h=l+"-"+e;return s||(s=i,i=t.Widget),t.isArray(s)&&(s=t.extend.apply(null,[{}].concat(s))),t.expr[":"][h.toLowerCase()]=function(e){return!!t.data(e,h)},t[l]=t[l]||{},n=t[l][e],o=t[l][e]=function(t,e){return this._createWidget?(arguments.length&&this._createWidget(t,e),void 0):new o(t,e)},t.extend(o,n,{version:s.version,_proto:t.extend({},s),_childConstructors:[]}),a=new i,a.options=t.widget.extend({},a.options),t.each(s,function(e,s){return t.isFunction(s)?(r[e]=function(){function t(){return i.prototype[e].apply(this,arguments)}function n(t){return i.prototype[e].apply(this,t)}return function(){var e,i=this._super,o=this._superApply;return this._super=t,this._superApply=n,e=s.apply(this,arguments),this._super=i,this._superApply=o,e}}(),void 0):(r[e]=s,void 0)}),o.prototype=t.widget.extend(a,{widgetEventPrefix:n?a.widgetEventPrefix||e:e},r,{constructor:o,namespace:l,widgetName:e,widgetFullName:h}),n?(t.each(n._childConstructors,function(e,i){var s=i.prototype;t.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete n._childConstructors):i._childConstructors.push(o),t.widget.bridge(e,o),o},t.widget.extend=function(e){for(var s,n,o=i.call(arguments,1),a=0,r=o.length;r>a;a++)for(s in o[a])n=o[a][s],o[a].hasOwnProperty(s)&&void 0!==n&&(e[s]=t.isPlainObject(n)?t.isPlainObject(e[s])?t.widget.extend({},e[s],n):t.widget.extend({},n):n);return e},t.widget.bridge=function(e,s){var n=s.prototype.widgetFullName||e;t.fn[e]=function(o){var a="string"==typeof o,r=i.call(arguments,1),l=this;return a?this.length||"instance"!==o?this.each(function(){var i,s=t.data(this,n);return"instance"===o?(l=s,!1):s?t.isFunction(s[o])&&"_"!==o.charAt(0)?(i=s[o].apply(s,r),i!==s&&void 0!==i?(l=i&&i.jquery?l.pushStack(i.get()):i,!1):void 0):t.error("no such method '"+o+"' for "+e+" widget instance"):t.error("cannot call methods on "+e+" prior to initialization; "+"attempted to call method '"+o+"'")}):l=void 0:(r.length&&(o=t.widget.extend.apply(null,[o].concat(r))),this.each(function(){var e=t.data(this,n);e?(e.option(o||{}),e._init&&e._init()):t.data(this,n,new s(o,this))})),l}},t.Widget=function(){},t.Widget._childConstructors=[],t.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{classes:{},disabled:!1,create:null},_createWidget:function(i,s){s=t(s||this.defaultElement||this)[0],this.element=t(s),this.uuid=e++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=t(),this.hoverable=t(),this.focusable=t(),this.classesElementLookup={},s!==this&&(t.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===s&&this.destroy()}}),this.document=t(s.style?s.ownerDocument:s.document||s),this.window=t(this.document[0].defaultView||this.document[0].parentWindow)),this.options=t.widget.extend({},this.options,this._getCreateOptions(),i),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:t.noop,_create:t.noop,_init:t.noop,destroy:function(){var e=this;this._destroy(),t.each(this.classesElementLookup,function(t,i){e._removeClass(i,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:t.noop,widget:function(){return this.element},option:function(e,i){var s,n,o,a=e;if(0===arguments.length)return t.widget.extend({},this.options);if("string"==typeof e)if(a={},s=e.split("."),e=s.shift(),s.length){for(n=a[e]=t.widget.extend({},this.options[e]),o=0;s.length-1>o;o++)n[s[o]]=n[s[o]]||{},n=n[s[o]];if(e=s.pop(),1===arguments.length)return void 0===n[e]?null:n[e];n[e]=i}else{if(1===arguments.length)return void 0===this.options[e]?null:this.options[e];a[e]=i}return this._setOptions(a),this},_setOptions:function(t){var e;for(e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return"classes"===t&&this._setOptionClasses(e),this.options[t]=e,"disabled"===t&&this._setOptionDisabled(e),this},_setOptionClasses:function(e){var i,s,n;for(i in e)n=this.classesElementLookup[i],e[i]!==this.options.classes[i]&&n&&n.length&&(s=t(n.get()),this._removeClass(n,i),s.addClass(this._classes({element:s,keys:i,classes:e,add:!0})))},_setOptionDisabled:function(t){this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,!!t),t&&(this._removeClass(this.hoverable,null,"ui-state-hover"),this._removeClass(this.focusable,null,"ui-state-focus"))},enable:function(){return Line truncated
+1 -12
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
+11 -13
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);
}
+6 -3
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);
};
+3 -4
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,
});
+15
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;