diff --git a/css/style.css b/css/style.css index 55865ec2e..c6e230450 100644 --- a/css/style.css +++ b/css/style.css @@ -20,9 +20,8 @@ } .oca-spreedme-add-person { - width: 225px; - top: 0; - border-bottom: 1px solid #eee; + width: 100%; + border: 1px solid #eee; } /** @@ -89,17 +88,6 @@ height: 32px; } -#oca-spreedme-add-room button { - position: absolute; - background-color: transparent; - border: none; - right: 0; - top: 0; - padding: 23px; - margin: 0; - opacity: .3; -} - .public-room { display: block !important; } @@ -128,7 +116,7 @@ .password-input, .rename-input { - margin-top: 0px !important; + margin-top: 0 !important; margin-bottom: 4px !important; } @@ -409,7 +397,7 @@ video { #video-fullscreen { position: absolute; - right: 0px; + right: 0; z-index: 90; } @@ -754,3 +742,41 @@ video { background-position: center; background-image: url('../../../core/img/actions/more.svg?v=1'); } + +/** + * Sidebar details view + */ + +.detailCallInfoContainer h3 { + max-width: calc(100% - 72px); + display: inline-block; +} + +.detailCallInfoContainer .rename-button { + display: none; +} + +.detailCallInfoContainer .clipboard-button, +.detailCallInfoContainer:hover .rename-button { + display: inline-block; +} + +.detailCallInfoContainer .clipboard-button .icon, +.detailCallInfoContainer .rename-button .icon { + cursor: pointer; + width: 16px; + height: 16px; + margin: -2px 10px; +} + +.detailCallInfoContainer .rename-option, +.detailCallInfoContainer .password-option { + position: relative; + max-width: calc(100% - 72px); + display: inline-block; +} + +.detailCallInfoContainer .rename-input, +.detailCallInfoContainer .password-input { + width: 100%; +} diff --git a/js/app.js b/js/app.js index c18c4c81c..1801c1e25 100644 --- a/js/app.js +++ b/js/app.js @@ -350,10 +350,11 @@ _showParticipantList: function() { this._participants = new OCA.SpreedMe.Models.ParticipantCollection(); this._participantsView = new OCA.SpreedMe.Views.ParticipantView({ + room: this.activeRoom, collection: this._participants }); - this._participants.listenTo(this._rooms, 'change:active', function(model, active) { + this._participantsView.listenTo(this._rooms, 'change:active', function(model, active) { if (active) { this.setRoom(model); } diff --git a/js/views/callinfoview.js b/js/views/callinfoview.js index 8da66d4ae..44be53120 100644 --- a/js/views/callinfoview.js +++ b/js/views/callinfoview.js @@ -21,7 +21,7 @@ * */ -(function(OCA, Marionette, Handlebars) { +(function(OC, OCA, Marionette, Handlebars, $, _) { 'use strict'; @@ -29,27 +29,266 @@ OCA.SpreedMe.Views = OCA.SpreedMe.Views || {}; var TEMPLATE = - '{{displayName}}'; + '

{{displayName}}

' + + '{{#if showShareLink}}' + + '
' + + '{{/if}}' + + '{{#if canModerate}}' + + '
' + + ' '+ + '
'+ + '
' + + '
' + + '{{/if}}' + + '{{#if canModerate}}' + + '
' + + ' ' + + ' ' + + ' {{#if isPublic}}' + + '
' + + '
' + + ' '+ + '
'+ + '
' + + ' {{/if}}' + + '
' + + '{{/if}}'; var CallInfoView = Marionette.View.extend({ - tagName: 'h3', + tagName: 'div', template: Handlebars.compile(TEMPLATE), + + renderTimeout: undefined, + templateContext: function() { - return { - displayName: this.model.get('displayName') - }; + var canModerate = this.model.get('participantType') === 1 || this.model.get('participantType') === 2; + return $.extend(this.model.toJSON(), { + canModerate: canModerate, + isPublic: this.model.get('type') === 3, + showShareLink: !canModerate && this.model.get('type') === 3, + isNameEditable: canModerate && this.model.get('type') !== 1, + isDeletable: canModerate && (Object.keys(this.model.get('participants')).length > 2 || this.model.get('numGuests') > 0) + }); + }, + + ui: { + 'roomName': 'h3.room-name', + 'clipboardButton': '.clipboard-button', + 'linkCheckbox': '.link-checkbox', + + 'renameButton': '.rename-button', + 'renameOption': '.rename-option', + 'renameInput': '.rename-input', + 'renameConfirm': '.rename-confirm', + + 'passwordOption': '.password-option', + 'passwordInput': '.password-input', + 'passwordConfirm': '.password-confirm' + }, + + events: { + 'change @ui.linkCheckbox': 'toggleLinkCheckbox', + + 'click @ui.renameButton': 'showRenameInput', + 'keyup @ui.renameInput': 'keyUpRename', + 'click @ui.renameConfirm': 'confirmRename', + + 'keyup @ui.passwordInput': 'keyUpPassword', + 'click @ui.passwordConfirm': 'confirmPassword' }, modelEvents: { 'change:displayName': function() { + this.renderWhenInactive(); + }, + 'change:hasPassword': function() { + this.renderWhenInactive(); + }, + 'change:participantType': function() { + // User permission change, refresh even when typing, because the + // action will fail in the future anyway. this.render(); }, - } + 'change:type': function() { + this.renderWhenInactive(); + } + }, + renderWhenInactive: function() { + if (!this.ui.renameInput.is(':visible') && + this.ui.passwordInput.val() === '') { + this.render(); + return; + } + + this.renderTimeout = setTimeout(_.bind(this.renderWhenInactive, this), 500); + }, + + onRender: function() { + if (!_.isUndefined(this.renderTimeout)) { + clearTimeout(this.renderTimeout); + this.renderTimeout = undefined; + } + + var roomURL = OC.generateUrl('/call/' + this.model.get('token')), + completeURL = window.location.protocol + '//' + window.location.host + roomURL; + + this.ui.clipboardButton.attr('value', completeURL); + this.ui.clipboardButton.attr('data-clipboard-text', completeURL); + this.ui.clipboardButton.tooltip({ + placement: 'bottom', + trigger: 'hover', + title: t('spreed', 'Copy') + }); + this.initClipboard(); + }, + + /** + * Rename + */ + showRenameInput: function() { + this.ui.renameOption.removeClass('hidden-important'); + this.ui.roomName.addClass('hidden-important'); + this.ui.renameButton.addClass('hidden-important'); + }, + + hideRenameInput: function() { + this.ui.renameOption.addClass('hidden-important'); + this.ui.roomName.removeClass('hidden-important'); + this.ui.renameButton.removeClass('hidden-important'); + }, + + confirmRename: function() { + var newRoomName = this.ui.renameInput.val().trim(); + + if (newRoomName === this.model.get('name')) { + this.hideRenameInput(); + return; + } + + console.log('Changing room name from "' + this.model.get('name') + '" to "' + newRoomName + '".'); + + $.ajax({ + url: OC.linkToOCS('apps/spreed/api/v1/room', 2) + this.model.get('token'), + type: 'PUT', + data: { + roomName: newRoomName + }, + success: function() { + this.ui.roomName.text(newRoomName); + this.hideRenameInput(); + OCA.SpreedMe.app.syncRooms(); + }.bind(this) + }); + + console.log('.rename-option'); + }, + + keyUpRename: function(e) { + if (e.keyCode === 13) { + // Enter + this.confirmRename(); + } else if (e.keyCode === 27) { + // ESC + this.hideRenameInput(); + this.ui.renameInput.val(this.model.get('name')); + } + }, + + /** + * Share link + */ + toggleLinkCheckbox: function() { + var shareLink = this.ui.linkCheckbox.attr('checked') === 'checked'; + + $.ajax({ + url: OC.linkToOCS('apps/spreed/api/v1/room', 2) + this.model.get('token') + '/public', + type: shareLink ? 'POST' : 'DELETE', + success: function() { + OCA.SpreedMe.app.syncRooms(); + } + }); + }, + + /** + * Password + */ + confirmPassword: function() { + var newPassword = this.ui.passwordInput.val().trim(); + + console.log('Setting room password to "' + newPassword + '".'); + console.log('Setting room password to "' + this.model.get('hasPassword') + '".'); + + $.ajax({ + url: OC.linkToOCS('apps/spreed/api/v1/room', 2) + this.model.get('token') + '/password', + type: 'PUT', + data: { + password: newPassword + }, + success: function() { + OCA.SpreedMe.app.syncRooms(); + }.bind(this) + }); + + console.log('.rename-option'); + }, + + keyUpPassword: function(e) { + if (e.keyCode === 13) { + // Enter + this.confirmPassword(); + } else if (e.keyCode === 27) { + // ESC + this.ui.passwordInput.val(''); + } + }, + + /** + * Clipboard + */ + initClipboard: function() { + var clipboard = new Clipboard('.clipboard-button'); + clipboard.on('success', function(e) { + var $input = $(e.trigger); + $input.tooltip('hide') + .attr('data-original-title', t('core', 'Copied!')) + .tooltip('fixTitle') + .tooltip({placement: 'bottom', trigger: 'manual'}) + .tooltip('show'); + _.delay(function() { + $input.tooltip('hide') + .attr('data-original-title', t('core', 'Copy')) + .tooltip('fixTitle'); + }, 3000); + }); + clipboard.on('error', function (e) { + var $input = $(e.trigger); + var actionMsg = ''; + if (/iPhone|iPad/i.test(navigator.userAgent)) { + actionMsg = t('core', 'Not supported!'); + } else if (/Mac/i.test(navigator.userAgent)) { + actionMsg = t('core', 'Press ⌘-C to copy.'); + } else { + actionMsg = t('core', 'Press Ctrl-C to copy.'); + } + + $input.tooltip('hide') + .attr('data-original-title', actionMsg) + .tooltip('fixTitle') + .tooltip({placement: 'bottom', trigger: 'manual'}) + .tooltip('show'); + _.delay(function () { + $input.tooltip('hide') + .attr('data-original-title', t('spreed', 'Copy')) + .tooltip('fixTitle'); + }, 3000); + }); + } }); OCA.SpreedMe.Views.CallInfoView = CallInfoView; -})(OCA, Marionette, Handlebars); +})(OC, OCA, Marionette, Handlebars, $, _); diff --git a/js/views/participantlistview.js b/js/views/participantlistview.js new file mode 100644 index 000000000..22359758e --- /dev/null +++ b/js/views/participantlistview.js @@ -0,0 +1,248 @@ +/* global Marionette, Handlebars */ + +/** + * @author Christoph Wurst + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +(function(OC, OCA, Marionette, Handlebars) { + 'use strict'; + + OCA.SpreedMe = OCA.SpreedMe || {}; + OCA.SpreedMe.Views = OCA.SpreedMe.Views || {}; + + var uiChannel = Backbone.Radio.channel('ui'); + + var ITEM_TEMPLATE = '' + + '' + + '
' + + ' {{name}}' + + '{{#if participantIsOwner}}(' + t('spreed', 'moderator') + '){{/if}}' + + '{{#if participantIsModerator}}(' + t('spreed', 'moderator') + '){{/if}}' + + '
'+ + '{{#if canModerate}}' + + '
'+ + '
    '+ + '
  • '+ + '
'+ + '
'+ + '' + + '{{/if}}'; + + OCA.SpreedMe.Views.ParticipantListView = Marionette.CollectionView.extend({ + tagName: 'ul', + className: 'participantWithList', + collectionEvents: { + 'update': function() { + this.render(); + }, + 'reset': function() { + this.render(); + }, + 'sort': function() { + this.render(); + }, + 'sync': function() { + this.render(); + } + }, + childView: Marionette.View.extend({ + tagName: 'li', + modelEvents: { + 'change:active': function() { + this.render(); + }, + 'change:displayName': function() { + this.render(); + }, + 'change:participants': function() { + this.render(); + }, + 'change:type': function() { + this.render(); + this.checkSharingStatus(); + } + }, + initialize: function() { + this.listenTo(uiChannel, 'document:click', function(event) { + var target = $(event.target); + if (!this.$el.is(target.closest('.participant'))) { + // Click was not triggered by this element -> close menu + this.menuShown = false; + this.toggleMenuClass(); + } + }); + }, + templateContext: function() { + var canModerate = this.model.get('participantType') !== OCA.SpreedMe.app.OWNER && // can not moderate owners + this.model.get('userId') !== oc_current_user && // can not moderate yourself + (OCA.SpreedMe.app.activeRoom.get('participantType') === OCA.SpreedMe.app.OWNER || // current user must be owner + OCA.SpreedMe.app.activeRoom.get('participantType') === OCA.SpreedMe.app.MODERATOR); // or moderator. + + return { + canModerate: canModerate, + name: this.model.get('userId').length ? this.model.get('displayName') : t('spreed', 'Guest'), + participantIsUser: this.model.get('participantType') === OCA.SpreedMe.app.USER, + participantIsModerator: this.model.get('participantType') === OCA.SpreedMe.app.MODERATOR, + participantIsOwner: this.model.get('participantType') === OCA.SpreedMe.app.OWNER + }; + }, + onRender: function() { + this.$el.find('.avatar').each(function() { + var element = $(this); + if (element.data('displayname').length) { + element.avatar(element.data('user-id'), 32, undefined, false, undefined, element.data('displayname')); + } else { + element.imageplaceholder('?', undefined, 32); + element.css('background-color', '#b9b9b9'); + } + }); + + this.$el.attr('data-session-id', this.model.get('sessionId')); + this.$el.attr('data-participant', this.model.get('userId')); + this.$el.addClass('participant'); + + if (!this.model.isOnline()) { + this.$el.addClass('participant-offline'); + } + + this.toggleMenuClass(); + }, + events: { + 'click .participant-entry-utils-menu-button button': 'toggleMenu', + 'click .popovermenu .promote-moderator': 'promoteToModerator', + 'click .popovermenu .demote-moderator': 'demoteFromModerator', + 'click .popovermenu .remove-participant': 'removeParticipant' + }, + ui: { + 'participant': 'li.participant', + 'menu': '.popovermenu' + }, + template: Handlebars.compile(ITEM_TEMPLATE), + menuShown: false, + toggleMenu: function(e) { + e.preventDefault(); + this.menuShown = !this.menuShown; + this.toggleMenuClass(); + }, + toggleMenuClass: function() { + this.ui.menu.toggleClass('open', this.menuShown); + }, + promoteToModerator: function() { + if (this.model.get('participantType') !== OCA.SpreedMe.app.USER) { + return; + } + + var participantId = this.model.get('userId'), + self = this; + + $.ajax({ + type: 'POST', + url: OC.linkToOCS('apps/spreed/api/v1/room', 2) + OCA.SpreedMe.app.activeRoom.get('token') + '/moderators', + data: { + participant: participantId + }, + success: function() { + self.render(); + }, + error: function() { + console.log('Error while promoting user to moderator'); + } + }); + }, + demoteFromModerator: function() { + if (this.model.get('participantType') !== OCA.SpreedMe.app.MODERATOR) { + return; + } + + var participantId = this.model.get('userId'), + self = this; + + $.ajax({ + type: 'DELETE', + url: OC.linkToOCS('apps/spreed/api/v1/room', 2) + OCA.SpreedMe.app.activeRoom.get('token') + '/moderators', + data: { + participant: participantId + }, + success: function() { + self.render(); + }, + error: function() { + console.log('Error while demoting moderator'); + } + }); + }, + removeParticipant: function() { + if (this.model.get('participantType') === OCA.SpreedMe.app.OWNER) { + return; + } + + var self = this, + participantId = this.model.get('userId'), + endpoint = '/participants'; + + if (this.model.get('participantType') === OCA.SpreedMe.app.GUEST) { + participantId = this.model.get('sessionId'); + endpoint += '/guests'; + } + + $.ajax({ + type: 'DELETE', + url: OC.linkToOCS('apps/spreed/api/v1/room', 2) + OCA.SpreedMe.app.activeRoom.get('token') + endpoint, + data: { + participant: participantId + }, + success: function() { + self.render(); + }, + error: function() { + console.log('Error while removing user from room'); + } + }); + } + }) + }); + +})(OC, OCA, Marionette, Handlebars); diff --git a/js/views/participantview.js b/js/views/participantview.js index 5bcd5ce9c..6ed838b4b 100644 --- a/js/views/participantview.js +++ b/js/views/participantview.js @@ -1,7 +1,8 @@ /* global Marionette, Handlebars */ /** - * @author Christoph Wurst + * + * @copyright Copyright (c) 2017, Daniel Calviño Sánchez (danxuliu@gmail.com) * * @license GNU AGPL version 3 or any later version * @@ -20,229 +21,164 @@ * */ - (function(OC, OCA, Marionette, Handlebars) { 'use strict'; OCA.SpreedMe = OCA.SpreedMe || {}; OCA.SpreedMe.Views = OCA.SpreedMe.Views || {}; - var uiChannel = Backbone.Radio.channel('ui'); + var TEMPLATE = ''+ + '
'+ + ' '+ + '
'+ + '
    ' + + '
'; - var ITEM_TEMPLATE = '' + - '' + - '
' + - ' {{name}}' + - '{{#if participantIsOwner}}(' + t('spreed', 'moderator') + '){{/if}}' + - '{{#if participantIsModerator}}(' + t('spreed', 'moderator') + '){{/if}}' + - '
'+ - '{{#if canModerate}}' + - '
'+ - '
    '+ - '
  • '+ - '
'+ - '
'+ - '' + - '{{/if}}'; + OCA.SpreedMe.Views.ParticipantView = Marionette.View.extend({ - OCA.SpreedMe.Views.ParticipantView = Marionette.CollectionView.extend({ - tagName: 'ul', - className: 'participantWithList', - collectionEvents: { - 'update': function() { - this.render(); - }, - 'reset': function() { - this.render(); - }, - 'sort': function() { - this.render(); - }, - 'sync': function() { - this.render(); - } + tagName: 'div', + + ui: { + addParticipantInput: '.add-person-input', + participantList: '.participantWithList' }, - childView: Marionette.View.extend({ - tagName: 'li', - modelEvents: { - 'change:active': function() { - this.render(); - }, - 'change:displayName': function() { - this.render(); - }, - 'change:participants': function() { - this.render(); - }, - 'change:type': function() { - this.render(); - this.checkSharingStatus(); - } - }, - initialize: function() { - this.listenTo(uiChannel, 'document:click', function(event) { - var target = $(event.target); - if (!this.$el.is(target.closest('.participant'))) { - // Click was not triggered by this element -> close menu - this.menuShown = false; - this.toggleMenuClass(); - } - }); - }, - templateContext: function() { - var canModerate = this.model.get('participantType') !== OCA.SpreedMe.app.OWNER && // can not moderate owners - this.model.get('userId') !== oc_current_user && // can not moderate yourself - (OCA.SpreedMe.app.activeRoom.get('participantType') === OCA.SpreedMe.app.OWNER || // current user must be owner - OCA.SpreedMe.app.activeRoom.get('participantType') === OCA.SpreedMe.app.MODERATOR); // or moderator. - return { - canModerate: canModerate, - name: this.model.get('userId').length ? this.model.get('displayName') : t('spreed', 'Guest'), - participantIsUser: this.model.get('participantType') === OCA.SpreedMe.app.USER, - participantIsModerator: this.model.get('participantType') === OCA.SpreedMe.app.MODERATOR, - participantIsOwner: this.model.get('participantType') === OCA.SpreedMe.app.OWNER - }; - }, - onRender: function() { - this.$el.find('.avatar').each(function() { + regions: { + participantList: '@ui.participantList' + }, + + template: Handlebars.compile(TEMPLATE), + + initialize: function(options) { + this.room = options.room; + this.collection = options.collection; + this._participantListView = new OCA.SpreedMe.Views.ParticipantListView({ collection: options.collection }); + + // In Marionette 3.0 the view is not rendered automatically if + // needed when showing a child view, so it must be rendered + // explicitly to ensure that the DOM element in which the child view + // will be appended exists. + this.render(); + this.showChildView('participantList', this._participantListView, { replaceElement: true } ); + }, + + /** + * @param {OCA.SpreedMe.Models.Room} room + * @returns {Array} + */ + setRoom: function(room) { + this.room = room; + this.collection.setRoom(room); + }, + + onRender: function() { + this.initAddParticipantSelector(); + }, + + initAddParticipantSelector: function() { + this.ui.addParticipantInput.select2({ + ajax: { + url: OC.linkToOCS('apps/files_sharing/api/v1') + 'sharees', + dataType: 'json', + quietMillis: 100, + data: function (term) { + return { + format: 'json', + search: term, + perPage: 200, + itemType: 'call' + }; + }, + results: function (response) { + // TODO improve error case + if (_.isUndefined(response.ocs.data)) { + return; + } + + var results = [], + participants = this.room.get('participants'); + + $.each(response.ocs.data.exact.users, function(id, user) { + var isExactUserInGroup = false; + + $.each(participants, function(participantId) { + if (participantId === user.value.shareWith) { + isExactUserInGroup = true; + } + }); + + if (!isExactUserInGroup) { + results.push({ id: user.value.shareWith, displayName: user.label, type: "user"}); + } + }); + + $.each(response.ocs.data.users, function(id, user) { + var isUserInGroup = false; + + $.each(participants, function(participantId) { + if (participantId === user.value.shareWith) { + isUserInGroup = true; + } + }); + + if (!isUserInGroup) { + results.push({ id: user.value.shareWith, displayName: user.label, type: "user"}); + } + }); + + return { + results: results, + more: false + }; + }.bind(this) + }, + initSelection: function (element, callback) { + callback({id: element.val()}); + }, + formatResult: function (element) { + return '
' + escapeHTML(element.displayName) + '
'; + }, + formatSelection: function () { + return ''+OC.L10N.translate('spreed', 'Choose person…')+''; + } + }); + this.ui.addParticipantInput.on('change', function(e) { + var token = this.room.get('token'); + var participant = e.val; + OCA.SpreedMe.app.addParticipantToRoom(token, participant); + + $('.select2-drop').find('.avatar').each(function () { var element = $(this); - if (element.data('displayname').length) { - element.avatar(element.data('user-id'), 32, undefined, false, undefined, element.data('displayname')); + if (element.data('user-display-name')) { + element.avatar(element.data('user'), 32, undefined, false, undefined, element.data('user-display-name')); } else { - element.imageplaceholder('?', undefined, 32); - element.css('background-color', '#b9b9b9'); + element.avatar(element.data('user'), 32); } }); - - this.$el.attr('data-session-id', this.model.get('sessionId')); - this.$el.attr('data-participant', this.model.get('userId')); - this.$el.addClass('participant'); - - if (!this.model.isOnline()) { - this.$el.addClass('participant-offline'); - } - - this.toggleMenuClass(); - }, - events: { - 'click .participant-entry-utils-menu-button button': 'toggleMenu', - 'click .popovermenu .promote-moderator': 'promoteToModerator', - 'click .popovermenu .demote-moderator': 'demoteFromModerator', - 'click .popovermenu .remove-participant': 'removeParticipant' - }, - ui: { - 'participant': 'li.participant', - 'menu': '.popovermenu' - }, - template: Handlebars.compile(ITEM_TEMPLATE), - menuShown: false, - toggleMenu: function(e) { - e.preventDefault(); - this.menuShown = !this.menuShown; - this.toggleMenuClass(); - }, - toggleMenuClass: function() { - this.ui.menu.toggleClass('open', this.menuShown); - }, - promoteToModerator: function() { - if (this.model.get('participantType') !== OCA.SpreedMe.app.USER) { - return; - } - - var participantId = this.model.get('userId'), - self = this; - - $.ajax({ - type: 'POST', - url: OC.linkToOCS('apps/spreed/api/v1/room', 2) + OCA.SpreedMe.app.activeRoom.get('token') + '/moderators', - data: { - participant: participantId - }, - success: function() { - self.render(); - }, - error: function() { - console.log('Error while promoting user to moderator'); + }.bind(this)); + this.ui.addParticipantInput.on('click', function() { + $('.select2-drop').find('.avatar').each(function () { + var element = $(this); + if (element.data('user-display-name')) { + element.avatar(element.data('user'), 32, undefined, false, undefined, element.data('user-display-name')); + } else { + element.avatar(element.data('user'), 32); } }); - }, - demoteFromModerator: function() { - if (this.model.get('participantType') !== OCA.SpreedMe.app.MODERATOR) { - return; - } + }); - var participantId = this.model.get('userId'), - self = this; - - $.ajax({ - type: 'DELETE', - url: OC.linkToOCS('apps/spreed/api/v1/room', 2) + OCA.SpreedMe.app.activeRoom.get('token') + '/moderators', - data: { - participant: participantId - }, - success: function() { - self.render(); - }, - error: function() { - console.log('Error while demoting moderator'); + this.ui.addParticipantInput.on('select2-loaded', function() { + $('.select2-drop').find('.avatar').each(function () { + var element = $(this); + if (element.data('user-display-name')) { + element.avatar(element.data('user'), 32, undefined, false, undefined, element.data('user-display-name')); + } else { + element.avatar(element.data('user'), 32); } }); - }, - removeParticipant: function() { - if (this.model.get('participantType') === OCA.SpreedMe.app.OWNER) { - return; - } + }); + } - var self = this, - participantId = this.model.get('userId'), - endpoint = '/participants'; - - if (this.model.get('participantType') === OCA.SpreedMe.app.GUEST) { - participantId = this.model.get('sessionId'); - endpoint += '/guests'; - } - - $.ajax({ - type: 'DELETE', - url: OC.linkToOCS('apps/spreed/api/v1/room', 2) + OCA.SpreedMe.app.activeRoom.get('token') + endpoint, - data: { - participant: participantId - }, - success: function() { - self.render(); - }, - error: function() { - console.log('Error while removing user from room'); - } - }); - } - }) }); })(OC, OCA, Marionette, Handlebars); diff --git a/js/views/roomlistview.js b/js/views/roomlistview.js index 4e8b05db8..06889cab6 100644 --- a/js/views/roomlistview.js +++ b/js/views/roomlistview.js @@ -42,70 +42,24 @@ ''+ '
'+ '
    '+ - '{{#if canModerate}}'+ - '
  • '+ - ''+ - '
  • '+ - '{{#if isNameEditable}}'+ - '
  • '+ - ''+ - ''+ - '
    '+ - '
  • '+ - '{{/if}}'+ - '
  • '+ - ''+ - ''+ - '
    '+ - '
    '+ - '
  • '+ - '
  • '+ - ''+ - ''+ - '
    '+ - '
  • '+ - '{{/if}}'+ - '{{#if showShareLink}}'+ - '
  • '+ - ''+ - '
    '+ - '
  • '+ - '{{/if}}'+ '
  • '+ ''+ '
  • '+ '{{#if isDeletable}}'+ '
  • '+ ''+ '
  • '+ '{{/if}}'+ '
'+ - '{{#if canModerate}}'+ - ''+ - '{{/if}}'+ '
'; - var RoomItenView = Marionette.View.extend({ + var RoomItemView = Marionette.View.extend({ tagName: 'li', modelEvents: { 'change:active': function() { @@ -119,7 +73,6 @@ }, 'change:type': function() { this.render(); - this.checkSharingStatus(); } }, initialize: function() { @@ -135,32 +88,17 @@ }); }, templateContext: function() { - var canModerate = this.model.get('participantType') === 1 || this.model.get('participantType') === 2; return { - canModerate: canModerate, - showShareLink: !canModerate && this.model.get('type') === ROOM_TYPE_PUBLIC_CALL, - isNameEditable: canModerate && this.model.get('type') !== ROOM_TYPE_ONE_TO_ONE, - isDeletable: canModerate && (Object.keys(this.model.get('participants')).length > 2 || this.model.get('numGuests') > 0) + isDeletable: (this.model.get('participantType') === 1 || this.model.get('participantType') === 2) && + (Object.keys(this.model.get('participants')).length > 2 || this.model.get('numGuests') > 0) }; }, onRender: function() { - var roomURL, completeURL; + var roomURL; - this.initPersonSelector(); this.checkSharingStatus(); roomURL = OC.generateUrl('/call/' + this.model.get('token')); - completeURL = window.location.protocol + '//' + window.location.host + roomURL; - - this.ui.shareLinkInput.attr('value', completeURL); - this.$el.find('.clipboardButton').attr('data-clipboard-text', completeURL); - this.$el.find('.clipboardButton').tooltip({ - placement: 'bottom', - trigger: 'hover', - title: t('spreed', 'Copy') - }); - this.initClipboard(); - this.$el.find('.app-navigation-entry-link').attr('href', roomURL); if (this.model.get('active')) { @@ -179,26 +117,14 @@ }, events: { 'click .app-navigation-entry-utils-menu-button button': 'toggleMenu', - 'click .app-navigation-entry-menu .add-person-button': 'addPerson', - 'click .app-navigation-entry-menu .rename-room-button': 'showRenameInput', - 'click .app-navigation-entry-menu .rename-confirm': 'confirmRoomRename', - 'keyup .rename-input': 'renameKeyUp', - 'click .app-navigation-entry-menu .password-room-button': 'showPasswordInput', - 'click .app-navigation-entry-menu .password-confirm': 'confirmRoomPassword', - 'keyup .password-input': 'passwordKeyUp', - 'click .app-navigation-entry-menu .share-link-button': 'shareGroup', - 'click .app-navigation-entry-menu .leave-room-button': 'leaveRoom', - 'click .app-navigation-entry-menu .delete-room-button': 'deleteRoom', - 'click .icon-delete': 'unshareGroup', - 'click .app-navigation-entry-link': 'joinRoom' + 'click @ui.menu .leave-room-button': 'leaveRoom', + 'click @ui.menu .delete-room-button': 'deleteRoom', + 'click @ui.room': 'joinRoom' }, ui: { 'room': '.app-navigation-entry-link', 'menu': '.app-navigation-entry-menu', - 'shareLinkInput': '.share-link-input', - 'menuList': '.app-navigation-entry-menu-list', - 'personSelectorForm' : '.oca-spreedme-add-person', - 'personSelectorInput': '.add-person-input' + 'menuList': '.app-navigation-entry-menu-list' }, template: Handlebars.compile(ITEM_TEMPLATE), menuShown: false, @@ -209,14 +135,6 @@ }, toggleMenuClass: function() { this.ui.menu.toggleClass('open', this.menuShown); - - // Hide rename and password input and show button when opening menu - if (this.menuShown) { - this.$el.find('.rename-element').addClass('hidden-important'); - this.$el.find('.rename-room-button').removeClass('hidden-important'); - this.$el.find('.password-element').addClass('hidden-important'); - this.$el.find('.password-room-button').removeClass('hidden-important'); - } }, checkSharingStatus: function() { if (this.model.get('type') === ROOM_TYPE_ONE_TO_ONE) { // 1on1 @@ -247,126 +165,6 @@ this.addRoomMessage(); } }, - addPerson: function() { - this.ui.menuList.attr('style', 'display: none !important'); - this.ui.personSelectorForm.toggleClass('hidden'); - this.ui.personSelectorInput.select2('open'); - }, - showRenameInput: function() { - var currentRoomName = this.model.get('name'); - - this.$el.find('.rename-element').removeClass('hidden-important'); - this.$el.find('.rename-room-button').addClass('hidden-important'); - - if (currentRoomName) { - this.$el.find('.rename-input').val(currentRoomName); - } - - this.$el.find('.rename-input').focus(); - this.$el.find('.rename-input').select(); - }, - hideRenameInput: function() { - this.$el.find('.rename-element').addClass('hidden-important'); - this.$el.find('.rename-room-button').removeClass('hidden-important'); - }, - confirmRoomRename: function() { - var currentRoomName = this.model.get('name'); - var newRoomName = $.trim(this.$el.find('.rename-input').val()); - - if (currentRoomName !== newRoomName) { - console.log('Changing room name to: '+newRoomName+' from: '+currentRoomName); - this.renameRoom(newRoomName); - } - - this.hideRenameInput(); - }, - renameKeyUp: function(e) { - if (e.keyCode === 13) { - this.confirmRoomRename(); - } else if (e.keyCode === 27) { - this.hideRenameInput(); - } - }, - renameRoom: function(roomName) { - var app = OCA.SpreedMe.app; - - // This should be the only case - if ((this.model.get('type') !== ROOM_TYPE_ONE_TO_ONE) && (roomName.length <= 200)) { - $.ajax({ - url: OC.linkToOCS('apps/spreed/api/v1/room', 2) + this.model.get('token'), - type: 'PUT', - data: 'roomName='+roomName, - success: function() { - app.syncRooms(); - } - }); - } - }, - showPasswordInput: function() { - this.$el.find('.password-element').removeClass('hidden-important'); - this.$el.find('.password-room-button').addClass('hidden-important'); - - this.$el.find('.password-input').focus(); - this.$el.find('.password-input').select(); - }, - hidePasswordInput: function() { - this.$el.find('.password-element').addClass('hidden-important'); - this.$el.find('.password-room-button').removeClass('hidden-important'); - }, - confirmRoomPassword: function() { - var newRoomPassword = $.trim(this.$el.find('.password-input').val()); - this.passwordRoom(newRoomPassword); - this.hidePasswordInput(); - }, - passwordKeyUp: function(e) { - if (e.keyCode === 13) { - this.confirmRoomPassword(); - } else if (e.keyCode === 27) { - this.hidePasswordInput(); - } - }, - passwordRoom: function(roomPassword) { - var app = OCA.SpreedMe.app; - - if (this.model.get('type') === ROOM_TYPE_PUBLIC_CALL) { - $.ajax({ - url: OC.linkToOCS('apps/spreed/api/v1/room', 2) + this.model.get('token') + '/password', - type: 'PUT', - data: 'password='+roomPassword, - success: function() { - app.syncRooms(); - } - }); - } - }, - shareGroup: function() { - var app = OCA.SpreedMe.app; - - // This should be the only case - if (this.model.get('type') !== ROOM_TYPE_PUBLIC_CALL) { - $.ajax({ - url: OC.linkToOCS('apps/spreed/api/v1/room', 2) + this.model.get('token') + '/public', - type: 'POST', - success: function() { - app.syncRooms(); - } - }); - } - }, - unshareGroup: function() { - var app = OCA.SpreedMe.app; - - // This should be the only case - if (this.model.get('type') === ROOM_TYPE_PUBLIC_CALL) { - $.ajax({ - url: OC.linkToOCS('apps/spreed/api/v1/room', 2) + this.model.get('token') + '/public', - type: 'DELETE', - success: function() { - app.syncRooms(); - } - }); - } - }, leaveRoom: function() { // If user is in that room, it should leave the associated call first. if (this.model.get('active')) { @@ -507,164 +305,12 @@ html: 'true', title: htmlstring }); - }, - initClipboard: function () { - var clipboard = new Clipboard('.clipboardButton'); - clipboard.on('success', function(e) { - var $input = $(e.trigger); - $input.tooltip('hide') - .attr('data-original-title', t('core', 'Copied!')) - .tooltip('fixTitle') - .tooltip({placement: 'bottom', trigger: 'manual'}) - .tooltip('show'); - _.delay(function() { - $input.tooltip('hide') - .attr('data-original-title', t('core', 'Copy')) - .tooltip('fixTitle'); - }, 3000); - }); - clipboard.on('error', function (e) { - var $input = $(e.trigger); - var actionMsg = ''; - if (/iPhone|iPad/i.test(navigator.userAgent)) { - actionMsg = t('core', 'Not supported!'); - } else if (/Mac/i.test(navigator.userAgent)) { - actionMsg = t('core', 'Press ⌘-C to copy.'); - } else { - actionMsg = t('core', 'Press Ctrl-C to copy.'); - } - - $input.tooltip('hide') - .attr('data-original-title', actionMsg) - .tooltip('fixTitle') - .tooltip({placement: 'bottom', trigger: 'manual'}) - .tooltip('show'); - _.delay(function () { - $input.tooltip('hide') - .attr('data-original-title', t('spreed', 'Copy')) - .tooltip('fixTitle'); - }, 3000); - }); - }, - initPersonSelector: function() { - var _this = this; - - this.ui.personSelectorInput.select2({ - ajax: { - url: OC.linkToOCS('apps/files_sharing/api/v1') + 'sharees', - dataType: 'json', - quietMillis: 100, - data: function (term) { - return { - format: 'json', - search: term, - perPage: 200, - itemType: 'call' - }; - }, - results: function (response) { - // TODO improve error case - if (response.ocs.data === undefined) { - console.error('Failure happened', response); - return; - } - - var results = [], - participants = _this.model.get('participants'); - - $.each(response.ocs.data.exact.users, function(id, user) { - var isExactUserInGroup = false; - - $.each(participants, function(participantId) { - if (participantId === user.value.shareWith) { - isExactUserInGroup = true; - } - }); - - if (!isExactUserInGroup) { - results.push({ id: user.value.shareWith, displayName: user.label, type: "user"}); - } - }); - - $.each(response.ocs.data.users, function(id, user) { - var isUserInGroup = false; - - $.each(participants, function(participantId) { - if (participantId === user.value.shareWith) { - isUserInGroup = true; - } - }); - - if (!isUserInGroup) { - results.push({ id: user.value.shareWith, displayName: user.label, type: "user"}); - } - }); - - return { - results: results, - more: false - }; - } - }, - initSelection: function (element, callback) { - console.log(element); - callback({id: element.val()}); - }, - formatResult: function (element) { - return '
' + escapeHTML(element.displayName) + '
'; - }, - formatSelection: function () { - return ''+OC.L10N.translate('spreed', 'Choose person…')+''; - } - }); - this.ui.personSelectorInput.on('change', function(e) { - var token = _this.model.get('token'); - var participant = e.val; - OCA.SpreedMe.app.addParticipantToRoom(token, participant); - - $('.select2-drop').find('.avatar').each(function () { - var element = $(this); - if (element.data('user-display-name')) { - element.avatar(element.data('user'), 32, undefined, false, undefined, element.data('user-display-name')); - } else { - element.avatar(element.data('user'), 32); - } - }); - }); - this.ui.personSelectorInput.on('click', function() { - $('.select2-drop').find('.avatar').each(function () { - var element = $(this); - if (element.data('user-display-name')) { - element.avatar(element.data('user'), 32, undefined, false, undefined, element.data('user-display-name')); - } else { - element.avatar(element.data('user'), 32); - } - }); - }); - - this.ui.personSelectorInput.on('select2-loaded', function() { - $('.select2-drop').find('.avatar').each(function () { - var element = $(this); - if (element.data('user-display-name')) { - element.avatar(element.data('user'), 32, undefined, false, undefined, element.data('user-display-name')); - } else { - element.avatar(element.data('user'), 32); - } - }); - }); - - this.ui.personSelectorInput.on('select2-close', function () { - _this.ui.menuList.attr('style', 'display: block !important'); - _this.ui.personSelectorForm.toggleClass('hidden'); - _this.menuShown = false; - _this.toggleMenuClass(); - }); } }); var RoomListView = Marionette.CollectionView.extend({ tagName: 'ul', - childView: RoomItenView + childView: RoomItemView }); OCA.SpreedMe.Views.RoomListView = RoomListView; diff --git a/templates/index.php b/templates/index.php index 1b5259b38..2fe1da924 100644 --- a/templates/index.php +++ b/templates/index.php @@ -17,6 +17,7 @@ script( 'models/participant', 'models/participantcollection', 'views/callinfoview', + 'views/participantlistview', 'views/participantview', 'views/roomlistview', 'views/sidebarview',