Commit b6f4f05b authored by JC Brand's avatar JC Brand

Add converse-autocomplete and use that in the chat textarea

parent f0ad326e
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
"rules": { "rules": {
"lodash/prefer-lodash-method": [2, { "lodash/prefer-lodash-method": [2, {
"ignoreMethods": [ "ignoreMethods": [
"find", "endsWith", "startsWith", "filter", "reduce", "find", "endsWith", "startsWith", "filter", "reduce", "isArray", "create",
"map", "replace", "toLower", "split", "trim", "forEach", "toUpperCase", "includes" "map", "replace", "toLower", "split", "trim", "forEach", "toUpperCase", "includes"
] ]
}], }],
...@@ -215,10 +215,7 @@ ...@@ -215,10 +215,7 @@
"one-var": "off", "one-var": "off",
"one-var-declaration-per-line": "off", "one-var-declaration-per-line": "off",
"operator-assignment": "off", "operator-assignment": "off",
"operator-linebreak": [ "operator-linebreak": "off",
"error",
"after"
],
"padded-blocks": "off", "padded-blocks": "off",
"prefer-arrow-callback": "off", "prefer-arrow-callback": "off",
"prefer-const": "error", "prefer-const": "error",
......
...@@ -7748,6 +7748,8 @@ body.reset { ...@@ -7748,6 +7748,8 @@ body.reset {
line-height: 27px; } line-height: 27px; }
#conversejs.converse-fullscreen .chatbox .sendXMPPMessage ul { #conversejs.converse-fullscreen .chatbox .sendXMPPMessage ul {
width: 100%; } 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 { #conversejs.converse-fullscreen .chatbox .sendXMPPMessage .toggle-smiley ul.emoji-toolbar .emoji-category-picker {
margin-right: 5em; } margin-right: 5em; }
#conversejs.converse-fullscreen .chatbox .sendXMPPMessage .toggle-smiley ul.emoji-toolbar .emoji-category { #conversejs.converse-fullscreen .chatbox .sendXMPPMessage .toggle-smiley ul.emoji-toolbar .emoji-category {
...@@ -8681,8 +8683,7 @@ body.reset { ...@@ -8681,8 +8683,7 @@ body.reset {
color: #E77051; } color: #E77051; }
#conversejs.converse-embedded .chatroom .sendXMPPMessage .chat-textarea, #conversejs.converse-embedded .chatroom .sendXMPPMessage .chat-textarea,
#conversejs .chatroom .sendXMPPMessage .chat-textarea { #conversejs .chatroom .sendXMPPMessage .chat-textarea {
border-bottom-right-radius: 0; border-bottom-right-radius: 0; }
resize: none; }
#conversejs.converse-embedded .chatroom .sendXMPPMessage .chat-textarea.correcting, #conversejs.converse-embedded .chatroom .sendXMPPMessage .chat-textarea.correcting,
#conversejs .chatroom .sendXMPPMessage .chat-textarea.correcting { #conversejs .chatroom .sendXMPPMessage .chat-textarea.correcting {
background-color: #fadfd7; } background-color: #fadfd7; }
...@@ -9040,20 +9041,26 @@ body.reset { ...@@ -9040,20 +9041,26 @@ body.reset {
#conversejs .visually-hidden { #conversejs .visually-hidden {
position: absolute; position: absolute;
clip: rect(0, 0, 0, 0); } clip: rect(0, 0, 0, 0); }
#conversejs .form-group .suggestion-box,
#conversejs .form-group .awesomplete { #conversejs .form-group .awesomplete {
width: 100%; } width: 100%; }
#conversejs div.awesomplete { #conversejs .suggestion-box,
display: inline-block; #conversejs .awesomplete {
position: relative; } position: relative; }
#conversejs div.awesomplete mark { #conversejs .suggestion-box mark,
#conversejs .awesomplete mark {
background: #FFB9A7; } background: #FFB9A7; }
#conversejs div.awesomplete > input { #conversejs .suggestion-box > input,
#conversejs .awesomplete > input {
display: block; } 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; position: absolute;
left: 0; left: 0;
right: 0; right: 0;
z-index: 1; z-index: 2;
min-width: 100%; min-width: 100%;
box-sizing: border-box; box-sizing: border-box;
list-style: none; list-style: none;
...@@ -9061,51 +9068,91 @@ body.reset { ...@@ -9061,51 +9068,91 @@ body.reset {
border-radius: .3em; border-radius: .3em;
margin: .2em 0 0; margin: .2em 0 0;
background: rgba(255, 255, 255, 0.9); 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); 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; } 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: ""; content: "";
position: absolute; position: absolute;
top: -.43em; top: -.43em;
left: 1em; left: 1em;
width: 0; width: 0;
height: 0; height: 0;
padding: .4em;
background: white; background: white;
border: inherit; border: inherit;
border-right: 0; border-right: 0;
border-bottom: 0; border-bottom: 0;
-webkit-transform: rotate(45deg); -webkit-transform: rotate(45deg);
transform: rotate(45deg); } transform: rotate(45deg);
#conversejs div.awesomplete > ul > li { 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; text-overflow: ellipsis;
overflow-x: hidden; overflow-x: hidden;
position: relative; position: relative;
cursor: pointer; cursor: pointer;
padding: 1em; } 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[hidden],
#conversejs div.awesomplete > ul:empty { #conversejs div.awesomplete > ul:empty {
display: none; } display: none; }
@supports (transform: scale(0)) { @supports (transform: scale(0)) {
#conversejs .suggestion-box > ul,
#conversejs div.awesomplete > ul { #conversejs div.awesomplete > ul {
transition: 0.3s cubic-bezier(0.4, 0.2, 0.5, 1.4); transition: 0.3s cubic-bezier(0.4, 0.2, 0.5, 1.4);
transform-origin: 1.43em -.43em; } transform-origin: 1.43em -.43em; }
#conversejs .suggestion-box > ul[hidden],
#conversejs .suggestion-box > ul:empty,
#conversejs div.awesomplete > ul[hidden], #conversejs div.awesomplete > ul[hidden],
#conversejs div.awesomplete > ul:empty { #conversejs div.awesomplete > ul:empty {
opacity: 0; opacity: 0;
transform: scale(0); transform: scale(0);
display: block; display: block;
transition-timing-function: ease; } } transition-timing-function: ease; } }
#conversejs .suggestion-box > ul > li:hover,
#conversejs div.awesomplete > ul > li:hover { #conversejs div.awesomplete > ul > li:hover {
z-index: 2;
background: #E77051; background: #E77051;
color: white; } color: white; }
#conversejs .suggestion-box > ul > li[aria-selected="true"],
#conversejs div.awesomplete > ul > li[aria-selected="true"] { #conversejs div.awesomplete > ul > li[aria-selected="true"] {
background: #3d6d8f; background: #3d6d8f;
color: white; } color: white; }
#conversejs .suggestion-box li:hover mark,
#conversejs div.awesomplete li:hover mark { #conversejs div.awesomplete li:hover mark {
background: #A53214; background: #A53214;
color: white; } color: white; }
#conversejs .suggestion-box li[aria-selected="true"] mark,
#conversejs div.awesomplete li[aria-selected="true"] mark { #conversejs div.awesomplete li[aria-selected="true"] mark {
background: #3d6b00; background: #3d6b00;
color: inherit; } color: inherit; }
......
This diff is collapsed.
...@@ -7,13 +7,14 @@ ...@@ -7,13 +7,14 @@
} }
.form-group { .form-group {
.suggestion-box,
.awesomplete { .awesomplete {
width: 100%; width: 100%;
} }
} }
div.awesomplete { .suggestion-box,
display: inline-block; .awesomplete {
position: relative; position: relative;
mark { mark {
background: $lightest-red; background: $lightest-red;
...@@ -23,6 +24,7 @@ ...@@ -23,6 +24,7 @@
display: block; display: block;
} }
.suggestion-box__results,
> ul { > ul {
&:before { &:before {
content: ""; content: "";
...@@ -30,18 +32,19 @@ ...@@ -30,18 +32,19 @@
top: -.43em; top: -.43em;
left: 1em; left: 1em;
width: 0; height: 0; width: 0; height: 0;
padding: .4em;
background: white; background: white;
border: inherit; border: inherit;
border-right: 0; border-right: 0;
border-bottom: 0; border-bottom: 0;
-webkit-transform: rotate(45deg); -webkit-transform: rotate(45deg);
transform: rotate(45deg); transform: rotate(45deg);
z-index: 1;
} }
position: absolute; position: absolute;
left: 0; left: 0;
right: 0; right: 0;
z-index: 1; z-index: 2;
min-width: 100%; min-width: 100%;
box-sizing: border-box; box-sizing: border-box;
list-style: none; list-style: none;
...@@ -49,9 +52,9 @@ ...@@ -49,9 +52,9 @@
border-radius: .3em; border-radius: .3em;
margin: .2em 0 0; margin: .2em 0 0;
background: hsla(0,0%,100%,.9); 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); 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; text-shadow: none;
> li { > li {
...@@ -62,19 +65,45 @@ ...@@ -62,19 +65,45 @@
padding: 1em; 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[hidden],
div.awesomplete > ul:empty { div.awesomplete > ul:empty {
display: none; display: none;
} }
@supports (transform: scale(0)) { @supports (transform: scale(0)) {
.suggestion-box > ul,
div.awesomplete > ul { div.awesomplete > ul {
transition: .3s cubic-bezier(.4,.2,.5,1.4); transition: .3s cubic-bezier(.4,.2,.5,1.4);
transform-origin: 1.43em -.43em; transform-origin: 1.43em -.43em;
} }
.suggestion-box > ul[hidden],
.suggestion-box > ul:empty,
div.awesomplete > ul[hidden], div.awesomplete > ul[hidden],
div.awesomplete > ul:empty { div.awesomplete > ul:empty {
opacity: 0; opacity: 0;
...@@ -84,21 +113,26 @@ ...@@ -84,21 +113,26 @@
} }
} }
.suggestion-box > ul > li:hover,
div.awesomplete > ul > li:hover { div.awesomplete > ul > li:hover {
z-index: 2;
background: $red; background: $red;
color: $inverse-link-color; color: $inverse-link-color;
} }
.suggestion-box > ul > li[aria-selected="true"],
div.awesomplete > ul > li[aria-selected="true"] { div.awesomplete > ul > li[aria-selected="true"] {
background: hsl(205, 40%, 40%); background: hsl(205, 40%, 40%);
color: white; color: white;
} }
.suggestion-box li:hover mark,
div.awesomplete li:hover mark { div.awesomplete li:hover mark {
background: $darkest-red; background: $darkest-red;
color: $inverse-link-color; color: $inverse-link-color;
} }
.suggestion-box li[aria-selected="true"] mark,
div.awesomplete li[aria-selected="true"] mark { div.awesomplete li[aria-selected="true"] mark {
background: hsl(86, 100%, 21%); background: hsl(86, 100%, 21%);
color: inherit; color: inherit;
......
...@@ -605,6 +605,11 @@ ...@@ -605,6 +605,11 @@
ul { ul {
width: 100%; width: 100%;
} }
.suggestion-box__results {
&:after {
display: none;
}
}
.toggle-smiley { .toggle-smiley {
ul { ul {
&.emoji-toolbar { &.emoji-toolbar {
......
...@@ -271,7 +271,6 @@ ...@@ -271,7 +271,6 @@
} }
.chat-textarea { .chat-textarea {
border-bottom-right-radius: 0; border-bottom-right-radius: 0;
resize: none;
&.correcting { &.correcting {
background-color: lighten($chatroom-head-color, 30%); background-color: lighten($chatroom-head-color, 30%);
} }
......
This diff is collapsed.
...@@ -50,18 +50,6 @@ ...@@ -50,18 +50,6 @@
"use strict"; "use strict";
const { $msg, Backbone, Promise, Strophe, _, b64_sha1, f, sizzle, moment } = converse.env; const { $msg, Backbone, Promise, Strophe, _, b64_sha1, f, sizzle, moment } = converse.env;
const u = converse.env.utils; 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', { converse.plugins.add('converse-chatview', {
/* Plugin dependencies are other plugins which might be /* Plugin dependencies are other plugins which might be
...@@ -926,20 +914,26 @@ ...@@ -926,20 +914,26 @@
return; return;
} }
if (!ev.shiftKey && !ev.altKey) { 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. // Forward slash is used to run commands. Nothing to do here.
return; return;
} else if (ev.keyCode === KEY.ESCAPE) { } else if (ev.keyCode === _converse.keycodes.ESCAPE) {
return this.onEscapePressed(ev); return this.onEscapePressed(ev);
} else if (ev.keyCode === KEY.ENTER) { } else if (ev.keyCode === _converse.keycodes.ENTER) {
return this.onFormSubmitted(ev); 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(); 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(); 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; return;
} }
if (this.model.get('chat_state') !== _converse.COMPOSING) { if (this.model.get('chat_state') !== _converse.COMPOSING) {
......
...@@ -67,6 +67,7 @@ ...@@ -67,6 +67,7 @@
// Core plugins are whitelisted automatically // Core plugins are whitelisted automatically
_converse.core_plugins = [ _converse.core_plugins = [
'converse-autocomplete',
'converse-bookmarks', 'converse-bookmarks',
'converse-caps', 'converse-caps',
'converse-chatboxes', 'converse-chatboxes',
...@@ -106,6 +107,21 @@ ...@@ -106,6 +107,21 @@
// Make converse pluggable // Make converse pluggable
pluggable.enable(_converse, '_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 // Module-level constants
_converse.STATUS_WEIGHTS = { _converse.STATUS_WEIGHTS = {
'offline': 6, 'offline': 6,
......
// Converse.js // Converse.js
// http://conversejs.org // 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) // Licensed under the Mozilla Public License (MPLv2)
(function (root, factory) { (function (root, factory) {
...@@ -93,7 +93,7 @@ ...@@ -93,7 +93,7 @@
* If the setting "strict_plugin_dependencies" is set to true, * If the setting "strict_plugin_dependencies" is set to true,
* an error will be raised if the plugin is not found. * 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: { overrides: {
...@@ -584,6 +584,7 @@ ...@@ -584,6 +584,7 @@
this.renderHeading(); this.renderHeading();
this.renderChatArea(); this.renderChatArea();
this.renderMessageForm(); this.renderMessageForm();
this.initAutoComplete();
if (this.model.get('connection_status') !== converse.ROOMSTATUS.ENTERED) { if (this.model.get('connection_status') !== converse.ROOMSTATUS.ENTERED) {
this.showSpinner(); this.showSpinner();
} }
...@@ -610,6 +611,23 @@ ...@@ -610,6 +611,23 @@
return this; 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) { showRoomDetailsModal (ev) {
ev.preventDefault(); ev.preventDefault();
if (_.isUndefined(this.model.room_details_modal)) { if (_.isUndefined(this.model.room_details_modal)) {
...@@ -834,8 +852,7 @@ ...@@ -834,8 +852,7 @@
}, },
parseMessageForCommands (text) { parseMessageForCommands (text) {
const _super_ = _converse.ChatBoxView.prototype; if (_converse.ChatBoxView.prototype.parseMessageForCommands.apply(this, arguments)) {
if (_super_.parseMessageForCommands.apply(this, arguments)) {
return true; return true;
} }
if (_converse.muc_disable_moderator_commands) { if (_converse.muc_disable_moderator_commands) {
......
...@@ -7,6 +7,7 @@ if (typeof define !== 'undefined') { ...@@ -7,6 +7,7 @@ if (typeof define !== 'undefined') {
* -------------------- * --------------------
* Any of the following components may be removed if they're not needed. * Any of the following components may be removed if they're not needed.
*/ */
"converse-autocomplete",
"converse-bookmarks", // XEP-0048 Bookmarks "converse-bookmarks", // XEP-0048 Bookmarks
"converse-caps", // XEP-0115 Entity Capabilities "converse-caps", // XEP-0115 Entity Capabilities
"converse-chatview", // Renders standalone chat boxes for single user chat "converse-chatview", // Renders standalone chat boxes for single user chat
......
...@@ -6,14 +6,22 @@ ...@@ -6,14 +6,22 @@
{[ } ]} {[ } ]}
<input type="text" placeholder="{{o.label_spoiler_hint}}" value="{{ o.hint_value }}" <input type="text" placeholder="{{o.label_spoiler_hint}}" value="{{ o.hint_value }}"
class="{[ if (!o.composing_spoiler) { ]} hidden {[ } ]} spoiler-hint"/> class="{[ if (!o.composing_spoiler) { ]} hidden {[ } ]} spoiler-hint"/>
<textarea
type="text" <div class="suggestion-box">
class="chat-textarea <ul class="suggestion-box__results suggestion-box__results--above" hidden></ul>
{[ if (o.show_send_button) { ]} chat-textarea-send-button {[ } ]} <textarea
{[ if (o.composing_spoiler) { ]} spoiler {[ } ]}" type="text"
placeholder="{{{o.label_personal_message}}}">{{ o.message_value }}</textarea> class="chat-textarea suggestion-box__input
{[ if (o.show_send_button) { ]} {[ if (o.show_send_button) { ]} chat-textarea-send-button {[ } ]}
<button type="submit" class="pure-button send-button">{{{ o.label_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> </form>
</div> </div>
...@@ -808,7 +808,18 @@ ...@@ -808,7 +808,18 @@
} else { } else {
model.set(attributes); 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) { u.isVisible = function (el) {
if (u.hasClass('hidden', el)) { if (u.hasClass('hidden', el)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment