diff options
author | Houssam Haidar <houssam@sdelements.com> | 2015-04-10 16:21:35 -0400 |
---|---|---|
committer | Houssam Haidar <houssam@sdelements.com> | 2015-04-10 16:21:35 -0400 |
commit | ae774d5234e04e77ca14938674346e23c19ee7c9 (patch) | |
tree | 44724a77341e24aad9e71d1c3de2a9b7ef368390 | |
parent | 2a58299b7884ad340ad037cec9f2ca4d7649fc75 (diff) | |
parent | 5515052dd7571f0db8492a4c1caf015a5caaef3e (diff) | |
download | lets-chat-origin/marionette.zip lets-chat-origin/marionette.tar.gz lets-chat-origin/marionette.tar.bz2 |
Merge branch 'marionette' of github.com:sdelements/lets-chat into marionetteorigin/marionette
Conflicts:
templates/chat.html
-rw-r--r-- | media/js/chat.js | 1 | ||||
-rw-r--r-- | media/js/client.js | 36 | ||||
-rw-r--r-- | media/js/common.js | 18 | ||||
-rw-r--r-- | media/js/models.js | 83 | ||||
-rw-r--r-- | media/js/views/browser.js | 180 | ||||
-rw-r--r-- | media/js/views/client.js | 133 | ||||
-rw-r--r-- | media/js/views/menu.js | 34 | ||||
-rw-r--r-- | media/js/views/modals.js | 1 | ||||
-rw-r--r-- | media/js/views/panes.js | 264 | ||||
-rw-r--r-- | media/js/views/room.js | 91 | ||||
-rw-r--r-- | media/js/views/status.js | 26 | ||||
-rw-r--r-- | media/js/views/upload.js | 18 | ||||
-rw-r--r-- | media/js/views/window.js | 116 | ||||
-rw-r--r-- | media/less/style/chat/tabs.less | 2 | ||||
-rw-r--r-- | templates/chat.html | 21 | ||||
-rw-r--r-- | templates/includes/js/browser-item-user.html | 4 | ||||
-rw-r--r-- | templates/includes/js/browser-item.html | 38 | ||||
-rw-r--r-- | templates/includes/js/browser.html | 17 | ||||
-rw-r--r-- | templates/includes/js/chat.html | 28 | ||||
-rw-r--r-- | templates/includes/js/menu.html | 41 | ||||
-rw-r--r-- | templates/includes/js/room.html | 171 | ||||
-rw-r--r-- | templates/includes/js/status.html | 11 | ||||
-rw-r--r-- | templates/includes/js/tab.html | 16 | ||||
-rw-r--r-- | templates/includes/js/tabs.html | 7 |
24 files changed, 831 insertions, 526 deletions
diff --git a/media/js/chat.js b/media/js/chat.js index 3c43175..c1c9b24 100644 --- a/media/js/chat.js +++ b/media/js/chat.js @@ -8,6 +8,7 @@ //= require views/panes.js //= require views/modals.js //= require views/upload.js +//= require views/menu.js //= require views/client.js //= require client.js diff --git a/media/js/client.js b/media/js/client.js index 867f078..a8d5901 100644 --- a/media/js/client.js +++ b/media/js/client.js @@ -35,7 +35,18 @@ this.user = new UserModel(); this.users = new UsersCollection(); this.rooms = new RoomsCollection(); + this.tabs = new TabCollection(); this.events = _.extend({}, Backbone.Events); + + this.tabs.add(Tab.roomList()); + + this.rooms.on('change:joined', function(room, joined) { + if (joined) { + return this.tabs.add(Tab.room(room)); + } + this.tabs.remove(room.id); + }, this); + return this; }; // @@ -97,9 +108,8 @@ }; Client.prototype.switchRoom = function(id) { // Make sure we have a last known room ID - this.rooms.last.set('id', this.rooms.current.get('id')); if (!id || id === 'list') { - this.rooms.current.set('id', 'list'); + this.tabs.selectTab('list'); this.router.navigate('!/', { replace: true }); @@ -107,7 +117,7 @@ } var room = this.rooms.get(id); if (room && room.get('joined')) { - this.rooms.current.set('id', id); + this.tabs.selectTab(id); this.router.navigate('!/room/' + room.id, { replace: true }); @@ -268,10 +278,7 @@ } } this.socket.emit('rooms:leave', id); - if (id === this.rooms.current.get('id')) { - var room = this.rooms.get(this.rooms.last.get('id')); - this.switchRoom(room && room.get('joined') ? room.id : ''); - } + // Remove room id from localstorage RoomStore.remove(id); }; @@ -298,7 +305,7 @@ var lastMessageOwner = room.get('lastMessageOwner'); var lastMessagePosted = room.get('lastMessagePosted'); - var msg = new MessageModel(_.extend(message, { + var model = new MessageModel(_.extend(message, { paste: /\n/i.test(message.text), @@ -310,11 +317,11 @@ posted.diff(lastMessagePosted, 'minutes') < 5 })); - room.messages.add(msg); + room.messages.add(model); room.set('lastMessageOwner', message.owner.id); room.set('lastMessagePosted', posted); - room.trigger('messages:new', message); + room.trigger('messages:new', model); }; Client.prototype.addMessages = function(messages, historical) { _.each(messages, function(message) { @@ -559,9 +566,14 @@ this.getReplacements(); this.listen(); this.route(); - this.view = new window.LCB.ClientView({ - client: this + + this.view = new window.LCB.RootView({ + client: this, + childView: window.LCB.ClientView }); + + this.view.render(); + this.passwordModal = new window.LCB.RoomPasswordModalView({ el: $('#lcb-password') }); diff --git a/media/js/common.js b/media/js/common.js index ccdd8ba..ef7d3c0 100644 --- a/media/js/common.js +++ b/media/js/common.js @@ -1,3 +1,21 @@ +Marionette.Renderer.render = function(template, data) { + if (typeof template === 'function') { + return template(data); + } + + var self = Marionette.Renderer.render; + + if (!self.cache) { + self.cache = {}; + } + + if (!self.cache[template]) { + self.cache[template] = Handlebars.compile($(template).html()); + } + + return self.cache[template](data); +}; + // Validator defaults $.validator.setDefaults({ diff --git a/media/js/models.js b/media/js/models.js index ff6fac7..7d83a66 100644 --- a/media/js/models.js +++ b/media/js/models.js @@ -2,6 +2,62 @@ // LCB Models // +var Tab = Backbone.Model.extend({ + defaults: { + id: 'list', + type: 'list', + name: 'Rooms', + model: null + }, + + initialize: function() { + var type = this.get('type'); + + if (type === 'room') { + var room = this.get('model'); + this.set('name', room.get('name')); + room.on('change:name', function(name) { + this.set('name', name); + }, this); + } + } + +}); + +Tab.roomList = function(room) { + return new Tab(); +}; + +Tab.room = function(room) { + return new Tab({ + id: room.id, + type: 'room', + model: room + }); +}; + +var TabCollection = Backbone.Collection.extend({ + model: Tab, + initialize: function() { + this.on('remove', function(model) { + if (model.get('selected')) { + model.set('selected', false); + this.get('list').set('selected', true); + } + }, this); + }, + + selectTab: function(id) { + var tab = this.get(id); + if (tab) { + this.forEach(function(x) { + x.set('selected', false); + }); + tab.set('selected', true); + } + } +}); + var UserModel = Backbone.Model.extend(); var UsersCollection = Backbone.Collection.extend({ @@ -47,7 +103,30 @@ var RoomModel = Backbone.Model.extend({ var RoomsCollection = Backbone.Collection.extend({ model: RoomModel, initialize: function() { - this.current = new Backbone.Model(); - this.last = new Backbone.Model(); + this.on('users:add users:remove', this.sort); + }, + comparator: function(a, b) { + var au = a.users.length, + bu = b.users.length, + aj = a.get('joined'), + bj = b.get('joined'); + + if (aj && bj || !aj && !bj) { + if (au > bu) { + return -1; + } + if (au < bu) { + return 1; + } + } + + if (aj) { + return -1; + } + + if (bj) { + return 1; + } + return 0; } }); diff --git a/media/js/views/browser.js b/media/js/views/browser.js index 6235a59..0e47852 100644 --- a/media/js/views/browser.js +++ b/media/js/views/browser.js @@ -9,101 +9,120 @@ window.LCB = window.LCB || {}; - window.LCB.BrowserView = Backbone.View.extend({ + var BrowserItemUser = Marionette.ItemView.extend({ + tagName: 'li', + template:'#template-room-browser-item-user', + attributes: function() { + return { + 'class': 'lcb-rooms-list-user', + 'data-id': this.model.get('id'), + 'title': this.model.get('displayName') + }; + } + }); + + var BrowserItem = Marionette.CompositeView.extend({ + tagName: 'li', + template: '#template-room-browser-item', + attributes: function() { + return { + 'class': 'lcb-rooms-list-item', + 'data-id': this.model.get('id') + }; + }, + events: { - 'submit .lcb-rooms-add': 'create', - 'keyup .lcb-rooms-browser-filter-input': 'filter', 'change .lcb-rooms-switch': 'toggle', 'click .lcb-rooms-switch-label': 'toggle' }, - initialize: function(options) { - this.client = options.client; - this.template = Handlebars.compile($('#template-room-browser-item').html()); - this.userTemplate = Handlebars.compile($('#template-room-browser-item-user').html()); - this.rooms = options.rooms; - this.rooms.on('add', this.add, this); - this.rooms.on('remove', this.remove, this); - this.rooms.on('change:description change:name', this.update, this); - this.rooms.on('change:lastActive', _.debounce(this.updateLastActive, 200), this); - this.rooms.on('change:joined', this.updateToggles, this); - this.rooms.on('users:add', this.addUser, this); - this.rooms.on('users:remove', this.removeUser, this); - this.rooms.on('users:add users:remove add remove', this.sort, this); - this.rooms.current.on('change:id', function(current, id) { - // We only care about the list pane - if (id !== 'list') return; - this.sort(); - }, this); + + childView: BrowserItemUser, + childViewContainer: 'ul', + onRender: function() { + this.update(); + this.model.on('change', this.update, this); }, - updateToggles: function(room, joined) { - this.$('.lcb-rooms-switch[data-id=' + room.id + ']').prop('checked', joined); + update: function() { + var room = this.model; + this.$('.lcb-rooms-list-item-name') + .text(room.get('name')); + this.$('.lcb-rooms-list-item-description') + .text(room.get('description')); + this.$('.lcb-rooms-list-item-last-active .value') + .text(moment(room.get('lastActive')).calendar()); + this.$('.lcb-rooms-switch').prop('checked', room.get('joined')); }, toggle: function(e) { e.preventDefault(); - var $target = $(e.currentTarget), - $input = $target.is(':checkbox') && $target || $target.siblings('[type="checkbox"]'), - id = $input.data('id'), - room = this.rooms.get(id); - if (!room) { - return; - } - - if (room.get('joined')) { - this.client.leaveRoom(room.id); + if (this.model.get('joined')) { + window.client.leaveRoom(this.model.id); } else { - this.client.joinRoom(room); + window.client.joinRoom(this.model); } + } + }); + + window.LCB.BrowserView = Marionette.CompositeView.extend({ + tagName: 'div', + template: '#template-room-browser', + + attributes: function() { + return { + 'class': 'lcb-rooms-browser lcb-pane', + 'data-id': 'list' + }; }, - add: function(room) { - var room = room.toJSON ? room.toJSON() : room, - context = _.extend(room, { - lastActive: moment(room.lastActive).calendar() - }); - this.$('.lcb-rooms-list').append(this.template(context)); - }, - remove: function(room) { - this.$('.lcb-rooms-list-item[data-id=' + room.id + ']').remove(); + + events: { + 'submit .lcb-rooms-add': 'create', + 'keyup .lcb-rooms-browser-filter-input': 'search' }, - update: function(room) { - this.$('.lcb-rooms-list-item[data-id=' + room.id + '] .lcb-rooms-list-item-name').text(room.get('name')); - this.$('.lcb-rooms-list-item[data-id=' + room.id + '] .lcb-rooms-list-item-description').text(room.get('description')); + + ui: { + filter: '.lcb-rooms-browser-filter-input' }, - updateLastActive: function(room) { - this.$('.lcb-rooms-list-item[data-id=' + room.id + '] .lcb-rooms-list-item-last-active .value').text(moment(room.get('lastActive')).calendar()); + + childView: BrowserItem, + childViewContainer: 'ul', + + childViewOptions: function(model, index) { + return { + model: model, + collection: model.users + }; }, - sort: function(model) { - var that = this, - $items = this.$('.lcb-rooms-list-item'); - // We only care about other users - if (this.$el.hasClass('hide') && model && model.id === this.client.user.id) - return; - $items.sort(function(a, b){ - var ar = that.rooms.get($(a).data('id')), - br = that.rooms.get($(b).data('id')), - au = ar.users.length, - bu = br.users.length, - aj = ar.get('joined'), - bj = br.get('joined') - if ((aj && bj) || (!aj && !bj)) { - if (au > bu) return -1; - if (au < bu) return 1; + + initialize: function(options) { + options.tab.on('change:selected', function(current, selected) { + if (selected) { + this.$el.show(); + } else { + this.$el.hide(); } - if (aj) return -1; - if (bj) return 1; - return 0; - }); - $items.detach().appendTo(this.$('.lcb-rooms-list')); + }, this); }, - filter: function(e) { + + search: function(e) { e.preventDefault(); - var $input = $(e.currentTarget), - needle = $input.val().toLowerCase(); - this.$('.lcb-rooms-list-item').each(function () { - var haystack = $(this).find('.lcb-rooms-list-item-name').text().toLowerCase(); - $(this).toggle(haystack.indexOf(needle) >= 0); - }); + this._renderChildren(); + }, + + addChild: function (item, ItemView, index) { + var val = this.ui.filter.val(); // ???? + + if (val) { + var needle = val.toLowerCase(); + var haystack = item.get('name').toLowerCase(); + + if (haystack.indexOf(needle) === -1) { + return; + } + } + + Marionette.CollectionView.prototype.addChild.apply(this, arguments); }, + create: function(e) { var that = this; e.preventDefault(); @@ -160,16 +179,7 @@ } this.client.events.trigger('rooms:create', data); - }, - addUser: function(user, room) { - this.$('.lcb-rooms-list-item[data-id="' + room.id + '"]') - .find('.lcb-rooms-list-users').prepend(this.userTemplate(user.toJSON())); - }, - removeUser: function(user, room) { - this.$('.lcb-rooms-list-item[data-id="' + room.id + '"]') - .find('.lcb-rooms-list-user[data-id="' + user.id + '"]').remove(); } - }); }(window, $, _); diff --git a/media/js/views/client.js b/media/js/views/client.js index b14b305..84a122a 100644 --- a/media/js/views/client.js +++ b/media/js/views/client.js @@ -9,99 +9,62 @@ window.LCB = window.LCB || {}; - window.LCB.ClientView = Backbone.View.extend({ - el: '#lcb-client', + window.LCB.ClientView = Marionette.LayoutView.extend({ + + attributes: { + 'id': 'lcb-client', + 'class': 'lcb-client' + }, + + template: '#template-chat', + events: { - 'click .lcb-tab': 'toggleSideBar', + // 'click .lcb-tab': 'toggleSideBar', 'click .lcb-header-toggle': 'toggleSideBar' }, - initialize: function(options) { - this.client = options.client; - // - // Subviews - // - this.browser = new window.LCB.BrowserView({ - el: this.$el.find('.lcb-rooms-browser'), - rooms: this.client.rooms, - client: this.client - }); - this.tabs = new window.LCB.TabsView({ - el: this.$el.find('.lcb-tabs'), - rooms: this.client.rooms, - client: this.client - }); - this.panes = new window.LCB.PanesView({ - el: this.$el.find('.lcb-panes'), - rooms: this.client.rooms, - client: this.client - }); - this.window = new window.LCB.WindowView({ - rooms: this.client.rooms, - client: this.client - }); + + regions: { + status: '.lcb-status-indicators', + menu: '.lcb-menu', + tabs: '.lcb-tabs', + panes: '.lcb-panes', + }, + + onRender: function() { + this.options.client.status.once('change:connected', + this.hideLoadingIndicator, this); + + this.getRegion('status').show(new window.LCB.StatusView({ + client: this.options.client + })); + + this.getRegion('menu').show(new window.LCB.MenuView({ + model: this.options.client.user, + client: this.options.client + })); + + this.getRegion('tabs').show(new window.LCB.TabsView({ + collection: this.options.client.tabs, + client: this.options.client + })); + + this.getRegion('panes').show(new window.LCB.PanesView({ + collection: this.options.client.tabs, + client: this.options.client + })); + this.hotKeys = new window.LCB.HotKeysView({ - rooms: this.client.rooms, - client: this.client + rooms: this.options.client.rooms, + client: this.options.client }); - this.status = new window.LCB.StatusView({ - el: this.$el.find('.lcb-status-indicators'), - client: this.client - }); - this.accountButton = new window.LCB.AccountButtonView({ - el: this.$el.find('.lcb-account-button'), - model: this.client.user - }); - this.desktopNotifications = new window.LCB.DesktopNotificationsView({ - rooms: this.client.rooms, - client: this.client - }); - if (this.client.options.filesEnabled) { - this.upload = new window.LCB.UploadView({ - el: this.$el.find('#lcb-upload'), - rooms: this.client.rooms - }); - } - - // - // Modals - // - this.profileModal = new window.LCB.ProfileModalView({ - el: this.$el.find('#lcb-profile'), - model: this.client.user - }); - this.accountModal = new window.LCB.AccountModalView({ - el: this.$el.find('#lcb-account'), - model: this.client.user - }); - this.tokenModal = new window.LCB.AuthTokensModalView({ - el: this.$el.find('#lcb-tokens') - }); - this.notificationsModal = new window.LCB.NotificationsModalView({ - el: this.$el.find('#lcb-notifications') - }); - this.giphyModal = new window.LCB.GiphyModalView({ - el: this.$el.find('#lcb-giphy') - }); - // - // Misc - // - this.client.status.once('change:connected', _.bind(function(status, connected) { - this.$el.find('.lcb-client-loading').hide(connected); - }, this)); - return this; }, - toggleSideBar: function(e) { - this.$el.toggleClass('lcb-sidebar-opened'); - } - }); - window.LCB.AccountButtonView = Backbone.View.extend({ - initialize: function() { - this.model.on('change', this.update, this); + hideLoadingIndicator: function(status, connected) { + this.$el.find('.lcb-client-loading').hide(connected); }, - update: function(user){ - this.$('.lcb-account-button-username').text('@' + user.get('username')); - this.$('.lcb-account-button-name').text(user.get('displayName')); + + toggleSideBar: function(e) { + this.$el.toggleClass('lcb-sidebar-opened'); } }); diff --git a/media/js/views/menu.js b/media/js/views/menu.js new file mode 100644 index 0000000..7e38c17 --- /dev/null +++ b/media/js/views/menu.js @@ -0,0 +1,34 @@ +/* + * CLIENT VIEW + * The king of all views. + */ + +'use strict'; + ++function(window, $, _) { + + window.LCB = window.LCB || {}; + + window.LCB.MenuView = Marionette.ItemView.extend({ + tagName: 'div', + + attributes: { + 'class': 'lcb-menu-inner' + }, + + template: '#template-menu', + + onRender: function() { + this.model.on('change', this.update, this); + }, + + update: function(user){ + this.$('.lcb-account-button-username') + .text('@' + user.get('username')); + this.$('.lcb-account-button-name') + .text(user.get('displayName')); + } + }); + + +}(window, $, _); diff --git a/media/js/views/modals.js b/media/js/views/modals.js index a6d1c41..1bd48a2 100644 --- a/media/js/views/modals.js +++ b/media/js/views/modals.js @@ -221,7 +221,6 @@ } }, loadGifs: _.throttle(function() { - console.log(1) var that = this; var search = this.$el.find('.search-giphy').val(); diff --git a/media/js/views/panes.js b/media/js/views/panes.js index 78d5cc0..9104c48 100644 --- a/media/js/views/panes.js +++ b/media/js/views/panes.js @@ -8,149 +8,175 @@ window.LCB = window.LCB || {}; - window.LCB.TabsView = Backbone.View.extend({ - events: { - 'click .lcb-tab-close': 'leave' + var TabView = Marionette.ItemView.extend({ + tagName: 'li', + + template: function() { return ''; }, + + attributes: function() { + var opts = { + 'class': 'lcb-tab', + 'data-id': this.model.id, + + }; + + if (this.model.get('selected')) { + opts.class += ' selected'; + } + + return opts; }, - focus: true, - initialize: function(options) { - this.client = options.client; - this.template = Handlebars.compile($('#template-room-tab').html()); - this.rooms = options.rooms; - // Room joining - this.rooms.on('change:joined', function(room, joined) { - if (joined) { - this.add(room.toJSON()); - return; - } - this.remove(room.id); - }, this); - // Room meta updates - this.rooms.on('change:name change:description', this.update, this); - // Current room switching - this.rooms.current.on('change:id', function(current, id) { - this.switch(id); - this.clearAlerts(id); - }, this); - // Alerts - this.rooms.on('messages:new', this.alert, this); - // Initial switch since router runs before view is loaded - this.switch(this.rooms.current.get('id')); - // Blur/Focus events - $(window).on('focus blur', _.bind(this.onFocusBlur, this)); - this.render(); + + onRender: function() { + this.model.on('change:selected', this.onSelect, this); + this.options.childView.render(); + this.$el.append(this.options.childView.el); }, - add: function(room) { - this.$el.append(this.template(room)); + + onSelect: function(current, selected) { + if (selected) { + this.$el.addClass('selected'); + } else { + this.$el.removeClass('selected'); + } + } + }); + + var ListTabView = Marionette.ItemView.extend({ + tagName: 'a', + + attributes: function() { + return { + 'href': '#!/' + }; }, - remove: function(id) { - this.$el.find('.lcb-tab[data-id=' + id + ']').remove(); + + template: function() { + return '<i class="fa fa-th"></i>'; + } + }); + + var RoomTabView = Marionette.ItemView.extend({ + tagName: 'a', + + attributes: function() { + return { + 'href': '#!/room/' + this.model.id + }; + }, + + template: '#template-room-tab', + + events: { + 'click .lcb-tab-close': 'leave' }, - update: function(room) { - this.$el.find('.lcb-tab[data-id=' + room.id + '] .lcb-tab-title').text(room.get('name')); + + ui: { + newMessages: '.lcb-tab-alerts-total', + newMentions: '.lcb-tab-alerts-mentions' }, - switch: function(id) { - if (!id) { - id = 'list'; - } - this.$el.find('.lcb-tab').removeClass('selected') - .filter('[data-id=' + id + ']').addClass('selected'); + + onRender: function() { + this.model.messages.on('add', this.alert, this); + this.options.tab.on('change:selected', this.removeAlerts, this); + }, + + update: function() { + this.$el.find('.lcb-tab-title').text( + this.model.get('name') + ); }, + leave: function(e) { e.preventDefault(); - var id = $(e.currentTarget).closest('[data-id]').data('id'); - this.client.events.trigger('rooms:leave', id); + this.options.client.events + .trigger('rooms:leave', this.model.get('id')); }, + alert: function(message) { - var $tab = this.$('.lcb-tab[data-id=' + message.room.id + ']'), - $total = $tab.find('.lcb-tab-alerts-total'), - $mentions = $tab.find('.lcb-tab-alerts-mentions'); - if (message.historical || $tab.length === 0 - || ((this.rooms.current.get('id') === message.room.id) && this.focus)) { - // Nothing to do here! + if (message.get('historical') || this.options.tab.get('selected')) { return; } - var total = parseInt($tab.data('count-total')) || 0, - mentions = parseInt($tab.data('count-mentions')) || 0; - // All messages - $tab.data('count-total', ++total); - $total.text(total); - // Just mentions - if (new RegExp('\\B@(' + this.client.user.get('username') + ')(?!@)\\b', 'i').test(message.text)) { - $tab.data('count-mentions', ++mentions); - $mentions.text(mentions); + + var $total = this.ui.newMessages; + var total = parseInt($total.text() || '0') || 0; + $total.text(++total); + + if (!message.get('mentioned')) { + return; } + + var $mentions = this.ui.newMentions; + var mentions = parseInt($mentions.text() || '0') || 0; + $mentions.text(++mentions); }, - clearAlerts: function(id) { - var $tab = this.$('.lcb-tab[data-id=' + id + ']'), - $total = $tab.find('.lcb-tab-alerts-total'), - $mentions = $tab.find('.lcb-tab-alerts-mentions'); - $tab.data('count-total', 0).data('count-mentions', 0); - $total.text(''); - $mentions.text(''); - }, - onFocusBlur: function(e) { - var that = this; - this.focus = (e.type === 'focus'); - clearTimeout(this.clearTimer); - if (this.focus) { - this.clearTimer = setTimeout(function() { - that.clearAlerts(that.rooms.current.get('id')); - }, 9 * 1000); - return; + + removeAlerts: function(tab, selected) { + if (selected) { + this.$el.data('count-total', 0).data('count-mentions', 0); + this.$el.find('.lcb-tab-alerts-total').text(''); + this.$el.find('.lcb-tab-alerts-mentions').text(''); } - that.clearAlerts(that.rooms.current.get('id')); } + }); - window.LCB.PanesView = Backbone.View.extend({ - initialize: function(options) { - this.client = options.client; - this.template = Handlebars.compile($('#template-room').html()); - this.rooms = options.rooms; - this.views = {}; - this.rooms.on('change:joined', function(room, joined) { - if (joined) { - this.add(room); - return; - } - this.remove(room.id); - }, this); - // Switch room - this.rooms.current.on('change:id', function(current, id) { - this.switch(id); - }, this); - // Initial switch since router runs before view is loaded - this.switch(this.rooms.current.get('id')); + window.LCB.TabsView = Marionette.CompositeView.extend({ + + tagName: 'div', + childViewContainer: 'ul', + + template: '#template-tabs', + + buildChildView: function(child, ChildViewClass, childViewOptions) { + return new TabView({ + client: this.options.client, + model: child, + childView: new ChildViewClass(childViewOptions) + }); }, - switch: function(id) { - if (!id) { - id = 'list'; + + getChildView: function(model) { + if (model.get('type') === 'list') { + return ListTabView; } - var $pane = this.$el.find('.lcb-pane[data-id=' + id + ']'); - $pane.removeClass('hide').siblings().addClass('hide'); - $(window).width() > 767 && $pane.find('[autofocus]').focus(); - // this.views[id] && this.views[id].scrollMessages(true); + return RoomTabView; }, - add: function(room) { - if (this.views[room.id]) { - // Nothing to do, this room is already here - return; + + childViewOptions: function(model, index) { + return { + client: this.options.client, + model: model.get('model'), + tab: model + }; + } + }); + + window.LCB.PanesView = Marionette.CollectionView.extend({ + + attributes: { + 'class': 'lcb-panes-inner' + }, + + getChildView: function(model) { + if (model.get('type') === 'list') { + return window.LCB.BrowserView; } - this.views[room.id] = new window.LCB.RoomView({ - client: this.client, - template: this.template, - model: room - }); - this.$el.append(this.views[room.id].$el); + return window.LCB.RoomView; }, - remove: function(id) { - if (!this.views[id]) { - // Nothing to do here - return; + + childViewOptions: function(model, index) { + var opts = { + model: model.get('model'), + tab: model, + client: this.options.client + }; + + if (model.get('type') === 'list') { + opts.collection = this.options.client.rooms; } - this.views[id].destroy(); - delete this.views[id]; + + return opts; } }); diff --git a/media/js/views/room.js b/media/js/views/room.js index 2083702..d9aeb75 100644 --- a/media/js/views/room.js +++ b/media/js/views/room.js @@ -9,9 +9,19 @@ window.LCB = window.LCB || {}; - window.LCB.RoomView = Backbone.View.extend({ + window.LCB.RoomView = Marionette.ItemView.extend({ + + attributes: function() { + return { + 'class': 'lcb-room lcb-pane lcb-pane-' + this.model.id, + 'data-id': this.model.id, + style: 'display: none;' + }; + }, + + template: '#template-room', + events: { - 'DOMCharacterDataModified .lcb-room-heading, .lcb-room-description': 'sendMeta', 'click .lcb-room-toggle-sidebar': 'toggleSidebar', 'click .show-edit-room': 'showEditRoom', 'click .hide-edit-room': 'hideEditRoom', @@ -23,25 +33,32 @@ initialize: function(options) { this.client = options.client; + options.tab.on('change:selected', function(tab, selected) { + if (selected) { + this.$el.show(); + } else { + this.$el.hide(); + } + }, this); + var iAmOwner = this.model.get('owner') === this.client.user.id; var iCanEdit = iAmOwner || !this.model.get('hasPassword'); this.model.set('iAmOwner', iAmOwner); this.model.set('iCanEdit', iCanEdit); - this.template = options.template; - this.render(); - this.model.on('change', this.updateMeta, this); this.model.on('remove', this.goodbye, this); this.model.users.on('change', this.updateUser, this); - - // - // Subviews - // + }, + onRender: function() { + // this.$el = $(this.template(_.extend(this.model.toJSON(), { + // sidebar: store.get('sidebar') + // }))); this.messageView = new window.LCB.MessagesView({ collection: this.model.messages, - el: this.$('.lcb-messages') + el: this.$('.lcb-messages'), + tab: this.options.tab }); this.composeView = new window.LCB.ComposeView({ el: this.$('.lcb-compose'), @@ -64,11 +81,6 @@ this.$('.lcb-room-sidebar').append(this.usersList.el); this.$('.lcb-room-sidebar').append(this.filesList.el); }, - render: function() { - this.$el = $(this.template(_.extend(this.model.toJSON(), { - sidebar: store.get('sidebar') - }))); - }, goodbye: function() { swal('Archived!', '"' + this.model.get('name') + '" has been archived.', 'warning'); }, @@ -77,17 +89,6 @@ this.$('.lcb-room-heading .slug').text('#' + this.model.get('slug')); this.$('.lcb-room-description').text(this.model.get('description')); }, - sendMeta: function(e) { - this.model.set({ - name: this.$('.lcb-room-heading').text(), - description: this.$('.lcb-room-description').text() - }); - this.client.events.trigger('rooms:update', { - id: this.model.id, - name: this.model.get('name'), - description: this.model.get('description') - }); - }, showEditRoom: function(e) { if (e) { e.preventDefault(); @@ -172,7 +173,7 @@ this.$el.siblings('.lcb-room').andSelf().toggleClass('lcb-room-sidebar-opened'); // Save to localstorage if ($(window).width() > 767) { - this.scrollMessages(); + // this.scrollMessages(); store.set('sidebar', this.$el.hasClass('lcb-room-sidebar-opened')); } @@ -208,7 +209,7 @@ }); window.LCB.ComposeView = Marionette.ItemView.extend({ - template: Handlebars.compile($('#template-compose').html()), + template: '#template-compose', tagName: 'form', attributes: { 'class': 'lcb-entry' @@ -384,7 +385,7 @@ }); var MessageView = Marionette.ItemView.extend({ - template: Handlebars.compile($('#template-message').html()), + template: '#template-message', tagName: 'li', attributes: function() { var attrs = { @@ -444,10 +445,15 @@ 'scroll .lcb-messages': 'updateScrollLock', }, + scrollLocked: false, + onRender: function() { - // Scroll Locking - this.scrollLocked = true; this.$el.on('scroll', _.bind(this.updateScrollLock, this)); + this.options.tab.on('change:selected', function(tab, selected) { + if (selected) { + this.scrollMessages(); + } + }, this); }, onAddChild: function(childView) { @@ -456,20 +462,25 @@ updateScrollLock: function() { this.scrollLocked = this.el.scrollHeight - - this.$el.scrollTop() - 5 <= this.$el.outerHeight(); + this.$el.scrollTop() - 5 > this.$el.outerHeight(); return this.scrollLocked; }, - scrollMessages: function(force) { - // if ((!force && !this.scrollLocked) || this.$el.hasClass('hide')) { - // return; - // } + scrollMessages: function() { + if (this.scrollLocked) { + return; + } + + if (!this.options.tab.get('selected')) { + return; + } + this.el.scrollTop = this.el.scrollHeight; } }); var UserView = Marionette.ItemView.extend({ - template: Handlebars.compile($('#template-user').html()), + template: '#template-user', tagName: 'li', attributes: function(model) { return { @@ -480,7 +491,7 @@ }); var FileView = Marionette.ItemView.extend({ - template: Handlebars.compile($('#template-file').html()), + template: '#template-file', tagName: 'li', attributes: function(model) { return { @@ -495,7 +506,7 @@ attributes: { 'class': 'lcb-room-sidebar-group lcb-room-sidebar-users' }, - template: Handlebars.compile($('#template-users').html()), + template: '#template-users', childView: UserView, childViewContainer: 'ul', @@ -515,7 +526,7 @@ attributes: { 'class': 'lcb-room-sidebar-group lcb-room-sidebar-files' }, - template: Handlebars.compile($('#template-files').html()), + template: '#template-files', childView: FileView, childViewContainer: 'ul' }); diff --git a/media/js/views/status.js b/media/js/views/status.js index 0089fe5..ace614d 100644 --- a/media/js/views/status.js +++ b/media/js/views/status.js @@ -9,15 +9,23 @@ window.LCB = window.LCB || {}; - window.LCB.StatusView = Backbone.View.extend({ - initialize: function(options) { - var that = this; - this.client = options.client; - this.client.status.on('change:connected', function(status, connected) { - that.$el.find('[data-status="connected"]').toggle(connected); - that.$el.find('[data-status="disconnected"]').toggle(!connected); - }); + window.LCB.StatusView = Marionette.ItemView.extend({ + + attributes: { + 'class': 'lcb-status-inner' + }, + + template: '#template-status', + + onRender: function () { + this.options.client.status.on('change:connected', + this.update, this); + }, + + update: function(status, connected) { + this.$el.find('[data-status="connected"]').toggle(connected); + this.$el.find('[data-status="disconnected"]').toggle(!connected); } }); -}(window, $, _);
\ No newline at end of file +}(window, $, _); diff --git a/media/js/views/upload.js b/media/js/views/upload.js index 2b9a54c..6743fdc 100644 --- a/media/js/views/upload.js +++ b/media/js/views/upload.js @@ -16,20 +16,22 @@ Dropzone && (Dropzone.autoDiscover = false); 'submit form': 'submit' }, initialize: function(options) { + this.dropZone = options.dropZone; this.template = $('#template-upload').html(); - this.rooms = options.rooms; - this.rooms.current.on('change:id', this.setRoom, this); + this.rooms = options.client.rooms; + this.tabs = options.client.tabs; + this.rooms.on('add remove', this.populateRooms, this); this.rooms.on('change:joined', this.populateRooms, this); this.rooms.on('upload:show', this.show, this); + this.tabs.on('change:selected', this.setRoom, this); this.render(); }, render: function() { // // Dropzone // - var $ele = this.$el.closest('.lcb-client').get(0); - this.dropzone = new Dropzone($ele, { + this.dropzone = new Dropzone(this.dropZone.get(0), { url: './files', autoProcessQueue: false, clickable: [this.$('.lcb-upload-target').get(0)], @@ -91,8 +93,12 @@ Dropzone && (Dropzone.autoDiscover = false); } this.dropzone.processQueue(); }, - setRoom: function() { - this.selectize.setValue(this.rooms.current.id); + setRoom: function(tab, selected) { + if (!selected) { + return; + } + + this.selectize.setValue(tab.id); }, populateRooms: function() { this.selectize.clearOptions(); diff --git a/media/js/views/window.js b/media/js/views/window.js index e6f3c97..6853482 100644 --- a/media/js/views/window.js +++ b/media/js/views/window.js @@ -9,43 +9,78 @@ window.LCB = window.LCB || {}; - window.LCB.WindowView = Backbone.View.extend({ + window.LCB.RootView = Backbone.View.extend({ el: 'html', + focus: true, count: 0, mentions: 0, - initialize: function(options) { - var that = this; + modals: { + + }, + initialize: function(options) { this.client = options.client; - this.rooms = options.rooms; + this.rooms = options.client.rooms; + this.tabs = options.client.tabs; + this.originalTitle = this.$('title').text(); this.title = this.originalTitle; - $(window).on('focus blur', _.bind(this.onFocusBlur, this)); - this.rooms.current.on('change:id', function(current, id) { - var room = this.rooms.get(id), - title = room ? room.get('name') : 'Rooms'; - this.updateTitle(title); - }, this); + var view = new options.childView({ + client: options.client, + el: this.$el.find('#lcb-client') + }); + + view.render(); + + this.initializeModals(options); + + this.notifications = new window.LCB.DesktopNotificationsView({ + rooms: options.client.rooms, + client: options.client + }); - this.rooms.on('change:name', function(room) { - if (room.id !== this.rooms.current.get('id')) { + this.rooms.on('messages:new', this.onNewMessage, this); + + this.tabs.on('change:selected', function(tab, selected) { + if (!selected) { return; } - this.updateTitle(room.get('name')); + this.updateTitle(tab.get('name')); }, this); + }, - this.rooms.on('messages:new', this.onNewMessage, this); + initializeModals: function(options) { + if (options.client.options.filesEnabled) { + this.modals.upload = new window.LCB.UploadView({ + el: this.$el.find('#lcb-upload'), + dropZone: this.$el.find('#lcb-client'), + client: options.client + }); + } - // Last man standing - _.defer(function() { - that.updateTitle(); + this.modals.profile = new window.LCB.ProfileModalView({ + el: this.$el.find('#lcb-profile'), + model: options.client.user + }); + this.modals.account = new window.LCB.AccountModalView({ + el: this.$el.find('#lcb-account'), + model: options.client.user + }); + this.modals.token = new window.LCB.AuthTokensModalView({ + el: this.$el.find('#lcb-tokens') + }); + this.modals.notifications = new window.LCB.NotificationsModalView({ + el: this.$el.find('#lcb-notifications') + }); + this.modals.giphy = new window.LCB.GiphyModalView({ + el: this.$el.find('#lcb-giphy') }); - }, + onFocusBlur: function(e) { this.focus = (e.type === 'focus'); if (this.focus) { @@ -57,19 +92,23 @@ this.updateTitle(); } }, + onNewMessage: function(message) { - if (this.focus || message.historical) { + if (this.focus || message.get('historical')) { return; } + this.countMessage(message); - this.flashTitle() + this.flashTitle(); }, + countMessage: function(message) { - var username = this.client.user.get('username'), - regex = new RegExp('\\B@(' + username + ')(?!@)\\b', 'i'); - ++this.count; - regex.test(message.text) && ++this.mentions; + this.count++; + if (message.get('mentioned')) { + this.mentions++; + } }, + flashTitle: function() { if (!this.titleTimer) { this._flashTitle(); @@ -77,6 +116,7 @@ this.titleTimer = setInterval(flashTitle, 1 * 1000); } }, + _flashTitle: function() { var titlePrefix = ''; if (this.count > 0) { @@ -90,11 +130,8 @@ this.$('title').html(title); this.titleTimerFlip = !this.titleTimerFlip; }, + updateTitle: function(name) { - if (!name) { - var room = this.rooms.get(this.rooms.current.get('id')); - name = (room && room.get('name')) || 'Rooms'; - } if (name) { this.title = $('<pre />').text(name).html() + ' · ' + this.originalTitle; @@ -102,7 +139,7 @@ this.title = this.originalTitle; } this.$('title').html(this.title); - }, + } }); window.LCB.HotKeysView = Backbone.View.extend({ @@ -157,7 +194,7 @@ }); }, onNewMessage: function(message) { - if (this.focus || message.historical) { + if (this.focus || message.get('historical')) { return; } this.createDesktopNotification(message); @@ -171,26 +208,27 @@ return; } - var roomID = message.room.id, - avatar = message.owner.avatar, - icon = 'https://www.gravatar.com/avatar/' + avatar + '?s=50', - title = message.owner.displayName + ' in ' + message.room.name, - mention = message.mentioned; + var owner = message.get('owner'), + room = message.get('room'); + + var icon = 'https://www.gravatar.com/avatar/' + owner.avatar + '?s=50'; + + var title = owner.displayName + ' in ' + room.name; var notification = notify.createNotification(title, { - body: message.text, - icon: icon, + body: message.get('text'), + icon: 'https://www.gravatar.com/avatar/' + owner.avatar + '?s=50', tag: message.id, autoClose: 1000, onclick: function() { window.focus(); - that.client.events.trigger('rooms:switch', roomID); + that.client.events.trigger('rooms:switch', room.id); } }); // // Mentions // - if (mention) { + if (message.get('mentioned')) { if (this.openMentions.length > 2) { this.openMentions[0].close(); this.openMentions.shift(); diff --git a/media/less/style/chat/tabs.less b/media/less/style/chat/tabs.less index c644b2d..28aa89d 100644 --- a/media/less/style/chat/tabs.less +++ b/media/less/style/chat/tabs.less @@ -2,7 +2,7 @@ * Tabs *********************/ -.lcb-tabs, +.lcb-tabs-list, .lab-tab { padding: 0; margin: 0; diff --git a/templates/chat.html b/templates/chat.html index cffb5d4..ed4b5bb 100644 --- a/templates/chat.html +++ b/templates/chat.html @@ -7,6 +7,9 @@ <% endblock %> <% block templates %> + <% include 'includes/js/status.html' %> + <% include 'includes/js/menu.html' %> + <% include 'includes/js/chat.html' %> <% include 'includes/js/room.html' %> <% include 'includes/js/compose.html' %> <% include 'includes/js/user.html' %> @@ -14,7 +17,9 @@ <% include 'includes/js/file.html' %> <% include 'includes/js/files.html' %> <% include 'includes/js/message.html' %> + <% include 'includes/js/tabs.html' %> <% include 'includes/js/tab.html' %> + <% include 'includes/js/browser.html' %> <% include 'includes/js/browser-item.html' %> <% include 'includes/js/browser-item-user.html' %> <% include 'includes/js/upload.html' %> @@ -114,12 +119,14 @@ <div class="lcb-loading lcb-client-loading"> <img class="lcb-loading-indicator" src="./media/img/loading.svg" alt="Loading..." /> </div> - <% include 'includes/modals/notifications.html' %> - <% include 'includes/modals/profile.html' %> - <% include 'includes/modals/account.html' %> - <% include 'includes/modals/xmpp.html' %> - <% include 'includes/modals/tokens.html' %> - <% include 'includes/modals/upload.html' %> - <% include 'includes/modals/giphy.html' %> </div><!-- lcb-client end --> + <% include 'includes/modals/add-room.html' %> + <% include 'includes/modals/password.html' %> + <% include 'includes/modals/notifications.html' %> + <% include 'includes/modals/profile.html' %> + <% include 'includes/modals/account.html' %> + <% include 'includes/modals/xmpp.html' %> + <% include 'includes/modals/tokens.html' %> + <% include 'includes/modals/upload.html' %> + <% include 'includes/modals/giphy.html' %> <% endblock %> diff --git a/templates/includes/js/browser-item-user.html b/templates/includes/js/browser-item-user.html index c7b87ff..a4a77a3 100644 --- a/templates/includes/js/browser-item-user.html +++ b/templates/includes/js/browser-item-user.html @@ -1,5 +1,3 @@ <script type="text/x-handlebars-template" id="template-room-browser-item-user"> - <li class="lcb-rooms-list-user" data-id="{{id}}" title="{{displayName}}"> - <img class="lcb-rooms-list-user-avatar" src="https://www.gravatar.com/avatar/{{avatar}}?s=50" alt="{{displayName}}" /> - </li> + <img class="lcb-rooms-list-user-avatar" src="https://www.gravatar.com/avatar/{{avatar}}?s=50" alt="{{displayName}}" /> </script> diff --git a/templates/includes/js/browser-item.html b/templates/includes/js/browser-item.html index 6c6ba2b..bcb20ac 100644 --- a/templates/includes/js/browser-item.html +++ b/templates/includes/js/browser-item.html @@ -1,22 +1,20 @@ <script type="text/x-handlebars-template" id="template-room-browser-item"> - <li class="lcb-rooms-list-item" data-id="{{id}}"> - <div class="lcb-rooms-list-item-top"> - {{#if hasPassword}} - <span class="lcb-rooms-list-item-password fa fa-lock"></span> - <a class="lcb-rooms-list-item-name" href="#!/room/{{id}}">{{name}}</a> - {{else}} - <a class="lcb-rooms-list-item-name" href="#!/room/{{id}}">{{name}}</a> - {{/if}} - <span class="lcb-rooms-list-item-slug">#{{slug}}</span> - </div> - <div class="lcb-rooms-list-item-description">{{description}}</div> - <ul class="lcb-rooms-list-users"></ul> - <div class="lcb-rooms-list-item-switch onoffswitch"> - <input type="checkbox" class="switch lcb-rooms-switch" id="room-switch-{{id}}" data-id="{{id}}" /> - <label class="switch lcb-rooms-switch-label" for="room-switch-{{id}}"></label> - </div> - <div class="lcb-rooms-list-item-last-active"> - <i class="fa fa-clock-o"></i> <span class="value">{{lastActive}}</span> - </div> - </li> + <div class="lcb-rooms-list-item-top"> + {{#if hasPassword}} + <span class="lcb-rooms-list-item-password fa fa-lock"></span> + <a class="lcb-rooms-list-item-name" href="#!/room/{{id}}">{{name}}</a> + {{else}} + <a class="lcb-rooms-list-item-name" href="#!/room/{{id}}">{{name}}</a> + {{/if}} + <span class="lcb-rooms-list-item-slug">#{{slug}}</span> + </div> + <div class="lcb-rooms-list-item-description">{{description}}</div> + <ul class="lcb-rooms-list-users"></ul> + <div class="lcb-rooms-list-item-switch onoffswitch"> + <input type="checkbox" class="switch lcb-rooms-switch" id="room-switch-{{id}}" data-id="{{id}}" /> + <label class="switch lcb-rooms-switch-label" for="room-switch-{{id}}"></label> + </div> + <div class="lcb-rooms-list-item-last-active"> + <i class="fa fa-clock-o"></i> <span class="value">{{lastActive}}</span> + </div> </script> diff --git a/templates/includes/js/browser.html b/templates/includes/js/browser.html new file mode 100644 index 0000000..5a138bb --- /dev/null +++ b/templates/includes/js/browser.html @@ -0,0 +1,17 @@ +<script type="text/x-handlebars-template" id="template-room-browser"> + <header class="lcb-rooms-browser-header"> + <h2 class="lcb-rooms-browser-heading"> + All Rooms + </h2> + <div class="lcb-rooms-browser-filter"> + <label class="lcb-rooms-browser-filter-label" for="lcb-rooms-browser-filter-input"> + <i class="fa fa-search"></i> + </label> + <input id="lcb-rooms-browser-filter-input" class="lcb-rooms-browser-filter-input" type="search" autofocus /> + </div> + <a class="btn btn-success lcb-rooms-browser-new" data-toggle="modal" data-target="#lcb-add-room" href="#!/rooms/add"> + <i class="fa fa-plus"></i> + </a> + </header> + <ul class="lcb-rooms-list"></ul> +</script> diff --git a/templates/includes/js/chat.html b/templates/includes/js/chat.html new file mode 100644 index 0000000..8bcddce --- /dev/null +++ b/templates/includes/js/chat.html @@ -0,0 +1,28 @@ +<script type="text/x-handlebars-template" id="template-chat"> + <div class="lcb-header"> + <button type="button" class="btn lcb-header-toggle"> + <i class="fa fa-bars"></i> + </button> + <div class="lcb-header-logo">Let's Chat</div> + </div> + <section class="lcb-sidebar"> + <div class="lcb-menu"></div> + <div class="lcb-status-indicators"> + <span class="lcb-status-indicator lcb-status-indicator-error lcb-status-connection" data-status="disconnected" style="display: none;"> + <i class="fa fa-plug"></i> Disconnected + </span> + <span class="lcb-status-indicator lcb-status-connection" data-status="connected" style="display: none;"> + <i class="fa fa-refresh"></i> Connected + </span> + <span class="lcb-status-indicator lcb-status-connection" style="display: none;"> + <i class="fa fa-bell-slash"></i> + </span> + </div> + <div class="lcb-tabs"> + </div> + </section> + <section class="lcb-panes"></section> + <div class="lcb-loading lcb-client-loading"> + <img class="lcb-loading-indicator" src="./media/img/loading.svg" alt="Loading..." /> + </div> +</script> diff --git a/templates/includes/js/menu.html b/templates/includes/js/menu.html new file mode 100644 index 0000000..8281b9d --- /dev/null +++ b/templates/includes/js/menu.html @@ -0,0 +1,41 @@ +<script type="text/x-handlebars-template" id="template-menu"> + <div class="dropdown"> + <a class="lcb-account-button dropdown-toggle" data-toggle="dropdown" href="3"> + <img class="lcb-account-button-avatar lcb-avatar" src="https://www.gravatar.com/avatar/<$ account.avatar $>?s=50" /> + <span class="lcb-account-button-name"><$ account.displayName $></span> + <span class="lcb-account-button-username">@<$ account.username $></span> + <i class="lcb-account-button-chevron fa fa-chevron-down"></i> + </a> + <ul class="dropdown-menu dropdown-menu-right"> + <li> + <a data-toggle="modal" href="#lcb-profile"> + <i class="fa fa-fw fa-edit"></i> Edit Profile + </a> + </li> + <li> + <a data-toggle="modal" href="#lcb-account"> + <i class="fa fa-fw fa-cogs"></i> Account Settings + </a> + </li> + <li> + <a data-toggle="modal" href="#lcb-notifications"> + <i class="fa fa-fw fa-bell"></i> Notifications + </a> + </li> + <% if settings.xmpp.enable %> + <li> + <a data-toggle="modal" href="#lcb-xmpp"> + <i class="fa fa-fw fa-comments"></i> XMPP/Jabber + </a> + </li> + <% endif %> + <li> + <a data-toggle="modal" href="#lcb-tokens"> + <i class="fa fa-fw fa-lock"></i> Auth tokens + </a> + </li> + <li class="divider"></li> + <li><a href="./logout"><i class="fa fa-fw fa-sign-out"></i> Logout</a></li> + </ul> + </div> +</script> diff --git a/templates/includes/js/room.html b/templates/includes/js/room.html index 6782ac2..a5564da 100644 --- a/templates/includes/js/room.html +++ b/templates/includes/js/room.html @@ -1,103 +1,100 @@ <script type="text/x-handlebars-template" id="template-room"> - <div class="lcb-room lcb-pane lcb-pane-{{id}} {{#if sidebar}}lcb-room-sidebar-opened{{/if}} hide" data-id="{{id}}"> - <div class="lcb-room-chat "> - <div class="lcb-room-header"> - <div class="lcb-room-meta"> - <h2 class="lcb-room-heading"> - <span class="name">{{name}}</span> - <span class="slug">#{{slug}}</span> - {{#if hasPassword}} - <span class="fa fa-lock btn password" title="This room require password to enter."></span> - {{/if}} - {{#if iCanEdit}} - <a class="btn hidden-xs show-edit-room" - title="Edit Room"> - <i class="fa fa-edit"></i> - </a> - {{/if}} - <a class="btn hidden-xs" title="Chat History" - href="./transcript?room={{ id }}" target="_blank"> - <i class="fa fa-history"></i> + <div class="lcb-room-chat "> + <div class="lcb-room-header"> + <div class="lcb-room-meta"> + <h2 class="lcb-room-heading"> + <span class="name">{{name}}</span> + <span class="slug">#{{slug}}</span> + {{#if hasPassword}} + <span class="fa fa-lock btn password" title="This room require password to enter."></span> + {{/if}} + {{#if iCanEdit}} + <a class="btn hidden-xs show-edit-room" + title="Edit Room"> + <i class="fa fa-edit"></i> </a> - <% if settings.files.enable %> - <a class="btn hidden-xs lcb-upload-trigger" title="Upload Files" href="#"> - <i class="fa fa-upload"></i> - </a> - <% endif %> - <a class="btn hidden-xs lcb-giphy" href="#lcb-giphy" title="Giphy" data-toggle="modal"> - <i class="fa fa-gift"></i> - </a> - </h2> - <div class="lcb-room-description"> - <p>{{description}}</p> - </div> - </div> - <div class="lcb-room-header-actions"> - <a class="lcb-room-toggle-sidebar" href="#"> - <i class="fa fa-chevron-left"></i> + {{/if}} + <a class="btn hidden-xs" title="Chat History" + href="./transcript?room={{ id }}" target="_blank"> + <i class="fa fa-history"></i> + </a> + <% if settings.files.enable %> + <a class="btn hidden-xs lcb-upload-trigger" title="Upload Files" href="#"> + <i class="fa fa-upload"></i> + </a> + <% endif %> + <a class="btn hidden-xs lcb-giphy" href="#lcb-giphy" title="Giphy" data-toggle="modal"> + <i class="fa fa-gift"></i> </a> + </h2> + <div class="lcb-room-description"> + <p>{{description}}</p> </div> - </div><!-- lcb-room-header end --> - <ul class="lcb-messages"> - </ul> - <form class="lcb-compose lcb-entry"> - </form> - </div><!-- lcb-chat end --> - <div class="lcb-room-sidebar"></div> - <div class="edit-room modal fade lcb-room-edit"> - <div class="modal-dialog"> - <div class="modal-content"> - <form action="" class="validate form-horizontal" method="post"> - <div class="modal-header"> - <button class="close hide-edit-room" type="button">×</button> - <h4 class="modal-title">Edit Room</h4> + </div> + <div class="lcb-room-header-actions"> + <a class="lcb-room-toggle-sidebar" href="#"> + <i class="fa fa-chevron-left"></i> + </a> + </div> + </div><!-- lcb-room-header end --> + <ul class="lcb-messages"> + </ul> + <form class="lcb-compose lcb-entry"> + </form> + </div><!-- lcb-chat end --> + <div class="lcb-room-sidebar"></div> + <div class="edit-room modal fade lcb-room-edit"> + <div class="modal-dialog"> + <div class="modal-content"> + <form action="" class="validate form-horizontal" method="post"> + <div class="modal-header"> + <button class="close hide-edit-room" type="button">×</button> + <h4 class="modal-title">Edit Room</h4> + </div> + <div class="modal-body"> + <div class="form-group"> + <label class="control-label col-sm-4">Name</label> + <div class="col-sm-7"> + <input class="required name form-control" name= + "name" type="text" value="{{name}}"> + </div> </div> - <div class="modal-body"> + <div class="form-group"> + <label class= + "control-label col-sm-4">Description</label> + <div class="col-sm-7"> + <textarea class="form-control" name= + "description">{{description}}</textarea> + </div> + </div> + {{#if hasPassword}} <div class="form-group"> - <label class="control-label col-sm-4">Name</label> + <label class= + "control-label col-sm-4">Password</label> <div class="col-sm-7"> - <input class="required name form-control" name= - "name" type="text" value="{{name}}"> + <input class="form-control" name= + "password" type="password" value="{{password}}"> </div> </div> <div class="form-group"> <label class= - "control-label col-sm-4">Description</label> + "control-label col-sm-4">Confirm Password</label> <div class="col-sm-7"> - <textarea class="form-control" name= - "description">{{description}}</textarea> + <input class="form-control" name= + "confirmPassword" type="password" value="{{password}}"> </div> </div> - {{#if hasPassword}} - <div class="form-group"> - <label class= - "control-label col-sm-4">Password</label> - <div class="col-sm-7"> - <input class="form-control" name= - "password" type="password" value="{{password}}"> - </div> - </div> - <div class="form-group"> - <label class= - "control-label col-sm-4">Confirm Password</label> - <div class="col-sm-7"> - <input class="form-control" name= - "confirmPassword" type="password" value="{{password}}"> - </div> - </div> - {{/if}} - <p class="response" style="display: none;"></p> - </div> - <div class="modal-footer"> - <button class="btn btn-success pull-right submit-edit-room" type= - "submit"><i class="icon-ok"></i> Save</button> - <a class="archive-room btn btn-danger pull-left" - tabindex="-1"><i class="icon-remove icon-white"></i> - Archive Room</a> - </div> - </form> - </div> + {{/if}} + <p class="response" style="display: none;"></p> + </div> + <div class="modal-footer"> + <button class="btn btn-success pull-right submit-edit-room" type= + "submit"><i class="icon-ok"></i> Save</button> + <a class="archive-room btn btn-danger pull-left" + tabindex="-1"><i class="icon-remove icon-white"></i> + Archive Room</a> + </div> + </form> </div> - </div><!-- edit room end --> - </div><!-- lcb-room end --> + </div> </script> diff --git a/templates/includes/js/status.html b/templates/includes/js/status.html new file mode 100644 index 0000000..6872029 --- /dev/null +++ b/templates/includes/js/status.html @@ -0,0 +1,11 @@ +<script type="text/x-handlebars-template" id="template-status"> + <span class="lcb-status-indicator lcb-status-indicator-error lcb-status-connection" data-status="disconnected" style="display: none;"> + <i class="fa fa-plug"></i> Disconnected + </span> + <span class="lcb-status-indicator lcb-status-connection" data-status="connected" style="display: none;"> + <i class="fa fa-refresh"></i> Connected + </span> + <span class="lcb-status-indicator lcb-status-connection" style="display: none;"> + <i class="fa fa-bell-slash"></i> + </span> +</script> diff --git a/templates/includes/js/tab.html b/templates/includes/js/tab.html index f8332b5..687bdd0 100644 --- a/templates/includes/js/tab.html +++ b/templates/includes/js/tab.html @@ -1,12 +1,8 @@ <script type="text/x-handlebars-template" id="template-room-tab"> - <li class="lcb-tab lcb-tab-room" data-id="{{id}}"> - <a href="#!/room/{{id}}"> - <span class="lcb-tab-title">{{name}}</span> - <span class="lcb-tab-alerts"> - <span class="lcb-tab-alerts-mentions"></span> - <span class="lcb-tab-alerts-total"></span> - </span> - <span class="lcb-tab-close">×</span> - </a> - </li> + <span class="lcb-tab-title">{{name}}</span> + <span class="lcb-tab-alerts"> + <span class="lcb-tab-alerts-mentions"></span> + <span class="lcb-tab-alerts-total"></span> + </span> + <span class="lcb-tab-close">×</span> </script> diff --git a/templates/includes/js/tabs.html b/templates/includes/js/tabs.html new file mode 100644 index 0000000..44e13c3 --- /dev/null +++ b/templates/includes/js/tabs.html @@ -0,0 +1,7 @@ +<script type="text/x-handlebars-template" id="template-tabs"> + <div class="lcb-tabs-group"> + <h3 class="lcb-tabs-group-heading">Rooms</h3> + <ul class="lcb-tabs-list"> + </ul> + </div> +</script> |