mirror of https://github.com/xwiki-labs/cryptpad
ui for hashtag picker
This commit is contained in:
parent
1b97996ef8
commit
15e24ebe4f
|
@ -41,6 +41,7 @@
|
|||
"bootstrap": "#v4.0.0-alpha.6",
|
||||
"diff-dom": "2.1.1",
|
||||
"nthen": "^0.1.5",
|
||||
"open-sans-fontface": "^1.4.2"
|
||||
"open-sans-fontface": "^1.4.2",
|
||||
"bootstrap-tokenfield": "^0.12.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,6 +85,20 @@
|
|||
|
||||
.dialog {
|
||||
padding: 12px;
|
||||
/*
|
||||
div.tokenfield {
|
||||
.token {
|
||||
//border: 1px solid red;
|
||||
//color: red;
|
||||
}
|
||||
|
||||
color: @colortheme_light-base;
|
||||
background-color: @alertify-dialog-bg;
|
||||
|
||||
input[id$="tokenfield"][type="text"].token-input {
|
||||
background-color: @alertify-dialog-bg !important;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
.dialog, .alert {
|
||||
|
@ -308,6 +322,5 @@
|
|||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
.tokenfield_main () {
|
||||
.tokenfield {
|
||||
.unselectable () {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.unselectable();
|
||||
height: auto;
|
||||
min-height: 34px;
|
||||
padding-bottom: 0px;
|
||||
&.focus {
|
||||
border-color: #66afe9;
|
||||
outline: 0;
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, 0.6);
|
||||
}
|
||||
.token {
|
||||
box-sizing: border-box;
|
||||
border-radius: 3px;
|
||||
display: inline-block;
|
||||
border: 1px solid #d9d9d9;
|
||||
background-color: #ededed;
|
||||
white-space: nowrap;
|
||||
margin: -1px 5px 5px 0;
|
||||
vertical-align: center;
|
||||
cursor: default;
|
||||
|
||||
color: #222;
|
||||
|
||||
&:hover {
|
||||
border-color: #b9b9b9;
|
||||
}
|
||||
&.invalid {
|
||||
background: none;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 0;
|
||||
border-bottom: 1px dotted #d9534f;
|
||||
}
|
||||
&.invalid.active {
|
||||
background: #ededed;
|
||||
border: 1px solid #ededed;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.token-label {
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
padding-left: 4px;
|
||||
vertical-align: center;
|
||||
}
|
||||
.close {
|
||||
font-family: Arial;
|
||||
display: inline-block;
|
||||
line-height: 100%;
|
||||
font-size: 1.1em;
|
||||
margin-left: 5px;
|
||||
float: none;
|
||||
height: 100%;
|
||||
vertical-align: center;
|
||||
padding-right: 4px;
|
||||
}
|
||||
&.active {
|
||||
border-color: #52a8ec;
|
||||
border-color: rgba(82, 168, 236, 0.8);
|
||||
}
|
||||
&.duplicate {
|
||||
border-color: #ebccd1;
|
||||
}
|
||||
}
|
||||
.token-input {
|
||||
background: none;
|
||||
width: 0%; //60px;
|
||||
min-width: 60px;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
margin-bottom: 6px;
|
||||
box-shadow: none;
|
||||
max-width: 100%;
|
||||
&:focus {
|
||||
border-color: transparent;
|
||||
outline: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
&.disabled {
|
||||
cursor: not-allowed;
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,9 +7,10 @@ define([
|
|||
'/common/notify.js',
|
||||
'/common/visible.js',
|
||||
'/common/tippy.min.js',
|
||||
'/common/hyperscript.js',
|
||||
'/bower_components/bootstrap-tokenfield/dist/bootstrap-tokenfield.js',
|
||||
'css!/common/tippy.css',
|
||||
], function ($, Messages, Util, AppConfig, Alertify, Notify, Visible, Tippy) {
|
||||
|
||||
], function ($, Messages, Util, AppConfig, Alertify, Notify, Visible, Tippy, h) {
|
||||
var UI = {};
|
||||
|
||||
/*
|
||||
|
@ -20,11 +21,17 @@ define([
|
|||
// set notification timeout
|
||||
Alertify._$$alertify.delay = AppConfig.notificationTimeout || 5000;
|
||||
|
||||
var findCancelButton = UI.findCancelButton = function () {
|
||||
var findCancelButton = UI.findCancelButton = function (root) {
|
||||
if (root) {
|
||||
return $(root).find('button.cancel').last();
|
||||
}
|
||||
return $('button.cancel').last();
|
||||
};
|
||||
|
||||
var findOKButton = UI.findOKButton = function () {
|
||||
var findOKButton = UI.findOKButton = function (root) {
|
||||
if (root) {
|
||||
return $(root).find('button.ok').last();
|
||||
}
|
||||
return $('button.ok').last();
|
||||
};
|
||||
|
||||
|
@ -33,7 +40,6 @@ define([
|
|||
switch (e.which) {
|
||||
case 27: // cancel
|
||||
if (typeof(no) === 'function') { no(e); }
|
||||
no();
|
||||
break;
|
||||
case 13: // enter
|
||||
if (typeof(yes) === 'function') { yes(e); }
|
||||
|
@ -363,5 +369,126 @@ define([
|
|||
}
|
||||
};
|
||||
|
||||
UI.tokenField = function (target) {
|
||||
var t = {
|
||||
element: target || h('input'),
|
||||
};
|
||||
var $t = t.tokenfield = $(t.element).tokenfield();
|
||||
t.getTokens = function () {
|
||||
return $t.tokenfield('getTokens').map(function (token) {
|
||||
return token.value;
|
||||
});
|
||||
};
|
||||
|
||||
t.preventDuplicates = function (cb) {
|
||||
$t.on('tokenfield:createtoken', function (ev) {
|
||||
var val;
|
||||
if (t.getTokens().some(function (t) {
|
||||
if (t === ev.attrs.value) { return ((val = t)); }
|
||||
})) {
|
||||
ev.preventDefault();
|
||||
if (typeof(cb) === 'function') { cb(val); }
|
||||
}
|
||||
});
|
||||
return t;
|
||||
};
|
||||
|
||||
t.setTokens = function (tokens) {
|
||||
$t.tokenfield('setTokens',
|
||||
tokens.map(function (token) {
|
||||
return {
|
||||
value: token,
|
||||
label: token,
|
||||
};
|
||||
}));
|
||||
};
|
||||
|
||||
t.focus = function () {
|
||||
var $temp = $t.closest('.tokenfield').find('.token-input');
|
||||
$temp.css('width', '20%');
|
||||
$t.tokenfield('focusInput', $temp[0]);
|
||||
};
|
||||
|
||||
return t;
|
||||
};
|
||||
|
||||
var dialog = UI.dialog = {};
|
||||
dialog.okButton = function () {
|
||||
return h('button.ok', { tabindex: '2', }, Messages.okButton);
|
||||
};
|
||||
|
||||
dialog.cancelButton = function () {
|
||||
return h('button.cancel', { tabindex: '1'}, Messages.cancelButton);
|
||||
};
|
||||
|
||||
dialog.message = function (text) {
|
||||
return h('p.message', text);
|
||||
};
|
||||
|
||||
dialog.textInput = function (opt) {
|
||||
return h('input', opt || {
|
||||
placeholder: '',
|
||||
type: 'text',
|
||||
'class': 'cp-text-input',
|
||||
});
|
||||
};
|
||||
|
||||
dialog.nav = function (content) {
|
||||
return h('nav', content || [
|
||||
dialog.cancelButton(),
|
||||
dialog.okButton(),
|
||||
]);
|
||||
};
|
||||
|
||||
dialog.frame = function (content) {
|
||||
return h('div.alertify', [
|
||||
h('div.dialog', [
|
||||
h('div', content),
|
||||
])
|
||||
]);
|
||||
};
|
||||
|
||||
dialog.tagPrompt = function (tags, cb) {
|
||||
var input = dialog.textInput();
|
||||
|
||||
var tagger = dialog.frame([
|
||||
dialog.message('make some tags'), // TODO translate
|
||||
input,
|
||||
dialog.nav(),
|
||||
]);
|
||||
|
||||
var field = UI.tokenField(input).preventDuplicates(function (val) {
|
||||
UI.warn('Duplicate tag: ' + val); // TODO translate
|
||||
});
|
||||
|
||||
var close = Util.once(function () {
|
||||
var $t = $(tagger).fadeOut(150, function () { $t.remove(); });
|
||||
});
|
||||
|
||||
var listener = listenForKeys(function () {}, function () {
|
||||
close();
|
||||
stopListening(listener);
|
||||
});
|
||||
|
||||
var CB = Util.once(cb);
|
||||
findOKButton(tagger).click(function () {
|
||||
var tokens = field.getTokens();
|
||||
close();
|
||||
CB(tokens);
|
||||
});
|
||||
findCancelButton(tagger).click(function () {
|
||||
close();
|
||||
CB(null);
|
||||
});
|
||||
|
||||
// :(
|
||||
setTimeout(function () {
|
||||
field.setTokens(tags);
|
||||
field.focus();
|
||||
});
|
||||
|
||||
return tagger;
|
||||
};
|
||||
|
||||
return UI;
|
||||
});
|
||||
|
|
|
@ -81,6 +81,8 @@ define([
|
|||
common.addTooltips = UI.addTooltips;
|
||||
common.clearTooltips = UI.clearTooltips;
|
||||
common.importContent = UI.importContent;
|
||||
common.tokenField = UI.tokenField;
|
||||
common.dialog = UI.dialog;
|
||||
|
||||
// import common utilities for export
|
||||
common.find = Util.find;
|
||||
|
@ -1380,6 +1382,20 @@ define([
|
|||
})
|
||||
.click(prepareFeedback(type));
|
||||
break;
|
||||
case 'hashtag':
|
||||
button = $('<button>', {
|
||||
'class': 'fa fa-hashtag',
|
||||
})
|
||||
.click(prepareFeedback(type))
|
||||
.click(function () {
|
||||
// TODO fetch pad tags before presenting dialog to user
|
||||
var dialog = Cryptpad.dialog.tagPrompt([], function (tags) {
|
||||
if (!Array.isArray(tags)) { return; }
|
||||
console.error(tags);
|
||||
// TODO do something with the tags the user entered
|
||||
});
|
||||
document.body.appendChild(dialog);
|
||||
});
|
||||
default:
|
||||
button = $('<button>', {
|
||||
'class': "fa fa-question",
|
||||
|
|
Loading…
Reference in New Issue