diff --git a/css/converse.css b/css/converse.css index 9955e8e4a..816555071 100644 --- a/css/converse.css +++ b/css/converse.css @@ -228,7 +228,7 @@ content: "\2b25"; } #converse-embedded-chat .icon-remove:before, #conversejs .icon-remove:before { - content: "\e02d"; } + content: "\2715"; } #converse-embedded-chat .icon-room-info:before, #conversejs .icon-room-info:before { content: "\e059"; } @@ -1328,7 +1328,7 @@ #converse-embedded-chat form.pure-form.converse-form, #conversejs form.pure-form.converse-form { background: white; - padding: 1em; } + padding: 0 1em; } #converse-embedded-chat form.pure-form.converse-form legend, #conversejs form.pure-form.converse-form legend { color: #818479; } @@ -1889,51 +1889,63 @@ #conversejs #controlbox #chatrooms form.add-chatroom input[type=submit], #conversejs #controlbox #chatrooms form.add-chatroom input[type=text] { width: 100%; } - #conversejs #controlbox #chatrooms dl.rooms-list { - margin: 0 1em; - padding: 0; - text-align: left; } - #conversejs #controlbox #chatrooms dl.rooms-list dt { - border: none; - color: #818479; - font-weight: normal; - padding: 0; - padding-bottom: 0.5em; - text-shadow: 0 1px 0 #FAFAFA; } - #conversejs #controlbox #chatrooms dl.rooms-list dd.available-chatroom { - border: none; - clear: both; - color: #818479; + #conversejs #controlbox #chatrooms .rooms-list-container { + text-align: left; + margin: 0 1em; } + #conversejs #controlbox #chatrooms .rooms-list-container .rooms-toggle { display: block; - overflow: hidden; - padding: 0.1em; - text-shadow: 0 1px 0 #FAFAFA; - word-wrap: break-word; } - #conversejs #controlbox #chatrooms dl.rooms-list dd.available-chatroom:hover { - background-color: #DCF9F6; } - #conversejs #controlbox #chatrooms dl.rooms-list dd.available-chatroom a.room-info { - clear: right; - display: block; } - #conversejs #controlbox #chatrooms dl.rooms-list dd.available-chatroom a.room-info:before { - font-size: 15px; } - #conversejs #controlbox #chatrooms dl.rooms-list dd.available-chatroom a.open-room { - float: left; - width: 85%; } - #conversejs #controlbox #chatrooms dl.rooms-list dd.available-chatroom .room-info { - font-size: 12px; - font-style: normal; - font-weight: normal; } - #conversejs #controlbox #chatrooms dl.rooms-list dd.available-chatroom li.room-info { - display: block; - margin-left: 5px; } - #conversejs #controlbox #chatrooms dl.rooms-list dd.available-chatroom p.room-info { - margin: 0; + font-weight: bold; + color: #818479; + margin-top: 1em; } + #conversejs #controlbox #chatrooms .rooms-list-container dl.rooms-list { + margin: 0.5em 0; + text-align: left; } + #conversejs #controlbox #chatrooms .rooms-list-container dl.rooms-list dt { + border: none; + color: #818479; + font-weight: normal; padding: 0; + padding-bottom: 0.5em; + text-shadow: 0 1px 0 #FAFAFA; } + #conversejs #controlbox #chatrooms .rooms-list-container dl.rooms-list dd.available-chatroom { + border: none; + clear: both; + color: #818479; display: block; - white-space: normal; } - #conversejs #controlbox #chatrooms dl.rooms-list dd.available-chatroom div.room-info { - clear: left; - width: 100%; } + overflow: hidden; + padding: 0.3em 0; + text-shadow: 0 1px 0 #FAFAFA; + word-wrap: break-word; } + #conversejs #controlbox #chatrooms .rooms-list-container dl.rooms-list dd.available-chatroom:hover { + background-color: #DCF9F6; } + #conversejs #controlbox #chatrooms .rooms-list-container dl.rooms-list dd.available-chatroom a.room-info:before { + font-size: 15px; } + #conversejs #controlbox #chatrooms .rooms-list-container dl.rooms-list dd.available-chatroom a.open-room { + float: left; + width: 68%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + padding-right: 0.5em; } + #conversejs #controlbox #chatrooms .rooms-list-container dl.rooms-list dd.available-chatroom .remove-bookmark { + color: #BBB; } + #conversejs #controlbox #chatrooms .rooms-list-container dl.rooms-list dd.available-chatroom .remove-bookmark.button-on { + color: #2A9D8F; } + #conversejs #controlbox #chatrooms .rooms-list-container dl.rooms-list dd.available-chatroom .room-info { + font-size: 12px; + font-style: normal; + font-weight: normal; } + #conversejs #controlbox #chatrooms .rooms-list-container dl.rooms-list dd.available-chatroom li.room-info { + display: block; + margin-left: 5px; } + #conversejs #controlbox #chatrooms .rooms-list-container dl.rooms-list dd.available-chatroom p.room-info { + margin: 0; + padding: 0; + display: block; + white-space: normal; } + #conversejs #controlbox #chatrooms .rooms-list-container dl.rooms-list dd.available-chatroom div.room-info { + clear: left; + width: 100%; } #conversejs #controlbox .dropdown { /* Custom addition for CSP */ } #conversejs #controlbox .dropdown a { @@ -2356,7 +2368,7 @@ float: right; margin-right: 1em; padding-top: 0.5em; - color: #A8ABA1; } + color: #BBB; } #conversejs #converse-roster span.pending-contact-name { line-height: 16px; width: 100%; } @@ -2628,24 +2640,6 @@ #conversejs #minimized-chats .chat-head-message-count-hidden { display: none; } -#conversejs #controlbox #chatrooms .bookmarks-list { - padding-top: 1em; } - #conversejs #controlbox #chatrooms .bookmarks-list .bookmarks-toggle { - display: block; - font-weight: bold; - color: #818479; - margin-bottom: 0.5em; } - #conversejs #controlbox #chatrooms .bookmarks-list dl.rooms-list.bookmarks dd.available-chatroom a.room-info { - clear: none; } - #conversejs #controlbox #chatrooms .bookmarks-list dl.rooms-list.bookmarks dd.available-chatroom a.open-room { - width: 75%; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - padding-right: 0.5em; } - #conversejs #controlbox #chatrooms .bookmarks-list dl.rooms-list.bookmarks dd.available-chatroom .remove-bookmark { - float: right; } - #converse-embedded-chat, #conversejs { /* Pointer */ } diff --git a/docs/CHANGES.md b/docs/CHANGES.md index ccb31b199..8f4cfd5e5 100755 --- a/docs/CHANGES.md +++ b/docs/CHANGES.md @@ -6,13 +6,13 @@ one chat is visible at any given time. Used in the mobile build: `converse-mobile.js` and makes the unread messages counter possible there. [jcbrand] -- Show unread messages next to roster contacts. [jcbrand] - API change: the `message` event now returns a data object with `stanza` and `chatbox` attributes, instead of just the stanza. [jcbrand] +- Remove all inline CSS to comply with strict Content-Security-Policy headers [mathiasertl] - #567 Unreaded message count reset on page load [novokrest] - #591 Unread message counter is reset when the chatbox is closed [novokrest] +- #754 Show unread messages next to roster contacts. [jcbrand] - #873 Inconsistent unread messages count updating [novokrest] -- Remove all inline CSS to comply with strict Content-Security-Policy headers [mathiasertl] ## 3.0.2 (2017-04-23) diff --git a/sass/_bookmarks.scss b/sass/_bookmarks.scss index 5e1469b73..302ce4a0b 100644 --- a/sass/_bookmarks.scss +++ b/sass/_bookmarks.scss @@ -2,33 +2,6 @@ #controlbox { #chatrooms { .bookmarks-list { - padding-top: 1em; - - .bookmarks-toggle { - display: block; - font-weight: bold; - color: $text-color; - margin-bottom: 0.5em; - } - dl.rooms-list.bookmarks { - dd.available-chatroom { - a { - &.room-info { - clear: none; - } - &.open-room { - width: 75%; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - padding-right: 0.5em; - } - } - .remove-bookmark { - float: right; - } - } - } } } } diff --git a/sass/_controlbox.scss b/sass/_controlbox.scss index f860d5624..1737dcf59 100644 --- a/sass/_controlbox.scss +++ b/sass/_controlbox.scss @@ -114,61 +114,78 @@ width: 100%; } } - dl.rooms-list { - margin: 0 1em; - padding: 0; + .rooms-list-container { text-align: left; - dt { - border: none; - color: $text-color; - font-weight: normal; - padding: 0; - padding-bottom: 0.5em; - text-shadow: 0 1px 0 $text-shadow-color; - } - dd.available-chatroom { - border: none; - clear: both; - color: $text-color; + margin: 0 1em; + .rooms-toggle { display: block; - overflow: hidden; - padding: 0.1em; - text-shadow: 0 1px 0 $text-shadow-color; - word-wrap: break-word; - &:hover { - background-color: $highlight-color; + font-weight: bold; + color: $text-color; + margin-top: 1em; + } + dl.rooms-list { + margin: 0.5em 0; + text-align: left; + dt { + border: none; + color: $text-color; + font-weight: normal; + padding: 0; + padding-bottom: 0.5em; + text-shadow: 0 1px 0 $text-shadow-color; } - a { - &.room-info { - clear: right; - display: block; - &:before { - font-size: 15px; + dd.available-chatroom { + border: none; + clear: both; + color: $text-color; + display: block; + overflow: hidden; + padding: 0.3em 0; + text-shadow: 0 1px 0 $text-shadow-color; + word-wrap: break-word; + &:hover { + background-color: $highlight-color; + } + a { + &.room-info { + &:before { + font-size: 15px; + } + } + &.open-room { + float: left; + width: 68%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + padding-right: 0.5em; } } - &.open-room { - float: left; - width: 85%; + .remove-bookmark { + &.button-on { + color: $link-color; + } + color: $subdued-color; + } + .room-info { + font-size: $font-size-small; + font-style: normal; + font-weight: normal; + } + li.room-info { + display: block; + margin-left: 5px; + } + p.room-info { + margin: 0; + padding: 0; + display: block; + white-space: normal; + } + div.room-info { + clear: left; + width: 100%; } - } - .room-info { - font-size: $font-size-small; - font-style: normal; - font-weight: normal; - } - li.room-info { - display: block; - margin-left: 5px; - } - p.room-info { - margin: 0; - padding: 0; - display: block; - white-space: normal; - } - div.room-info { - clear: left; - width: 100%; } } } diff --git a/sass/_core.scss b/sass/_core.scss index 25bdb2da6..63b740e27 100644 --- a/sass/_core.scss +++ b/sass/_core.scss @@ -170,7 +170,7 @@ form { &.pure-form.converse-form { background: white; - padding: 1em; + padding: 0 1em; legend { color: $text-color; } diff --git a/sass/_fonts.scss b/sass/_fonts.scss index 5573bd130..94d26043d 100644 --- a/sass/_fonts.scss +++ b/sass/_fonts.scss @@ -93,7 +93,7 @@ .icon-quotes-left:before { content: "\e01d"; } .icon-radio-checked:before { content: "\2b26"; } .icon-radio-unchecked:before { content: "\2b25"; } - .icon-remove:before { content: "\e02d"; } + .icon-remove:before { content: "\2715"; } .icon-room-info:before { content: "\e059"; } .icon-sad:before { content: "\2639"; } .icon-save:before { content: "\f0c7"; } diff --git a/sass/_variables.scss b/sass/_variables.scss index 8b170b206..8714bfd3d 100644 --- a/sass/_variables.scss +++ b/sass/_variables.scss @@ -43,7 +43,7 @@ $toolbar-color: #FFF5EE !default; $moderator-color: #D24E2B !default; $online-color: #1A9707 !default; $error-color: #D24E2B !default; -$subdued-color: #A8ABA1 !default; +$subdued-color: #BBB !default; $chatbox-border-radius: 4px !default; $bottom-gutter-height: 35px !default; diff --git a/src/config.js b/src/config.js index d4ddf01bc..c0697616b 100644 --- a/src/config.js +++ b/src/config.js @@ -59,6 +59,7 @@ require.config({ "converse-otr": "src/converse-otr", "converse-ping": "src/converse-ping", "converse-register": "src/converse-register", + "converse-roomslist": "src/converse-roomslist", "converse-rosterview": "src/converse-rosterview", "converse-singleton": "src/converse-singleton", "converse-vcard": "src/converse-vcard", @@ -149,6 +150,7 @@ require.config({ "room_description": "src/templates/room_description", "room_item": "src/templates/room_item", "room_panel": "src/templates/room_panel", + "rooms_list": "src/templates/rooms_list", "roster": "src/templates/roster", "roster_filter": "src/templates/roster_filter", "roster_item": "src/templates/roster_item", diff --git a/src/converse-bookmarks.js b/src/converse-bookmarks.js index 37d50fc03..b4614a2e7 100644 --- a/src/converse-bookmarks.js +++ b/src/converse-bookmarks.js @@ -10,7 +10,7 @@ * in XEP-0048. */ (function (root, factory) { - define([ "utils", + define(["utils", "converse-core", "converse-muc", "tpl!chatroom_bookmark_form", @@ -352,7 +352,7 @@ _converse.BookmarksView = Backbone.View.extend({ tagName: 'div', - className: 'bookmarks-list', + className: 'bookmarks-list, rooms-list-container', events: { 'click .remove-bookmark': 'removeBookmark', 'click .bookmarks-toggle': 'toggleBookmarksList' @@ -378,7 +378,7 @@ this.$el.html(tpl_bookmarks_list({ 'toggle_state': this.list_model.get('toggle-state'), 'desc_bookmarks': __('Click to toggle the bookmarks list'), - 'label_bookmarks': __('Bookmarked Rooms') + 'label_bookmarks': __('Bookmarks') })).hide(); if (this.list_model.get('toggle-state') !== _converse.OPENED) { this.$('.bookmarks').hide(); @@ -470,7 +470,7 @@ }); _converse.emit('bookmarksInitialized'); }; - _converse.on('chatBoxesFetched', initBookmarks); + _converse.on('roomsPanelRendered', initBookmarks); var afterReconnection = function () { if (!_converse.allow_bookmarks) { diff --git a/src/converse-roomslist.js b/src/converse-roomslist.js new file mode 100644 index 000000000..6317b17ad --- /dev/null +++ b/src/converse-roomslist.js @@ -0,0 +1,186 @@ +// Converse.js (A browser based XMPP chat client) +// http://conversejs.org +// +// Copyright (c) 2012-2017, Jan-Carel Brand +// Licensed under the Mozilla Public License (MPLv2) +// +/*global define */ + +/* This is a non-core Converse.js plugin which shows a list of currently open + * rooms in the "Rooms Panel" of the ControlBox. + */ +(function (root, factory) { + define(["utils", + "converse-core", + "converse-muc", + "tpl!bookmark", + "tpl!rooms_list" + ], factory); +}(this, function (utils, converse, muc, tpl_bookmark, tpl_rooms_list) { + var $ = converse.env.jQuery, + Backbone = converse.env.Backbone, + b64_sha1 = converse.env.b64_sha1, + sizzle = converse.env.sizzle, + _ = converse.env._; + + converse.plugins.add('converse-roomslist', { + initialize: function () { + /* The initialize function gets called as soon as the plugin is + * loaded by converse.js's plugin machinery. + */ + var _converse = this._converse, + __ = _converse.__, + ___ = _converse.___; + + _converse.RoomsList = Backbone.Model.extend({ + defaults: { + "toggle-state": _converse.OPENED + }, + + initialize: function () { + } + }); + + _converse.RoomsListView = Backbone.View.extend({ + tagName: 'div', + className: 'open-rooms-list, rooms-list-container', + events: { + 'click .close-room': 'closeRoom', + 'click .open-rooms-toggle': 'toggleRoomsList' + }, + + initialize: function () { + this.model.on('add', this.renderRoomsListElement, this); + this.model.on('change:bookmarked', this.renderRoomsListElement, this); + this.model.on('change:name', this.renderRoomsListElement, this); + this.model.on('remove', this.removeRoomsListElement, this); + + var cachekey = 'converse.roomslist'+_converse.bare_jid; + this.list_model = new _converse.RoomsList(); + this.list_model.id = cachekey; + this.list_model.browserStorage = new Backbone.BrowserStorage[_converse.storage]( + b64_sha1(cachekey) + ); + this.list_model.fetch(); + this.render(); + }, + + render: function () { + this.el.innerHTML = + tpl_rooms_list({ + 'toggle_state': this.list_model.get('toggle-state'), + 'desc_rooms': __('Click to toggle the rooms list'), + 'label_rooms': __('Open Rooms') + }) + this.hide(); + if (this.list_model.get('toggle-state') !== _converse.OPENED) { + this.$('.open-rooms-list').hide(); + } + this.model.each(this.renderRoomsListElement.bind(this)); + var controlboxview = _converse.chatboxviews.get('controlbox'); + + if (!_.isUndefined(controlboxview) && + !document.body.contains(this.el)) { + var container = controlboxview.el.querySelector('#chatrooms'); + if (!_.isNull(container)) { + container.insertBefore(this.el, container.firstChild); + } + } + return this.el; + }, + + hide: function () { + this.el.classList.add('hidden'); + }, + + show: function () { + this.el.classList.remove('hidden'); + }, + + closeRoom: function (ev) { + ev.preventDefault(); + var name = $(ev.target).data('roomName'); + var jid = $(ev.target).data('roomJid'); + if (confirm(__(___("Are you sure you want to leave the room \"%1$s\"?"), name))) { + _converse.chatboxviews.get(jid).leave(); + } + }, + + renderRoomsListElement: function (item) { + if (item.get('type') !== 'chatroom') { + return; + } + this.removeRoomsListElement(item); + + var name, bookmark + if (item.get('bookmarked')) { + bookmark = _.head(_converse.bookmarksview.model.where({'jid': item.get('jid')})); + name = bookmark.get('name'); + } else { + name = item.get('name'); + } + var div = document.createElement('div'); + div.innerHTML = tpl_bookmark(_.extend(item.toJSON(), { + 'can_leave_room': true, + 'info_leave_room': __('Leave this room'), + 'info_remove_bookmark': __('Unbookmark this room'), + 'info_title': __('Show more information on this room'), + 'name': name, + 'open_title': __('Click to open this room') + })); + this.el.querySelector('.open-rooms-list').appendChild(div.firstChild); + this.show(); + }, + + removeRoomsListElement: function (item) { + var list_el = this.el.querySelector('.open-rooms-list'); + var el = _.head(sizzle('.available-chatroom[data-room-jid="'+item.get('jid')+'"]', list_el)); + if (el) { + list_el.removeChild(el); + } + if (list_el.childElementCount === 0) { + this.hide(); + } + }, + + toggleRoomsList: function (ev) { + if (ev && ev.preventDefault) { ev.preventDefault(); } + var el = ev.target; + if (el.classList.contains("icon-opened")) { + this.$('.open-rooms-list').slideUp('fast'); + this.list_model.save({'toggle-state': _converse.CLOSED}); + el.classList.remove("icon-opened"); + el.classList.add("icon-closed"); + } else { + el.classList.remove("icon-closed"); + el.classList.add("icon-opened"); + this.$('.open-rooms-list').slideDown('fast'); + this.list_model.save({'toggle-state': _converse.OPENED}); + } + } + }); + + var initRoomsListView = function () { + _converse.rooms_list_view = new _converse.RoomsListView( + {'model': _converse.chatboxes} + ); + }; + _converse.on('bookmarksInitialized', initRoomsListView); + _converse.on('roomsPanelRendered', function () { + if (_converse.allow_bookmarks) { + return; + } + initRoomsListView(); + }); + + var afterReconnection = function () { + if (_.isUndefined(_converse.rooms_list_view)) { + initRoomsListView(); + } else { + _converse.rooms_list_view.render(); + } + }; + _converse.on('reconnected', afterReconnection); + } + }); +})); diff --git a/src/converse.js b/src/converse.js index 2693e0d4c..91bb88c8f 100755 --- a/src/converse.js +++ b/src/converse.js @@ -14,6 +14,7 @@ if (typeof define !== 'undefined') { "converse-chatview", // Renders standalone chat boxes for single user chat "converse-controlbox", // The control box "converse-bookmarks", // XEP-0048 Bookmarks + "converse-roomslist", // XEP-0048 Bookmarks "converse-mam", // XEP-0313 Message Archive Management "converse-muc", // XEP-0045 Multi-user chat "converse-vcard", // XEP-0054 VCard-temp diff --git a/src/templates/bookmark.html b/src/templates/bookmark.html index b6ee7e32c..6db4b7f20 100644 --- a/src/templates/bookmark.html +++ b/src/templates/bookmark.html @@ -1,7 +1,7 @@
{{{name}}} {[ if (can_leave_room) { ]} -  {[ } ]} {{{label_bookmarks}}} +{{{label_bookmarks}}}
diff --git a/src/templates/room_panel.html b/src/templates/room_panel.html index 5ef117745..fa558a747 100644 --- a/src/templates/room_panel.html +++ b/src/templates/room_panel.html @@ -10,4 +10,6 @@ -
+
+
+
diff --git a/src/templates/rooms_list.html b/src/templates/rooms_list.html new file mode 100644 index 000000000..6d1998d18 --- /dev/null +++ b/src/templates/rooms_list.html @@ -0,0 +1,2 @@ +{{{label_rooms}}} +