From 6fea88fcc315f5057a72c793dbb0ba052ea7f4c9 Mon Sep 17 00:00:00 2001 From: JC Brand Date: Mon, 17 Jul 2017 22:01:23 +0200 Subject: [PATCH] Add JID validation and error messages to the `add contact` form --- css/converse.css | 62 +++++++++++------------- css/inverse.css | 64 ++++++++++++------------- sass/_chatbox.scss | 3 -- sass/_controlbox.scss | 18 +++---- sass/inverse/_chatbox.scss | 3 ++ src/converse-controlbox.js | 36 ++++++++------ src/converse-core.js | 3 -- src/templates/add_contact_dropdown.html | 5 +- src/templates/add_contact_form.html | 20 ++++---- src/utils.js | 13 +++-- 10 files changed, 117 insertions(+), 110 deletions(-) diff --git a/css/converse.css b/css/converse.css index 5abfd0d0e..45bdcd444 100644 --- a/css/converse.css +++ b/css/converse.css @@ -1769,9 +1769,6 @@ #converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul.emoji-toolbar .picked, #conversejs .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul.emoji-toolbar .picked { background-color: #DCF9F6; } - #converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul.emoji-toolbar .emoji-category-picker, - #conversejs .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul.emoji-toolbar .emoji-category-picker { - margin-right: 5em; } #converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul.emoji-toolbar li, #conversejs .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul.emoji-toolbar li { height: 30px; @@ -2028,37 +2025,37 @@ padding: 0.3em 0; clear: left; width: 100%; } - #conversejs #controlbox .dropdown { - /* Custom addition for CSP */ } - #conversejs #controlbox .dropdown a { - width: 143px; - display: inline-block; } - #conversejs #controlbox .dropdown li { - list-style: none; - padding-left: 0; } - #conversejs #controlbox .dropdown dd ul { - padding: 0; - list-style: none; + #conversejs #controlbox .dropdown a { + width: 143px; + display: inline-block; } + #conversejs #controlbox .dropdown li { + list-style: none; + padding-left: 0; } + #conversejs #controlbox .dropdown dd ul { + padding: 0; + list-style: none; + position: absolute; + left: 0; + top: 0; + width: 100%; + z-index: 21; + background-color: #FCFDFD; } + #conversejs #controlbox .dropdown dd ul li:hover { + background-color: #DCF9F6; } + #conversejs #controlbox .dropdown dd.search-xmpp { + height: 0; } + #conversejs #controlbox .dropdown dd.search-xmpp .contact-form-container { position: absolute; - left: 0; - top: 0; - border: 1px solid #B1BFC4; - width: 100%; - z-index: 21; + z-index: 22; } + #conversejs #controlbox .dropdown dd.search-xmpp .contact-form-container form { + box-shadow: 1px 4px 10px 1px rgba(0, 0, 0, 0.4); + background-color: white; } + #conversejs #controlbox .dropdown dd.search-xmpp li:hover { background-color: #FCFDFD; } - #conversejs #controlbox .dropdown dd ul li:hover { - background-color: #DCF9F6; } - #conversejs #controlbox .dropdown dd.search-xmpp { - display: none; - width: 100%; } - #conversejs #controlbox .dropdown dd.search-xmpp ul { - box-shadow: 1px 4px 10px 1px rgba(0, 0, 0, 0.4); } - #conversejs #controlbox .dropdown dd.search-xmpp ul li:hover { - background-color: #FCFDFD; } - #conversejs #controlbox .dropdown dt a span { - cursor: pointer; - display: block; - padding: 4px 7px 0 5px; } + #conversejs #controlbox .dropdown dt a span { + cursor: pointer; + display: block; + padding: 4px 7px 0 5px; } #conversejs #controlbox #select-xmpp-status { display: none; float: right; @@ -2175,7 +2172,6 @@ #conversejs #controlbox #users { overflow-y: hidden; } #conversejs #controlbox .add-xmpp-contact { - background: none; padding: 1em 0.5em; } #conversejs #controlbox .add-xmpp-contact input { margin: 0 0 1rem; diff --git a/css/inverse.css b/css/inverse.css index 21d849dca..1d952893a 100644 --- a/css/inverse.css +++ b/css/inverse.css @@ -1815,9 +1815,6 @@ body { #converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul.emoji-toolbar .picked, #conversejs .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul.emoji-toolbar .picked { background-color: #DCF9F6; } - #converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul.emoji-toolbar .emoji-category-picker, - #conversejs .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul.emoji-toolbar .emoji-category-picker { - margin-right: 5em; } #converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul.emoji-toolbar li, #conversejs .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul.emoji-toolbar li { height: 32px; @@ -1939,6 +1936,8 @@ body { width: 100%; } #conversejs .chatbox form.sendXMPPMessage .toggle-smiley { padding-left: 0.5em; } + #conversejs .chatbox form.sendXMPPMessage .toggle-smiley ul.emoji-toolbar .emoji-category-picker { + margin-right: 5em; } #conversejs .chatbox form.sendXMPPMessage .toggle-smiley ul.emoji-toolbar .emoji-category { padding-left: 10px; padding-right: 10px; } @@ -2106,37 +2105,37 @@ body { padding: 0.3em 0; clear: left; width: 100%; } - #conversejs #controlbox .dropdown { - /* Custom addition for CSP */ } - #conversejs #controlbox .dropdown a { - width: 143px; - display: inline-block; } - #conversejs #controlbox .dropdown li { - list-style: none; - padding-left: 0; } - #conversejs #controlbox .dropdown dd ul { - padding: 0; - list-style: none; + #conversejs #controlbox .dropdown a { + width: 143px; + display: inline-block; } + #conversejs #controlbox .dropdown li { + list-style: none; + padding-left: 0; } + #conversejs #controlbox .dropdown dd ul { + padding: 0; + list-style: none; + position: absolute; + left: 0; + top: 0; + width: 100%; + z-index: 21; + background-color: #FCFDFD; } + #conversejs #controlbox .dropdown dd ul li:hover { + background-color: #DCF9F6; } + #conversejs #controlbox .dropdown dd.search-xmpp { + height: 0; } + #conversejs #controlbox .dropdown dd.search-xmpp .contact-form-container { position: absolute; - left: 0; - top: 0; - border: 1px solid #B1BFC4; - width: 100%; - z-index: 21; + z-index: 22; } + #conversejs #controlbox .dropdown dd.search-xmpp .contact-form-container form { + box-shadow: 1px 4px 10px 1px rgba(0, 0, 0, 0.4); + background-color: white; } + #conversejs #controlbox .dropdown dd.search-xmpp li:hover { background-color: #FCFDFD; } - #conversejs #controlbox .dropdown dd ul li:hover { - background-color: #DCF9F6; } - #conversejs #controlbox .dropdown dd.search-xmpp { - display: none; - width: 100%; } - #conversejs #controlbox .dropdown dd.search-xmpp ul { - box-shadow: 1px 4px 10px 1px rgba(0, 0, 0, 0.4); } - #conversejs #controlbox .dropdown dd.search-xmpp ul li:hover { - background-color: #FCFDFD; } - #conversejs #controlbox .dropdown dt a span { - cursor: pointer; - display: block; - padding: 4px 7px 0 5px; } + #conversejs #controlbox .dropdown dt a span { + cursor: pointer; + display: block; + padding: 4px 7px 0 5px; } #conversejs #controlbox #select-xmpp-status { display: none; float: right; @@ -2253,7 +2252,6 @@ body { #conversejs #controlbox #users { overflow-y: hidden; } #conversejs #controlbox .add-xmpp-contact { - background: none; padding: 1em 0.5em; } #conversejs #controlbox .add-xmpp-contact input { margin: 0 0 1rem; diff --git a/sass/_chatbox.scss b/sass/_chatbox.scss index 954822527..c3eb019bd 100644 --- a/sass/_chatbox.scss +++ b/sass/_chatbox.scss @@ -337,9 +337,6 @@ .picked { background-color: $highlight-color; } - .emoji-category-picker { - margin-right: 5em; - } li { height: $emoji_height + 2*5px; padding: 4px; diff --git a/sass/_controlbox.scss b/sass/_controlbox.scss index cf629f9a3..b0d817534 100644 --- a/sass/_controlbox.scss +++ b/sass/_controlbox.scss @@ -236,7 +236,6 @@ position: absolute; left: 0; top: 0; - border: 1px solid $light-background-border-color; width: 100%; z-index: 21; background-color: $light-background-color; @@ -246,14 +245,16 @@ } } - /* Custom addition for CSP */ dd.search-xmpp { - display: none; - width: 100%; - } - - dd.search-xmpp ul { - box-shadow: 1px 4px 10px 1px rgba(0, 0, 0, 0.4); + height: 0; + .contact-form-container { + position: absolute; + z-index: 22; + form { + box-shadow: 1px 4px 10px 1px rgba(0, 0, 0, 0.4); + background-color: white; + } + } li:hover { background-color: $light-background-color; } @@ -420,7 +421,6 @@ } .add-xmpp-contact { - background: none; padding: 1em 0.5em; input { margin: 0 0 1rem; diff --git a/sass/inverse/_chatbox.scss b/sass/inverse/_chatbox.scss index f275035c8..d26396a51 100644 --- a/sass/inverse/_chatbox.scss +++ b/sass/inverse/_chatbox.scss @@ -74,6 +74,9 @@ padding-left: 0.5em; ul { &.emoji-toolbar { + .emoji-category-picker { + margin-right: 5em; + } .emoji-category { padding-left: 10px; padding-right: 10px; diff --git a/src/converse-controlbox.js b/src/converse-controlbox.js index c7c3c3fae..e2169cb8e 100644 --- a/src/converse-controlbox.js +++ b/src/converse-controlbox.js @@ -635,31 +635,32 @@ this.parent_el.appendChild(this.render().el); this.tabs = this.parent_el.parentNode.querySelector('#controlbox-tabs'); this.tabs.appendChild(this.tab_el); - this.$('.search-xmpp ul').append( - this.generateAddContactHTML() - ); return this; }, - generateAddContactHTML () { + generateAddContactHTML (settings={}) { if (_converse.xhr_user_search) { return tpl_search_contact({ label_contact_name: __('Contact name'), label_search: __('Search') }); } else { - return tpl_add_contact_form({ + return tpl_add_contact_form(_.assign({ + error_message: null, label_contact_username: __('e.g. user@example.org'), - label_add: __('Add') - }); + label_add: __('Add'), + value: '' + }, settings)); } }, toggleContactForm (ev) { ev.preventDefault(); - this.$el.find('.search-xmpp').toggle('fast', function () { - if ($(this).is(':visible')) { - $(this).find('input.username').focus(); + this.el.querySelector('.search-xmpp div').innerHTML = this.generateAddContactHTML(); + var dropdown = this.el.querySelector('.contact-form-container'); + utils.slideToggleElement(dropdown).then(() => { + if ($(dropdown).is(':visible')) { + $(dropdown).find('input.username').focus(); } }); }, @@ -690,13 +691,18 @@ ev.preventDefault(); const $input = $(ev.target).find('input'); const jid = $input.val(); - if (! jid) { - // this is not a valid JID - $input.addClass('error'); + if (!jid || _.filter(jid.split('@')).length < 2) { + this.el.querySelector('.search-xmpp div').innerHTML = + this.generateAddContactHTML({ + error_message: __('Please enter a valid XMPP username'), + label_contact_username: __('e.g. user@example.org'), + label_add: __('Add'), + value: jid + }); return; } _converse.roster.addAndSubscribe(jid); - $('.search-xmpp').hide(); + utils.slideIn(this.el.querySelector('.contact-form-container')); }, addContactFromList (ev) { @@ -706,7 +712,7 @@ name = $target.text(); _converse.roster.addAndSubscribe(jid, name); $target.parent().remove(); - $('.search-xmpp').hide(); + utils.slideIn(this.el.querySelector('.contact-form-container')); } }); diff --git a/src/converse-core.js b/src/converse-core.js index 91bb45f5d..f9f9f5f6c 100755 --- a/src/converse-core.js +++ b/src/converse-core.js @@ -1417,15 +1417,12 @@ } }); - this.Messages = Backbone.Collection.extend({ model: _converse.Message, comparator: 'time' }); - this.ChatBox = Backbone.Model.extend({ - defaults: { 'type': 'chatbox', 'bookmarked': false, diff --git a/src/templates/add_contact_dropdown.html b/src/templates/add_contact_dropdown.html index dccfce4c6..90e545429 100644 --- a/src/templates/add_contact_dropdown.html +++ b/src/templates/add_contact_dropdown.html @@ -2,5 +2,8 @@ -
+
+ + +
diff --git a/src/templates/add_contact_form.html b/src/templates/add_contact_form.html index 6fac2c954..f88dc032b 100644 --- a/src/templates/add_contact_form.html +++ b/src/templates/add_contact_form.html @@ -1,9 +1,11 @@ -
  • -
    - - -
    -
  • +
    + {[ if (error_message) { ]} + {{{error_message}}} + {[ } ]} + + +
    diff --git a/src/utils.js b/src/utils.js index 2ce7b3dde..0fb78a87a 100755 --- a/src/utils.js +++ b/src/utils.js @@ -214,6 +214,13 @@ ); } + function wrapup (el) { + el.removeAttribute('data-slider-marker'); + el.classList.remove('collapsed'); + el.style.overflow = ""; + el.style.height = ""; + } + return new Promise((resolve, reject) => { if (_.isNil(el)) { const err = "Undefined or null element passed into slideOut" @@ -229,6 +236,7 @@ const end_height = calculateEndHeight(el); if ($.fx.off) { // Effects are disabled (for tests) el.style.height = end_height + 'px'; + wrapup(el); resolve(); return; } @@ -247,10 +255,7 @@ // offsetHeight beforehand. el.style.height = calculateEndHeight(el) + 'px'; window.clearInterval(interval_marker); - el.removeAttribute('data-slider-marker'); - el.classList.remove('collapsed'); - el.style.overflow = ""; - el.style.height = ""; + wrapup(el); resolve(); } }, interval);