Add converse-autocomplete and use that in the chat textarea

This commit is contained in:
JC Brand 2018-08-10 14:09:21 +02:00
parent f0ad326e2e
commit b6f4f05b9e
13 changed files with 1206 additions and 91 deletions

View File

@ -19,7 +19,7 @@
"rules": {
"lodash/prefer-lodash-method": [2, {
"ignoreMethods": [
"find", "endsWith", "startsWith", "filter", "reduce",
"find", "endsWith", "startsWith", "filter", "reduce", "isArray", "create",
"map", "replace", "toLower", "split", "trim", "forEach", "toUpperCase", "includes"
]
}],
@ -215,10 +215,7 @@
"one-var": "off",
"one-var-declaration-per-line": "off",
"operator-assignment": "off",
"operator-linebreak": [
"error",
"after"
],
"operator-linebreak": "off",
"padded-blocks": "off",
"prefer-arrow-callback": "off",
"prefer-const": "error",

View File

@ -7748,6 +7748,8 @@ body.reset {
line-height: 27px; }
#conversejs.converse-fullscreen .chatbox .sendXMPPMessage ul {
width: 100%; }
#conversejs.converse-fullscreen .chatbox .sendXMPPMessage .suggestion-box__results:after {
display: none; }
#conversejs.converse-fullscreen .chatbox .sendXMPPMessage .toggle-smiley ul.emoji-toolbar .emoji-category-picker {
margin-right: 5em; }
#conversejs.converse-fullscreen .chatbox .sendXMPPMessage .toggle-smiley ul.emoji-toolbar .emoji-category {
@ -8681,8 +8683,7 @@ body.reset {
color: #E77051; }
#conversejs.converse-embedded .chatroom .sendXMPPMessage .chat-textarea,
#conversejs .chatroom .sendXMPPMessage .chat-textarea {
border-bottom-right-radius: 0;
resize: none; }
border-bottom-right-radius: 0; }
#conversejs.converse-embedded .chatroom .sendXMPPMessage .chat-textarea.correcting,
#conversejs .chatroom .sendXMPPMessage .chat-textarea.correcting {
background-color: #fadfd7; }
@ -9040,20 +9041,26 @@ body.reset {
#conversejs .visually-hidden {
position: absolute;
clip: rect(0, 0, 0, 0); }
#conversejs .form-group .suggestion-box,
#conversejs .form-group .awesomplete {
width: 100%; }
#conversejs div.awesomplete {
display: inline-block;
#conversejs .suggestion-box,
#conversejs .awesomplete {
position: relative; }
#conversejs div.awesomplete mark {
#conversejs .suggestion-box mark,
#conversejs .awesomplete mark {
background: #FFB9A7; }
#conversejs div.awesomplete > input {
#conversejs .suggestion-box > input,
#conversejs .awesomplete > input {
display: block; }
#conversejs div.awesomplete > ul {
#conversejs .suggestion-box .suggestion-box__results,
#conversejs .suggestion-box > ul,
#conversejs .awesomplete .suggestion-box__results,
#conversejs .awesomplete > ul {
position: absolute;
left: 0;
right: 0;
z-index: 1;
z-index: 2;
min-width: 100%;
box-sizing: border-box;
list-style: none;
@ -9061,51 +9068,91 @@ body.reset {
border-radius: .3em;
margin: .2em 0 0;
background: rgba(255, 255, 255, 0.9);
background: linear-gradient(to bottom right, white, rgba(255, 255, 255, 0.8));
background: linear-gradient(to bottom right, white, rgba(255, 255, 255, 0.9));
border: 1px solid rgba(0, 0, 0, 0.3);
box-shadow: 0.05em 0.2em 0.6em rgba(0, 0, 0, 0.2);
box-shadow: 0.05em 0.2em 0.6em rgba(0, 0, 0, 0.1);
text-shadow: none; }
#conversejs div.awesomplete > ul:before {
#conversejs .suggestion-box .suggestion-box__results:before,
#conversejs .suggestion-box > ul:before,
#conversejs .awesomplete .suggestion-box__results:before,
#conversejs .awesomplete > ul:before {
content: "";
position: absolute;
top: -.43em;
left: 1em;
width: 0;
height: 0;
padding: .4em;
background: white;
border: inherit;
border-right: 0;
border-bottom: 0;
-webkit-transform: rotate(45deg);
transform: rotate(45deg); }
#conversejs div.awesomplete > ul > li {
transform: rotate(45deg);
z-index: 1; }
#conversejs .suggestion-box .suggestion-box__results > li,
#conversejs .suggestion-box > ul > li,
#conversejs .awesomplete .suggestion-box__results > li,
#conversejs .awesomplete > ul > li {
text-overflow: ellipsis;
overflow-x: hidden;
position: relative;
cursor: pointer;
padding: 1em; }
#conversejs .suggestion-box .suggestion-box__results--above,
#conversejs .awesomplete .suggestion-box__results--above {
bottom: 4.5em; }
#conversejs .suggestion-box .suggestion-box__results--above:before,
#conversejs .awesomplete .suggestion-box__results--above:before {
display: none; }
#conversejs .suggestion-box .suggestion-box__results--above:after,
#conversejs .awesomplete .suggestion-box__results--above:after {
z-index: 1;
content: "";
position: absolute;
bottom: -.43em;
left: 1em;
width: 0;
height: 0;
padding: .4em;
background: white;
border: inherit;
border-left: 0;
border-top: 0;
-webkit-transform: rotate(45deg);
transform: rotate(45deg); }
#conversejs .suggestion-box > ul[hidden],
#conversejs .suggestion-box > ul:empty,
#conversejs div.awesomplete > ul[hidden],
#conversejs div.awesomplete > ul:empty {
display: none; }
@supports (transform: scale(0)) {
#conversejs .suggestion-box > ul,
#conversejs div.awesomplete > ul {
transition: 0.3s cubic-bezier(0.4, 0.2, 0.5, 1.4);
transform-origin: 1.43em -.43em; }
#conversejs .suggestion-box > ul[hidden],
#conversejs .suggestion-box > ul:empty,
#conversejs div.awesomplete > ul[hidden],
#conversejs div.awesomplete > ul:empty {
opacity: 0;
transform: scale(0);
display: block;
transition-timing-function: ease; } }
#conversejs .suggestion-box > ul > li:hover,
#conversejs div.awesomplete > ul > li:hover {
z-index: 2;
background: #E77051;
color: white; }
#conversejs .suggestion-box > ul > li[aria-selected="true"],
#conversejs div.awesomplete > ul > li[aria-selected="true"] {
background: #3d6d8f;
color: white; }
#conversejs .suggestion-box li:hover mark,
#conversejs div.awesomplete li:hover mark {
background: #A53214;
color: white; }
#conversejs .suggestion-box li[aria-selected="true"] mark,
#conversejs div.awesomplete li[aria-selected="true"] mark {
background: #3d6b00;
color: inherit; }

589
dist/converse.js vendored
View File

@ -52182,7 +52182,6 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
return;
}
if (_.isBoolean(plugin.enabled) && plugin.enabled || _.isFunction(plugin.enabled) && plugin.enabled(this.plugged) || _.isNil(plugin.enabled)) {
_.extend(plugin, this.properties);
if (plugin.dependencies) {
this.loadPluginDependencies(plugin);
@ -67560,6 +67559,496 @@ var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;
/***/ }),
/***/ "./src/converse-autocomplete.js":
/*!**************************************!*\
!*** ./src/converse-autocomplete.js ***!
\**************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;
// Converse.js
// http://conversejs.org
//
// Copyright (c) 2013-2018, the Converse.js developers
// Licensed under the Mozilla Public License (MPLv2)
// This plugin started as a fork of Lea Verou's Awesomplete
// https://leaverou.github.io/awesomplete/
(function (root, factory) {
!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(/*! converse-core */ "./src/converse-core.js")], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory),
__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
})(void 0, function (converse) {
const _converse$env = converse.env,
_ = _converse$env._,
Backbone = _converse$env.Backbone,
u = converse.env.utils;
converse.plugins.add("converse-autocomplete", {
initialize() {
const _converse = this._converse;
_converse.FILTER_CONTAINS = function (text, input) {
return RegExp($.regExpEscape(input.trim()), "i").test(text);
};
_converse.FILTER_STARTSWITH = function (text, input) {
return RegExp("^" + $.regExpEscape(input.trim()), "i").test(text);
};
const _ac = function _ac(el, o) {
const me = this;
this.is_opened = false;
if (u.hasClass('.suggestion-box', el)) {
this.container = el;
} else {
this.container = el.querySelector('.suggestion-box');
}
this.input = $(this.container.querySelector('.suggestion-box__input'));
this.input.setAttribute("autocomplete", "off");
this.input.setAttribute("aria-autocomplete", "list");
this.ul = $(this.container.querySelector('.suggestion-box__results'));
this.status = $(this.container.querySelector('.suggestion-box__additions'));
o = o || {};
configure(this, {
'match_current_word': false,
// Match only the current word, otherwise all input is matched
'match_on_tab': false,
// Whether matching should only start when tab's pressed
'min_chars': 2,
'max_items': 10,
'auto_evaluate': true,
'auto_first': false,
'data': _ac.DATA,
'filter': _ac.FILTER_CONTAINS,
'sort': o.sort === false ? false : _ac.SORT_BYLENGTH,
'item': _ac.ITEM,
'replace': _ac.REPLACE
}, o);
this.index = -1;
const input = {
"blur": this.close.bind(this, {
reason: "blur"
}),
"keydown": function keydown(evt) {
const c = evt.keyCode; // If the dropdown `ul` is in view, then act on keydown for the following keys:
// Enter / Esc / Up / Down
if (me.opened) {
if (c === _converse.keycodes.ENTER && me.selected) {
evt.preventDefault();
me.select();
} else if (c === _converse.keycodes.ESCAPE) {
me.close({
reason: "esc"
});
} else if (c === _converse.keycodes.UP_ARROW || c === _converse.keycodes.DOWN_ARROW) {
evt.preventDefault();
me[c === _converse.keycodes.UP_ARROW ? "previous" : "next"]();
}
}
}
};
if (this.auto_evaluate) {
input["input"] = this.evaluate.bind(this);
} // Bind events
this._events = {
'input': input,
'form': {
"submit": this.close.bind(this, {
reason: "submit"
})
},
'ul': {
"mousedown": function mousedown(evt) {
let li = evt.target;
if (li !== this) {
while (li && !/li/i.test(li.nodeName)) {
li = li.parentNode;
}
if (li && evt.button === 0) {
// Only select on left click
evt.preventDefault();
me.select(li, evt.target);
}
}
}
}
};
$.bind(this.input, this._events.input);
$.bind(this.input.form, this._events.form);
$.bind(this.ul, this._events.ul);
if (this.input.hasAttribute("list")) {
this.list = "#" + this.input.getAttribute("list");
this.input.removeAttribute("list");
} else {
this.list = this.input.getAttribute("data-list") || o.list || [];
}
_ac.all.push(this);
};
_ac.prototype = {
set list(list) {
if (Array.isArray(list)) {
this._list = list;
} else if (typeof list === "string" && _.includes(list, ",")) {
this._list = list.split(/\s*,\s*/);
} else {
// Element or CSS selector
list = $(list);
if (list && list.children) {
const items = [];
slice.apply(list.children).forEach(function (el) {
if (!el.disabled) {
const text = el.textContent.trim(),
value = el.value || text,
label = el.label || text;
if (value !== "") {
items.push({
label: label,
value: value
});
}
}
});
this._list = items;
}
}
if (document.activeElement === this.input) {
this.evaluate();
}
},
get selected() {
return this.index > -1;
},
get opened() {
return this.is_opened;
},
close(o) {
if (!this.opened) {
return;
}
this.ul.setAttribute("hidden", "");
this.is_opened = false;
this.index = -1;
$.fire(this.input, "suggestion-box-close", o || {});
},
open() {
this.ul.removeAttribute("hidden");
this.is_opened = true;
if (this.auto_first && this.index === -1) {
this.goto(0);
}
$.fire(this.input, "suggestion-box-open");
},
destroy() {
//remove events from the input and its form
$.unbind(this.input, this._events.input);
$.unbind(this.input.form, this._events.form); //move the input out of the suggestion-box container and remove the container and its children
const parentNode = this.container.parentNode;
parentNode.insertBefore(this.input, this.container);
parentNode.removeChild(this.container); //remove autocomplete and aria-autocomplete attributes
this.input.removeAttribute("autocomplete");
this.input.removeAttribute("aria-autocomplete"); //remove this awesomeplete instance from the global array of instances
var indexOfAutoComplete = _ac.all.indexOf(this);
if (indexOfAutoComplete !== -1) {
_ac.all.splice(indexOfAutoComplete, 1);
}
},
next() {
var count = this.ul.children.length;
this.goto(this.index < count - 1 ? this.index + 1 : count ? 0 : -1);
},
previous() {
var count = this.ul.children.length;
var pos = this.index - 1;
this.goto(this.selected && pos !== -1 ? pos : count - 1);
},
// Should not be used, highlights specific item without any checks!
goto(i) {
var lis = this.ul.children;
if (this.selected) {
lis[this.index].setAttribute("aria-selected", "false");
}
this.index = i;
if (i > -1 && lis.length > 0) {
lis[i].setAttribute("aria-selected", "true");
this.status.textContent = lis[i].textContent; // scroll to highlighted element in case parent's height is fixed
this.ul.scrollTop = lis[i].offsetTop - this.ul.clientHeight + lis[i].clientHeight;
$.fire(this.input, "suggestion-box-highlight", {
text: this.suggestions[this.index]
});
}
},
select(selected, origin) {
if (selected) {
this.index = u.siblingIndex(selected);
} else {
selected = this.ul.children[this.index];
}
if (selected) {
const suggestion = this.suggestions[this.index],
allowed = $.fire(this.input, "suggestion-box-select", {
'text': suggestion,
'origin': origin || selected
});
if (allowed) {
this.replace(suggestion);
this.close({
'reason': 'select'
});
this.auto_completing = false;
this.trigger("suggestion-box-selectcomplete", {
'text': suggestion
});
}
}
},
keyPressed(ev) {
if (_.includes([_converse.keycodes.SHIFT, _converse.keycodes.META, _converse.keycodes.META_RIGHT, _converse.keycodes.ESCAPE, _converse.keycodes.ALT], ev.keyCode)) {
return;
}
if (this.match_on_tab && ev.keyCode === _converse.keycodes.TAB) {
ev.preventDefault();
this.auto_completing = true;
}
if (this.auto_completing) {
this.evaluate();
}
},
evaluate(ev) {
let value = this.input.value;
if (this.match_current_word) {
value = u.getCurrentWord(this.input);
}
if (value.length >= this.min_chars && this._list.length > 0) {
this.index = -1; // Populate list with options that match
this.ul.innerHTML = "";
this.suggestions = this._list.map(item => new Suggestion(this.data(item, value))).filter(item => this.filter(item, value));
if (this.sort !== false) {
this.suggestions = this.suggestions.sort(this.sort);
}
this.suggestions = this.suggestions.slice(0, this.max_items);
this.suggestions.forEach(text => this.ul.appendChild(this.item(text, value)));
if (this.ul.children.length === 0) {
this.close({
'reason': 'nomatches'
});
} else {
this.open();
}
} else {
this.close({
'reason': 'nomatches'
});
this.auto_completing = false;
}
}
}; // Make it an event emitter
_.extend(_ac.prototype, Backbone.Events); // Static methods/properties
_ac.all = [];
_ac.SORT_BYLENGTH = function (a, b) {
if (a.length !== b.length) {
return a.length - b.length;
}
return a < b ? -1 : 1;
};
_ac.ITEM = function (text, input) {
input = input.trim();
var element = document.createElement("li");
element.setAttribute("aria-selected", "false");
var regex = new RegExp("(" + input + ")", "ig");
var parts = input ? text.split(regex) : [text];
parts.forEach(function (txt) {
if (input && txt.match(regex)) {
var match = document.createElement("mark");
match.textContent = txt;
element.appendChild(match);
} else {
element.appendChild(document.createTextNode(txt));
}
});
return element;
};
_ac.REPLACE = function (text) {
this.input.value = text.value;
};
_ac.DATA = function (item
/*, input*/
) {
return item;
}; // Private functions
function Suggestion(data) {
const o = Array.isArray(data) ? {
label: data[0],
value: data[1]
} : typeof data === "object" && "label" in data && "value" in data ? data : {
label: data,
value: data
};
this.label = o.label || o.value;
this.value = o.value;
}
Object.defineProperty(Suggestion.prototype = Object.create(String.prototype), "length", {
get: function get() {
return this.label.length;
}
});
Suggestion.prototype.toString = Suggestion.prototype.valueOf = function () {
return "" + this.label;
};
function configure(instance, properties, o) {
for (var i in properties) {
if (!Object.prototype.hasOwnProperty.call(properties, i)) {
continue;
}
const initial = properties[i],
attr_value = instance.input.getAttribute("data-" + i.toLowerCase());
if (typeof initial === "number") {
instance[i] = parseInt(attr_value, 10);
} else if (initial === false) {
// Boolean options must be false by default anyway
instance[i] = attr_value !== null;
} else if (initial instanceof Function) {
instance[i] = null;
} else {
instance[i] = attr_value;
}
if (!instance[i] && instance[i] !== 0) {
instance[i] = i in o ? o[i] : initial;
}
}
} // Helpers
var slice = Array.prototype.slice;
function $(expr, con) {
return typeof expr === "string" ? (con || document).querySelector(expr) : expr || null;
}
function $$(expr, con) {
return slice.call((con || document).querySelectorAll(expr));
}
$.bind = function (element, o) {
if (element) {
for (var event in o) {
if (!Object.prototype.hasOwnProperty.call(o, event)) {
continue;
}
const callback = o[event];
event.split(/\s+/).forEach(event => element.addEventListener(event, callback));
}
}
};
$.unbind = function (element, o) {
if (element) {
for (var event in o) {
if (!Object.prototype.hasOwnProperty.call(o, event)) {
continue;
}
const callback = o[event];
event.split(/\s+/).forEach(event => element.removeEventListener(event, callback));
}
}
};
$.fire = function (target, type, properties) {
var evt = document.createEvent("HTMLEvents");
evt.initEvent(type, true, true);
for (var j in properties) {
if (!Object.prototype.hasOwnProperty.call(properties, j)) {
continue;
}
evt[j] = properties[j];
}
return target.dispatchEvent(evt);
};
$.regExpEscape = function (s) {
return s.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&");
};
_ac.$ = $;
_ac.$$ = $$;
_converse.AutoComplete = _ac;
}
});
});
/***/ }),
/***/ "./src/converse-bookmarks.js":
/*!***********************************!*\
!*** ./src/converse-bookmarks.js ***!
@ -69426,18 +69915,6 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
sizzle = _converse$env.sizzle,
moment = _converse$env.moment;
const u = converse.env.utils;
const KEY = {
ENTER: 13,
SHIFT: 17,
CTRL: 17,
ALT: 18,
ESCAPE: 27,
UP_ARROW: 38,
DOWN_ARROW: 40,
FORWARD_SLASH: 47,
META: 91,
META_RIGHT: 93
};
converse.plugins.add('converse-chatview', {
/* Plugin dependencies are other plugins which might be
* overridden or relied upon, and therefore need to be loaded before
@ -70308,21 +70785,21 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
}
if (!ev.shiftKey && !ev.altKey) {
if (ev.keyCode === KEY.FORWARD_SLASH) {
if (ev.keyCode === _converse.keycodes.FORWARD_SLASH) {
// Forward slash is used to run commands. Nothing to do here.
return;
} else if (ev.keyCode === KEY.ESCAPE) {
} else if (ev.keyCode === _converse.keycodes.ESCAPE) {
return this.onEscapePressed(ev);
} else if (ev.keyCode === KEY.ENTER) {
} else if (ev.keyCode === _converse.keycodes.ENTER) {
return this.onFormSubmitted(ev);
} else if (ev.keyCode === KEY.UP_ARROW && !ev.target.selectionEnd) {
} else if (ev.keyCode === _converse.keycodes.UP_ARROW && !ev.target.selectionEnd) {
return this.editEarlierMessage();
} else if (ev.keyCode === KEY.DOWN_ARROW && ev.target.selectionEnd === ev.target.value.length) {
} else if (ev.keyCode === _converse.keycodes.DOWN_ARROW && ev.target.selectionEnd === ev.target.value.length) {
return this.editLaterMessage();
}
}
if (_.includes([KEY.SHIFT, KEY.META, KEY.META_RIGHT, KEY.ESCAPE, KEY.ALT], ev.keyCode)) {
if (_.includes([_converse.keycodes.SHIFT, _converse.keycodes.META, _converse.keycodes.META_RIGHT, _converse.keycodes.ESCAPE, _converse.keycodes.ALT], ev.keyCode)) {
return;
}
@ -71490,13 +71967,26 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
_.extend(_converse, Backbone.Events); // Core plugins are whitelisted automatically
_converse.core_plugins = ['converse-bookmarks', 'converse-caps', 'converse-chatboxes', 'converse-chatview', 'converse-controlbox', 'converse-core', 'converse-disco', 'converse-dragresize', 'converse-embedded', 'converse-fullscreen', 'converse-headline', 'converse-mam', 'converse-message-view', 'converse-minimize', 'converse-modal', 'converse-muc', 'converse-muc-views', 'converse-notification', 'converse-oauth', 'converse-ping', 'converse-profile', 'converse-push', 'converse-register', 'converse-roomslist', 'converse-roster', 'converse-rosterview', 'converse-singleton', 'converse-spoilers', 'converse-vcard']; // Setting wait to 59 instead of 60 to avoid timing conflicts with the
_converse.core_plugins = ['converse-autocomplete', 'converse-bookmarks', 'converse-caps', 'converse-chatboxes', 'converse-chatview', 'converse-controlbox', 'converse-core', 'converse-disco', 'converse-dragresize', 'converse-embedded', 'converse-fullscreen', 'converse-headline', 'converse-mam', 'converse-message-view', 'converse-minimize', 'converse-modal', 'converse-muc', 'converse-muc-views', 'converse-notification', 'converse-oauth', 'converse-ping', 'converse-profile', 'converse-push', 'converse-register', 'converse-roomslist', 'converse-roster', 'converse-rosterview', 'converse-singleton', 'converse-spoilers', 'converse-vcard']; // Setting wait to 59 instead of 60 to avoid timing conflicts with the
// webserver, which is often also set to 60 and might therefore sometimes
// return a 504 error page instead of passing through to the BOSH proxy.
const BOSH_WAIT = 59; // Make converse pluggable
pluggable.enable(_converse, '_converse', 'pluggable'); // Module-level constants
pluggable.enable(_converse, '_converse', 'pluggable');
_converse.keycodes = {
TAB: 9,
ENTER: 13,
SHIFT: 16,
CTRL: 17,
ALT: 18,
ESCAPE: 27,
UP_ARROW: 38,
DOWN_ARROW: 40,
FORWARD_SLASH: 47,
META: 91,
META_RIGHT: 93
}; // Module-level constants
_converse.STATUS_WEIGHTS = {
'offline': 6,
@ -75750,7 +76240,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
// Converse.js
// http://conversejs.org
//
// Copyright (c) 2012-2018, the Converse.js developers
// Copyright (c) 2013-2018, the Converse.js developers
// Licensed under the Mozilla Public License (MPLv2)
(function (root, factory) {
!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(/*! converse-core */ "./src/converse-core.js"), __webpack_require__(/*! utils/muc */ "./src/utils/muc.js"), __webpack_require__(/*! xss */ "./node_modules/xss/dist/xss.js"), __webpack_require__(/*! templates/add_chatroom_modal.html */ "./src/templates/add_chatroom_modal.html"), __webpack_require__(/*! templates/chatarea.html */ "./src/templates/chatarea.html"), __webpack_require__(/*! templates/chatroom.html */ "./src/templates/chatroom.html"), __webpack_require__(/*! templates/chatroom_details_modal.html */ "./src/templates/chatroom_details_modal.html"), __webpack_require__(/*! templates/chatroom_disconnect.html */ "./src/templates/chatroom_disconnect.html"), __webpack_require__(/*! templates/chatroom_features.html */ "./src/templates/chatroom_features.html"), __webpack_require__(/*! templates/chatroom_form.html */ "./src/templates/chatroom_form.html"), __webpack_require__(/*! templates/chatroom_head.html */ "./src/templates/chatroom_head.html"), __webpack_require__(/*! templates/chatroom_invite.html */ "./src/templates/chatroom_invite.html"), __webpack_require__(/*! templates/chatroom_nickname_form.html */ "./src/templates/chatroom_nickname_form.html"), __webpack_require__(/*! templates/chatroom_password_form.html */ "./src/templates/chatroom_password_form.html"), __webpack_require__(/*! templates/chatroom_sidebar.html */ "./src/templates/chatroom_sidebar.html"), __webpack_require__(/*! templates/chatroom_toolbar.html */ "./src/templates/chatroom_toolbar.html"), __webpack_require__(/*! templates/info.html */ "./src/templates/info.html"), __webpack_require__(/*! templates/list_chatrooms_modal.html */ "./src/templates/list_chatrooms_modal.html"), __webpack_require__(/*! templates/occupant.html */ "./src/templates/occupant.html"), __webpack_require__(/*! templates/room_description.html */ "./src/templates/room_description.html"), __webpack_require__(/*! templates/room_item.html */ "./src/templates/room_item.html"), __webpack_require__(/*! templates/room_panel.html */ "./src/templates/room_panel.html"), __webpack_require__(/*! templates/rooms_results.html */ "./src/templates/rooms_results.html"), __webpack_require__(/*! templates/spinner.html */ "./src/templates/spinner.html"), __webpack_require__(/*! awesomplete */ "./node_modules/awesomplete-avoid-xss/awesomplete.js"), __webpack_require__(/*! converse-modal */ "./src/converse-modal.js")], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory),
@ -75801,7 +76291,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
* If the setting "strict_plugin_dependencies" is set to true,
* an error will be raised if the plugin is not found.
*/
dependencies: ["converse-modal", "converse-controlbox", "converse-chatview"],
dependencies: ["converse-autocomplete", "converse-modal", "converse-controlbox", "converse-chatview"],
overrides: {
ControlBoxView: {
renderRoomsPanel() {
@ -76292,6 +76782,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
this.renderHeading();
this.renderChatArea();
this.renderMessageForm();
this.initAutoComplete();
if (this.model.get('connection_status') !== converse.ROOMSTATUS.ENTERED) {
this.showSpinner();
@ -76321,6 +76812,26 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
return this;
},
initAutoComplete() {
this.auto_complete = new _converse.AutoComplete(this.el, {
'auto_evaluate': false,
'min_chars': 1,
'match_current_word': true,
'match_on_tab': true,
'list': this.model.occupants.map(o => ({
'label': o.getDisplayName(),
'value': o.get('jid')
})),
'filter': _converse.FILTER_STARTSWITH
});
this.auto_complete.on('suggestion-box-selectcomplete', () => this.auto_completing = false);
},
keyPressed(ev) {
this.auto_complete.keyPressed(ev);
return _converse.ChatBoxView.prototype.keyPressed.apply(this, arguments);
},
showRoomDetailsModal(ev) {
ev.preventDefault();
@ -76587,9 +77098,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
},
parseMessageForCommands(text) {
const _super_ = _converse.ChatBoxView.prototype;
if (_super_.parseMessageForCommands.apply(this, arguments)) {
if (_converse.ChatBoxView.prototype.parseMessageForCommands.apply(this, arguments)) {
return true;
}
@ -83819,7 +84328,7 @@ if (true) {
* --------------------
* Any of the following components may be removed if they're not needed.
*/
__webpack_require__(/*! converse-bookmarks */ "./src/converse-bookmarks.js"), // XEP-0048 Bookmarks
__webpack_require__(/*! converse-autocomplete */ "./src/converse-autocomplete.js"), __webpack_require__(/*! converse-bookmarks */ "./src/converse-bookmarks.js"), // XEP-0048 Bookmarks
__webpack_require__(/*! converse-caps */ "./src/converse-caps.js"), // XEP-0115 Entity Capabilities
__webpack_require__(/*! converse-chatview */ "./src/converse-chatview.js"), // Renders standalone chat boxes for single user chat
__webpack_require__(/*! converse-controlbox */ "./src/converse-controlbox.js"), // The control box
@ -84504,25 +85013,25 @@ __p += '\n <input type="text" placeholder="' +
if (!o.composing_spoiler) { ;
__p += ' hidden ';
} ;
__p += ' spoiler-hint"/>\n <textarea\n type="text"\n class="chat-textarea\n ';
__p += ' spoiler-hint"/>\n\n <div class="suggestion-box">\n <ul class="suggestion-box__results suggestion-box__results--above" hidden></ul>\n <textarea\n type="text"\n class="chat-textarea suggestion-box__input\n ';
if (o.show_send_button) { ;
__p += ' chat-textarea-send-button ';
} ;
__p += '\n ';
__p += '\n ';
if (o.composing_spoiler) { ;
__p += ' spoiler ';
} ;
__p += '"\n placeholder="' +
__p += '"\n placeholder="' +
__e(o.label_personal_message) +
'">' +
((__t = ( o.message_value )) == null ? '' : __t) +
'</textarea>\n ';
'</textarea>\n <span class="suggestion-box__additions visually-hidden" role="status" aria-live="assertive" aria-relevant="additions"></span>\n\n\n\n ';
if (o.show_send_button) { ;
__p += '\n <button type="submit" class="pure-button send-button">' +
__p += '\n <button type="submit" class="pure-button send-button">' +
__e( o.label_send ) +
'</button>\n ';
'</button>\n ';
} ;
__p += '\n</form>\n</div>\n';
__p += '\n </div>\n</form>\n</div>\n';
return __p
};
@ -88055,6 +88564,18 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
}
};
u.siblingIndex = function (el) {
/* eslint-disable no-cond-assign */
for (var i = 0; el = el.previousElementSibling; i++);
return i;
};
u.getCurrentWord = function (input) {
const cursor = input.selectionEnd || undefined;
return _.last(input.value.slice(0, cursor).split(' '));
};
u.isVisible = function (el) {
if (u.hasClass('hidden', el)) {
return false;

View File

@ -7,13 +7,14 @@
}
.form-group {
.suggestion-box,
.awesomplete {
width: 100%;
}
}
div.awesomplete {
display: inline-block;
.suggestion-box,
.awesomplete {
position: relative;
mark {
background: $lightest-red;
@ -23,6 +24,7 @@
display: block;
}
.suggestion-box__results,
> ul {
&:before {
content: "";
@ -30,18 +32,19 @@
top: -.43em;
left: 1em;
width: 0; height: 0;
padding: .4em;
background: white;
border: inherit;
border-right: 0;
border-bottom: 0;
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
z-index: 1;
}
position: absolute;
left: 0;
right: 0;
z-index: 1;
z-index: 2;
min-width: 100%;
box-sizing: border-box;
list-style: none;
@ -49,9 +52,9 @@
border-radius: .3em;
margin: .2em 0 0;
background: hsla(0,0%,100%,.9);
background: linear-gradient(to bottom right, white, hsla(0,0%,100%,.8));
background: linear-gradient(to bottom right, white, hsla(0,0%,100%,.9));
border: 1px solid rgba(0,0,0,.3);
box-shadow: .05em .2em .6em rgba(0,0,0,.2);
box-shadow: .05em .2em .6em rgba(0,0,0,.1);
text-shadow: none;
> li {
@ -62,19 +65,45 @@
padding: 1em;
}
}
.suggestion-box__results--above {
bottom: 4.5em;
&:before {
display: none;
}
&:after {
z-index: 1;
content: "";
position: absolute;
bottom: -.43em;
left: 1em;
width: 0; height: 0;
padding: .4em;
background: white;
border: inherit;
border-left: 0;
border-top: 0;
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
}
}
}
.suggestion-box > ul[hidden],
.suggestion-box > ul:empty,
div.awesomplete > ul[hidden],
div.awesomplete > ul:empty {
display: none;
}
@supports (transform: scale(0)) {
.suggestion-box > ul,
div.awesomplete > ul {
transition: .3s cubic-bezier(.4,.2,.5,1.4);
transform-origin: 1.43em -.43em;
}
.suggestion-box > ul[hidden],
.suggestion-box > ul:empty,
div.awesomplete > ul[hidden],
div.awesomplete > ul:empty {
opacity: 0;
@ -84,21 +113,26 @@
}
}
.suggestion-box > ul > li:hover,
div.awesomplete > ul > li:hover {
z-index: 2;
background: $red;
color: $inverse-link-color;
}
.suggestion-box > ul > li[aria-selected="true"],
div.awesomplete > ul > li[aria-selected="true"] {
background: hsl(205, 40%, 40%);
color: white;
}
.suggestion-box li:hover mark,
div.awesomplete li:hover mark {
background: $darkest-red;
color: $inverse-link-color;
}
.suggestion-box li[aria-selected="true"] mark,
div.awesomplete li[aria-selected="true"] mark {
background: hsl(86, 100%, 21%);
color: inherit;

View File

@ -605,6 +605,11 @@
ul {
width: 100%;
}
.suggestion-box__results {
&:after {
display: none;
}
}
.toggle-smiley {
ul {
&.emoji-toolbar {

View File

@ -271,7 +271,6 @@
}
.chat-textarea {
border-bottom-right-radius: 0;
resize: none;
&.correcting {
background-color: lighten($chatroom-head-color, 30%);
}

View File

@ -0,0 +1,465 @@
// Converse.js
// http://conversejs.org
//
// Copyright (c) 2013-2018, the Converse.js developers
// Licensed under the Mozilla Public License (MPLv2)
// This plugin started as a fork of Lea Verou's Awesomplete
// https://leaverou.github.io/awesomplete/
(function (root, factory) {
define(["converse-core"], factory);
}(this, function (converse) {
const { _, Backbone } = converse.env,
u = converse.env.utils;
converse.plugins.add("converse-autocomplete", {
initialize () {
const { _converse } = this;
_converse.FILTER_CONTAINS = function (text, input) {
return RegExp($.regExpEscape(input.trim()), "i").test(text);
};
_converse.FILTER_STARTSWITH = function (text, input) {
return RegExp("^" + $.regExpEscape(input.trim()), "i").test(text);
};
const _ac = function (el, o) {
const me = this;
this.is_opened = false;
if (u.hasClass('.suggestion-box', el)) {
this.container = el;
} else {
this.container = el.querySelector('.suggestion-box');
}
this.input = $(this.container.querySelector('.suggestion-box__input'));
this.input.setAttribute("autocomplete", "off");
this.input.setAttribute("aria-autocomplete", "list");
this.ul = $(this.container.querySelector('.suggestion-box__results'));
this.status = $(this.container.querySelector('.suggestion-box__additions'));
o = o || {};
configure(this, {
'match_current_word': false, // Match only the current word, otherwise all input is matched
'match_on_tab': false, // Whether matching should only start when tab's pressed
'min_chars': 2,
'max_items': 10,
'auto_evaluate': true,
'auto_first': false,
'data': _ac.DATA,
'filter': _ac.FILTER_CONTAINS,
'sort': o.sort === false ? false : _ac.SORT_BYLENGTH,
'item': _ac.ITEM,
'replace': _ac.REPLACE
}, o);
this.index = -1;
const input = {
"blur": this.close.bind(this, { reason: "blur" }),
"keydown": function(evt) {
const c = evt.keyCode;
// If the dropdown `ul` is in view, then act on keydown for the following keys:
// Enter / Esc / Up / Down
if(me.opened) {
if (c === _converse.keycodes.ENTER && me.selected) {
evt.preventDefault();
me.select();
} else if (c === _converse.keycodes.ESCAPE) {
me.close({ reason: "esc" });
} else if (c === _converse.keycodes.UP_ARROW || c === _converse.keycodes.DOWN_ARROW) {
evt.preventDefault();
me[c === _converse.keycodes.UP_ARROW ? "previous" : "next"]();
}
}
}
}
if (this.auto_evaluate) {
input["input"] = this.evaluate.bind(this);
}
// Bind events
this._events = {
'input': input,
'form': {
"submit": this.close.bind(this, { reason: "submit" })
},
'ul': {
"mousedown": function(evt) {
let li = evt.target;
if (li !== this) {
while (li && !(/li/i).test(li.nodeName)) {
li = li.parentNode;
}
if (li && evt.button === 0) { // Only select on left click
evt.preventDefault();
me.select(li, evt.target);
}
}
}
}
};
$.bind(this.input, this._events.input);
$.bind(this.input.form, this._events.form);
$.bind(this.ul, this._events.ul);
if (this.input.hasAttribute("list")) {
this.list = "#" + this.input.getAttribute("list");
this.input.removeAttribute("list");
}
else {
this.list = this.input.getAttribute("data-list") || o.list || [];
}
_ac.all.push(this);
}
_ac.prototype = {
set list (list) {
if (Array.isArray(list)) {
this._list = list;
}
else if (typeof list === "string" && _.includes(list, ",")) {
this._list = list.split(/\s*,\s*/);
}
else { // Element or CSS selector
list = $(list);
if (list && list.children) {
const items = [];
slice.apply(list.children).forEach(function (el) {
if (!el.disabled) {
const text = el.textContent.trim(),
value = el.value || text,
label = el.label || text;
if (value !== "") {
items.push({ label: label, value: value });
}
}
});
this._list = items;
}
}
if (document.activeElement === this.input) {
this.evaluate();
}
},
get selected() {
return this.index > -1;
},
get opened() {
return this.is_opened;
},
close (o) {
if (!this.opened) {
return;
}
this.ul.setAttribute("hidden", "");
this.is_opened = false;
this.index = -1;
$.fire(this.input, "suggestion-box-close", o || {});
},
open () {
this.ul.removeAttribute("hidden");
this.is_opened = true;
if (this.auto_first && this.index === -1) {
this.goto(0);
}
$.fire(this.input, "suggestion-box-open");
},
destroy () {
//remove events from the input and its form
$.unbind(this.input, this._events.input);
$.unbind(this.input.form, this._events.form);
//move the input out of the suggestion-box container and remove the container and its children
const parentNode = this.container.parentNode;
parentNode.insertBefore(this.input, this.container);
parentNode.removeChild(this.container);
//remove autocomplete and aria-autocomplete attributes
this.input.removeAttribute("autocomplete");
this.input.removeAttribute("aria-autocomplete");
//remove this awesomeplete instance from the global array of instances
var indexOfAutoComplete = _ac.all.indexOf(this);
if (indexOfAutoComplete !== -1) {
_ac.all.splice(indexOfAutoComplete, 1);
}
},
next () {
var count = this.ul.children.length;
this.goto(this.index < count - 1 ? this.index + 1 : (count ? 0 : -1) );
},
previous () {
var count = this.ul.children.length;
var pos = this.index - 1;
this.goto(this.selected && pos !== -1 ? pos : count - 1);
},
// Should not be used, highlights specific item without any checks!
goto (i) {
var lis = this.ul.children;
if (this.selected) {
lis[this.index].setAttribute("aria-selected", "false");
}
this.index = i;
if (i > -1 && lis.length > 0) {
lis[i].setAttribute("aria-selected", "true");
this.status.textContent = lis[i].textContent;
// scroll to highlighted element in case parent's height is fixed
this.ul.scrollTop = lis[i].offsetTop - this.ul.clientHeight + lis[i].clientHeight;
$.fire(this.input, "suggestion-box-highlight", {
text: this.suggestions[this.index]
});
}
},
select (selected, origin) {
if (selected) {
this.index = u.siblingIndex(selected);
} else {
selected = this.ul.children[this.index];
}
if (selected) {
const suggestion = this.suggestions[this.index],
allowed = $.fire(this.input, "suggestion-box-select", {
'text': suggestion,
'origin': origin || selected
});
if (allowed) {
this.replace(suggestion);
this.close({'reason': 'select'});
this.auto_completing = false;
this.trigger("suggestion-box-selectcomplete", {'text': suggestion});
}
}
},
keyPressed (ev) {
if (_.includes([
_converse.keycodes.SHIFT,
_converse.keycodes.META,
_converse.keycodes.META_RIGHT,
_converse.keycodes.ESCAPE,
_converse.keycodes.ALT]
, ev.keyCode)) {
return;
}
if (this.match_on_tab && ev.keyCode === _converse.keycodes.TAB) {
ev.preventDefault();
this.auto_completing = true;
}
if (this.auto_completing) {
this.evaluate();
}
},
evaluate (ev) {
let value = this.input.value;
if (this.match_current_word) {
value = u.getCurrentWord(this.input);
}
if (value.length >= this.min_chars && this._list.length > 0) {
this.index = -1;
// Populate list with options that match
this.ul.innerHTML = "";
this.suggestions = this._list
.map(item => new Suggestion(this.data(item, value)))
.filter(item => this.filter(item, value));
if (this.sort !== false) {
this.suggestions = this.suggestions.sort(this.sort);
}
this.suggestions = this.suggestions.slice(0, this.max_items);
this.suggestions.forEach((text) => this.ul.appendChild(this.item(text, value)));
if (this.ul.children.length === 0) {
this.close({'reason': 'nomatches'});
} else {
this.open();
}
} else {
this.close({'reason': 'nomatches'});
this.auto_completing = false;
}
}
};
// Make it an event emitter
_.extend(_ac.prototype, Backbone.Events);
// Static methods/properties
_ac.all = [];
_ac.SORT_BYLENGTH = function (a, b) {
if (a.length !== b.length) {
return a.length - b.length;
}
return a < b? -1 : 1;
};
_ac.ITEM = function (text, input) {
input = input.trim();
var element = document.createElement("li");
element.setAttribute("aria-selected", "false");
var regex = new RegExp("("+input+")", "ig");
var parts = input ? text.split(regex) : [text];
parts.forEach(function (txt) {
if (input && txt.match(regex)) {
var match = document.createElement("mark");
match.textContent = txt;
element.appendChild(match);
} else {
element.appendChild(document.createTextNode(txt));
}
});
return element;
};
_ac.REPLACE = function (text) {
this.input.value = text.value;
};
_ac.DATA = function (item/*, input*/) { return item; };
// Private functions
function Suggestion(data) {
const o = Array.isArray(data)
? { label: data[0], value: data[1] }
: typeof data === "object" && "label" in data && "value" in data ? data : { label: data, value: data };
this.label = o.label || o.value;
this.value = o.value;
}
Object.defineProperty(Suggestion.prototype = Object.create(String.prototype), "length", {
get: function() { return this.label.length; }
});
Suggestion.prototype.toString = Suggestion.prototype.valueOf = function () {
return "" + this.label;
};
function configure (instance, properties, o) {
for (var i in properties) {
if (!Object.prototype.hasOwnProperty.call(properties, i)) {
continue;
}
const initial = properties[i],
attr_value = instance.input.getAttribute("data-" + i.toLowerCase());
if (typeof initial === "number") {
instance[i] = parseInt(attr_value, 10);
} else if (initial === false) { // Boolean options must be false by default anyway
instance[i] = attr_value !== null;
} else if (initial instanceof Function) {
instance[i] = null;
} else {
instance[i] = attr_value;
}
if (!instance[i] && instance[i] !== 0) {
instance[i] = (i in o)? o[i] : initial;
}
}
}
// Helpers
var slice = Array.prototype.slice;
function $(expr, con) {
return typeof expr === "string"? (con || document).querySelector(expr) : expr || null;
}
function $$(expr, con) {
return slice.call((con || document).querySelectorAll(expr));
}
$.bind = function(element, o) {
if (element) {
for (var event in o) {
if (!Object.prototype.hasOwnProperty.call(o, event)) {
continue;
}
const callback = o[event];
event.split(/\s+/).forEach(event => element.addEventListener(event, callback));
}
}
};
$.unbind = function(element, o) {
if (element) {
for (var event in o) {
if (!Object.prototype.hasOwnProperty.call(o, event)) {
continue;
}
const callback = o[event];
event.split(/\s+/).forEach(event => element.removeEventListener(event, callback));
}
}
};
$.fire = function(target, type, properties) {
var evt = document.createEvent("HTMLEvents");
evt.initEvent(type, true, true );
for (var j in properties) {
if (!Object.prototype.hasOwnProperty.call(properties, j)) {
continue;
}
evt[j] = properties[j];
}
return target.dispatchEvent(evt);
};
$.regExpEscape = function (s) {
return s.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&");
};
_ac.$ = $;
_ac.$$ = $$;
_converse.AutoComplete = _ac;
}
});
}));

View File

@ -50,18 +50,6 @@
"use strict";
const { $msg, Backbone, Promise, Strophe, _, b64_sha1, f, sizzle, moment } = converse.env;
const u = converse.env.utils;
const KEY = {
ENTER: 13,
SHIFT: 17,
CTRL: 17,
ALT: 18,
ESCAPE: 27,
UP_ARROW: 38,
DOWN_ARROW: 40,
FORWARD_SLASH: 47,
META: 91,
META_RIGHT: 93
};
converse.plugins.add('converse-chatview', {
/* Plugin dependencies are other plugins which might be
@ -926,20 +914,26 @@
return;
}
if (!ev.shiftKey && !ev.altKey) {
if (ev.keyCode === KEY.FORWARD_SLASH) {
if (ev.keyCode === _converse.keycodes.FORWARD_SLASH) {
// Forward slash is used to run commands. Nothing to do here.
return;
} else if (ev.keyCode === KEY.ESCAPE) {
} else if (ev.keyCode === _converse.keycodes.ESCAPE) {
return this.onEscapePressed(ev);
} else if (ev.keyCode === KEY.ENTER) {
} else if (ev.keyCode === _converse.keycodes.ENTER) {
return this.onFormSubmitted(ev);
} else if (ev.keyCode === KEY.UP_ARROW && !ev.target.selectionEnd) {
} else if (ev.keyCode === _converse.keycodes.UP_ARROW && !ev.target.selectionEnd) {
return this.editEarlierMessage();
} else if (ev.keyCode === KEY.DOWN_ARROW && ev.target.selectionEnd === ev.target.value.length) {
} else if (ev.keyCode === _converse.keycodes.DOWN_ARROW && ev.target.selectionEnd === ev.target.value.length) {
return this.editLaterMessage();
}
}
if (_.includes([KEY.SHIFT, KEY.META, KEY.META_RIGHT, KEY.ESCAPE, KEY.ALT], ev.keyCode)) {
if (_.includes([
_converse.keycodes.SHIFT,
_converse.keycodes.META,
_converse.keycodes.META_RIGHT,
_converse.keycodes.ESCAPE,
_converse.keycodes.ALT]
, ev.keyCode)) {
return;
}
if (this.model.get('chat_state') !== _converse.COMPOSING) {

View File

@ -67,6 +67,7 @@
// Core plugins are whitelisted automatically
_converse.core_plugins = [
'converse-autocomplete',
'converse-bookmarks',
'converse-caps',
'converse-chatboxes',
@ -106,6 +107,21 @@
// Make converse pluggable
pluggable.enable(_converse, '_converse', 'pluggable');
_converse.keycodes = {
TAB: 9,
ENTER: 13,
SHIFT: 16,
CTRL: 17,
ALT: 18,
ESCAPE: 27,
UP_ARROW: 38,
DOWN_ARROW: 40,
FORWARD_SLASH: 47,
META: 91,
META_RIGHT: 93
};
// Module-level constants
_converse.STATUS_WEIGHTS = {
'offline': 6,

View File

@ -1,7 +1,7 @@
// Converse.js
// http://conversejs.org
//
// Copyright (c) 2012-2018, the Converse.js developers
// Copyright (c) 2013-2018, the Converse.js developers
// Licensed under the Mozilla Public License (MPLv2)
(function (root, factory) {
@ -93,7 +93,7 @@
* If the setting "strict_plugin_dependencies" is set to true,
* an error will be raised if the plugin is not found.
*/
dependencies: ["converse-modal", "converse-controlbox", "converse-chatview"],
dependencies: ["converse-autocomplete", "converse-modal", "converse-controlbox", "converse-chatview"],
overrides: {
@ -584,6 +584,7 @@
this.renderHeading();
this.renderChatArea();
this.renderMessageForm();
this.initAutoComplete();
if (this.model.get('connection_status') !== converse.ROOMSTATUS.ENTERED) {
this.showSpinner();
}
@ -610,6 +611,23 @@
return this;
},
initAutoComplete () {
this.auto_complete = new _converse.AutoComplete(this.el, {
'auto_evaluate': false,
'min_chars': 1,
'match_current_word': true,
'match_on_tab': true,
'list': this.model.occupants.map(o => ({'label': o.getDisplayName(), 'value': o.get('jid')})),
'filter': _converse.FILTER_STARTSWITH
});
this.auto_complete.on('suggestion-box-selectcomplete', () => (this.auto_completing = false));
},
keyPressed (ev) {
this.auto_complete.keyPressed(ev);
return _converse.ChatBoxView.prototype.keyPressed.apply(this, arguments);
},
showRoomDetailsModal (ev) {
ev.preventDefault();
if (_.isUndefined(this.model.room_details_modal)) {
@ -834,8 +852,7 @@
},
parseMessageForCommands (text) {
const _super_ = _converse.ChatBoxView.prototype;
if (_super_.parseMessageForCommands.apply(this, arguments)) {
if (_converse.ChatBoxView.prototype.parseMessageForCommands.apply(this, arguments)) {
return true;
}
if (_converse.muc_disable_moderator_commands) {

View File

@ -7,6 +7,7 @@ if (typeof define !== 'undefined') {
* --------------------
* Any of the following components may be removed if they're not needed.
*/
"converse-autocomplete",
"converse-bookmarks", // XEP-0048 Bookmarks
"converse-caps", // XEP-0115 Entity Capabilities
"converse-chatview", // Renders standalone chat boxes for single user chat

View File

@ -6,14 +6,22 @@
{[ } ]}
<input type="text" placeholder="{{o.label_spoiler_hint}}" value="{{ o.hint_value }}"
class="{[ if (!o.composing_spoiler) { ]} hidden {[ } ]} spoiler-hint"/>
<textarea
type="text"
class="chat-textarea
{[ if (o.show_send_button) { ]} chat-textarea-send-button {[ } ]}
{[ if (o.composing_spoiler) { ]} spoiler {[ } ]}"
placeholder="{{{o.label_personal_message}}}">{{ o.message_value }}</textarea>
{[ if (o.show_send_button) { ]}
<button type="submit" class="pure-button send-button">{{{ o.label_send }}}</button>
{[ } ]}
<div class="suggestion-box">
<ul class="suggestion-box__results suggestion-box__results--above" hidden></ul>
<textarea
type="text"
class="chat-textarea suggestion-box__input
{[ if (o.show_send_button) { ]} chat-textarea-send-button {[ } ]}
{[ if (o.composing_spoiler) { ]} spoiler {[ } ]}"
placeholder="{{{o.label_personal_message}}}">{{ o.message_value }}</textarea>
<span class="suggestion-box__additions visually-hidden" role="status" aria-live="assertive" aria-relevant="additions"></span>
{[ if (o.show_send_button) { ]}
<button type="submit" class="pure-button send-button">{{{ o.label_send }}}</button>
{[ } ]}
</div>
</form>
</div>

View File

@ -808,7 +808,18 @@
} else {
model.set(attributes);
}
}
};
u.siblingIndex = function (el) {
/* eslint-disable no-cond-assign */
for (var i = 0; el = el.previousElementSibling; i++);
return i;
};
u.getCurrentWord = function (input) {
const cursor = input.selectionEnd || undefined;
return _.last(input.value.slice(0, cursor).split(' '));
};
u.isVisible = function (el) {
if (u.hasClass('hidden', el)) {