From 8f4e3c6ce51e4fa5f7f8aff7a07a794b005f30f4 Mon Sep 17 00:00:00 2001 From: Aaron Ogle Date: Thu, 17 Sep 2015 17:24:41 -0500 Subject: [PATCH 01/12] Added dropdown for message options --- client/stylesheets/base.less | 49 ++++++++++++++++++++++++++++++++++- client/views/app/message.html | 17 +++++++----- client/views/app/room.coffee | 14 +++++++++- 3 files changed, 72 insertions(+), 8 deletions(-) diff --git a/client/stylesheets/base.less b/client/stylesheets/base.less index 0d1830fc5a3..0d8bf5a45ad 100644 --- a/client/stylesheets/base.less +++ b/client/stylesheets/base.less @@ -2375,15 +2375,56 @@ a.github-fork { cursor: pointer; } &:hover:not(.system) .edit-message { - display: inline-block; + display: block; } .delete-message { display: none; cursor: pointer; } &:hover:not(.system) .delete-message { + display: block; + } + .message-cog { + display: none; + cursor: pointer; + } + &:hover:not(.system) .message-cog { display: inline-block; } + + .message-dropdown { + position: absolute; + top: 65%; + left: 85px; + z-index: 1000; + float: left; + min-width: 110px; + display: none; + padding: 5px 0; + margin: 2px 0 0; + font-size: 14px; + text-align: left; + list-style: none; + background-color: #fff; + -webkit-background-clip: padding-box; + background-clip: padding-box; + border: 1px solid #ccc; + border: 1px solid rgba(0,0,0,.15); + border-radius: 4px; + -webkit-box-shadow: 0 6px 12px rgba(0,0,0,.175); + box-shadow: 0 6px 12px rgba(0,0,0,.175); + + li { + display: block; + padding: 3px 20px; + clear: both; + font-weight: 400; + line-height: 1.42857143; + color: #333; + white-space: nowrap; + } + } + .user { display: inline-block; font-weight: 600; @@ -2437,6 +2478,12 @@ a.github-fork { float: left; } } + + .message-dropdown { + top: 100%; + left: 0; + } + &:hover { .time { display: inline-block; diff --git a/client/views/app/message.html b/client/views/app/message.html index 70e01485246..d67cbcfae1e 100644 --- a/client/views/app/message.html +++ b/client/views/app/message.html @@ -11,13 +11,18 @@ {{_ "Only_you_can_see_this_message"}} {{/if}} - {{#if canEdit}} - - {{/if}} - {{#if canDelete}} - - {{/if}} + + + +
{{{body}}}
diff --git a/client/views/app/room.coffee b/client/views/app/room.coffee index d71bf3f5407..b55b095ce00 100644 --- a/client/views/app/room.coffee +++ b/client/views/app/room.coffee @@ -406,12 +406,21 @@ Template.room.events instance.showUsersOffline.set(!instance.showUsersOffline.get()) "click .edit-message": (e) -> - Template.instance().chatMessages.edit(e.currentTarget.parentNode.parentNode) + message = e.currentTarget.parentNode.parentNode + Template.instance().chatMessages.edit(message) + + $("\##{message.id} .message-dropdown").hide() + input = Template.instance().find('.input-message') Meteor.setTimeout -> input.focus() , 200 + 'click .message-cog': (e) -> + message_id = e.currentTarget.parentNode.parentNode.id + + $("\##{message_id} .message-dropdown").toggle() + "click .editing-commands-cancel > a": (e) -> Template.instance().chatMessages.clearEditing() @@ -434,6 +443,9 @@ Template.room.events 'click .delete-message': (event) -> message = @_arguments[1] msg = event.currentTarget.parentNode.parentNode + + $("\##{msg.id} .message-dropdown").hide() + instance = Template.instance() return if msg.classList.contains("system") swal { From 5a7f2746dbe3e1e093e783710f90294fc312113b Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt Date: Fri, 18 Sep 2015 09:31:04 -0300 Subject: [PATCH 02/12] Fix for race-condition on user creation that sometimes would not set user as admin --- server/lib/accounts.coffee | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/server/lib/accounts.coffee b/server/lib/accounts.coffee index 0cb2958c859..989491e6118 100644 --- a/server/lib/accounts.coffee +++ b/server/lib/accounts.coffee @@ -24,9 +24,6 @@ Accounts.onCreateUser (options, user) -> user.status = 'offline' user.active = not RocketChat.settings.get 'Accounts_ManuallyApproveNewUsers' - # when inserting first user give them admin privileges otherwise make a regular user - roleName = if Meteor.users.findOne() then 'user' else 'admin' - if not user?.name? or user.name is '' if options.profile?.name? user.name = options.profile?.name @@ -45,14 +42,20 @@ Accounts.onCreateUser (options, user) -> verified: true ] - Meteor.defer -> - # need to defer role assignment because underlying alanning:roles requires user - # to exist in users collection - RocketChat.authz.addUsersToRoles( user._id, roleName) - RocketChat.callbacks.run 'afterCreateUser', options, user - return user +# Wrap insertUserDoc to allow executing code after Accounts.insertUserDoc is run +Accounts.insertUserDoc = _.wrap Accounts.insertUserDoc, (insertUserDoc) -> + options = arguments[1] + user = arguments[2] + _id = insertUserDoc(options, user) + + # when inserting first user give them admin privileges otherwise make a regular user + roleName = if Meteor.users.findOne() then 'user' else 'admin' + + RocketChat.authz.addUsersToRoles(_id, roleName) + RocketChat.callbacks.run 'afterCreateUser', options, user + return _id Accounts.validateLoginAttempt (login) -> login = RocketChat.callbacks.run 'beforeValidateLogin', login From 4ab541291705cebd5071bf0b3fe62c1b568b5692 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt Date: Fri, 18 Sep 2015 09:36:00 -0300 Subject: [PATCH 03/12] Created a class for storing message action buttons --- client/views/app/message.coffee | 9 ++++++ client/views/app/message.html | 10 ++++-- .../client/MessageAction.coffee | 31 +++++++++++++++++++ packages/rocketchat-lib/package.js | 1 + 4 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 packages/rocketchat-lib/client/MessageAction.coffee diff --git a/client/views/app/message.coffee b/client/views/app/message.coffee index bdd7fb52b13..66189490c1f 100644 --- a/client/views/app/message.coffee +++ b/client/views/app/message.coffee @@ -1,4 +1,6 @@ Template.message.helpers + actions: -> + return Template.instance()?.actions?.getButtons() own: -> return 'own' if this.u?._id is Meteor.userId() @@ -57,6 +59,7 @@ Template.message.helpers Template.message.onViewRendered = (context) -> view = this + console.log view this._domrange.onAttached (domRange) -> lastNode = domRange.lastNode() if lastNode.previousElementSibling?.dataset?.date isnt lastNode.dataset.date @@ -92,3 +95,9 @@ Template.message.onViewRendered = (context) -> if view.parentView.parentView.parentView.parentView.parentView.templateInstance?().atBottom isnt true newMessage = document.querySelector(".new-message") newMessage.className = "new-message" + + # if RocketChat.authz.hasAtLeastOnePermission('edit-message', context.rid ) or (RocketChat.settings.get('Message_AllowEditing') and context.u?._id is Meteor.userId()) + # view.instance().actions.addButton({ id: 'edit-message', icon: 'icon-pencil', label: 'Edit' }) + +Template.message.onCreated -> + @actions = new MessageAction diff --git a/client/views/app/message.html b/client/views/app/message.html index d67cbcfae1e..626d0164edf 100644 --- a/client/views/app/message.html +++ b/client/views/app/message.html @@ -15,12 +15,18 @@
    - {{#if canEdit}} + + {{#each actions}} +
  • {{label}}
  • + {{/each}} + + + {{!-- {{#if canEdit}}
  • Edit
  • {{/if}} {{#if canDelete}}
  • Delete
  • - {{/if}} + {{/if}} --}}
diff --git a/packages/rocketchat-lib/client/MessageAction.coffee b/packages/rocketchat-lib/client/MessageAction.coffee new file mode 100644 index 00000000000..2d29afe658b --- /dev/null +++ b/packages/rocketchat-lib/client/MessageAction.coffee @@ -0,0 +1,31 @@ +class @MessageAction + constructor: -> + @buttons = new ReactiveVar {} + + addButton: (config) => + unless config?.id + throw new Meteor.Error "MessageAction-addButton-error", "Button id was not informed." + + Tracker.nonreactive => + btns = @buttons.get() + btns[config.id] = config + @buttons.set btns + + removeButton: (id) => + Tracker.nonreactive => + btns = @buttons.get() + delete btns[id] + @buttons.set btns + + updateButton: (id, config) => + Tracker.nonreactive => + btns = @buttons.get() + if btns[id] + btns[id] = _.extend btns[id], config + @buttons.set btns + + getButtons: => + return _.sortBy (_.toArray @buttons.get()), 'order' + + resetButtons: => + @buttons.set {} diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 27fd00eafe0..e63f11d6715 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -27,6 +27,7 @@ Package.onUse(function(api) { // CLIENT api.addFiles('client/Notifications.coffee', 'client'); api.addFiles('client/TabBar.coffee', 'client'); + api.addFiles('client/MessageAction.coffee', 'client'); api.addFiles('settings/client/startup.coffee', 'client'); api.addFiles('settings/client/rocketchat.coffee', 'client'); From f1ec43a5de14e33524ff6818fb6b626bd1e239fa Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento Date: Fri, 18 Sep 2015 12:13:08 -0300 Subject: [PATCH 04/12] Change layout of dropdown to toolbar --- client/stylesheets/base.less | 72 ++++++++++++++++++++--------------- client/views/app/message.html | 24 +++++++----- client/views/app/room.coffee | 4 +- 3 files changed, 57 insertions(+), 43 deletions(-) diff --git a/client/stylesheets/base.less b/client/stylesheets/base.less index 0d8bf5a45ad..2700f9cb8a0 100644 --- a/client/stylesheets/base.less +++ b/client/stylesheets/base.less @@ -2384,44 +2384,54 @@ a.github-fork { &:hover:not(.system) .delete-message { display: block; } - .message-cog { - display: none; - cursor: pointer; + .message-cog-container { + position: relative; + display: inline-block; + .message-cog { + visibility: hidden; + cursor: pointer; + } } &:hover:not(.system) .message-cog { - display: inline-block; + visibility: visible; } .message-dropdown { position: absolute; - top: 65%; - left: 85px; + top: -5px; + left: -2px; z-index: 1000; - float: left; - min-width: 110px; display: none; - padding: 5px 0; - margin: 2px 0 0; - font-size: 14px; - text-align: left; - list-style: none; background-color: #fff; - -webkit-background-clip: padding-box; - background-clip: padding-box; - border: 1px solid #ccc; - border: 1px solid rgba(0,0,0,.15); + border: 1px solid #eee; border-radius: 4px; - -webkit-box-shadow: 0 6px 12px rgba(0,0,0,.175); - box-shadow: 0 6px 12px rgba(0,0,0,.175); + overflow: hidden; + box-shadow: 1px 1px 4px #eee; + ul { + display: flex; + display: -webkit-flex; + padding: 0px; + font-size: 14px; - li { - display: block; - padding: 3px 20px; - clear: both; - font-weight: 400; - line-height: 1.42857143; - color: #333; - white-space: nowrap; + li { + display: block; + padding: 0px 8px; + font-weight: 400; + line-height: 26px; + cursor: pointer; + color: #666; + &:first-child { + padding-left: 0px; + background-color: #f8f8f8; + border-right: 1px solid #eee; + } + &:last-child { + padding-right: 13px; + } + &:hover { + background-color: #eee; + } + } } } @@ -2479,10 +2489,10 @@ a.github-fork { } } - .message-dropdown { - top: 100%; - left: 0; - } + // .message-dropdown { + // top: 100%; + // left: 0; + // } &:hover { .time { diff --git a/client/views/app/message.html b/client/views/app/message.html index d67cbcfae1e..0bf638ea5c0 100644 --- a/client/views/app/message.html +++ b/client/views/app/message.html @@ -11,18 +11,22 @@ {{_ "Only_you_can_see_this_message"}} {{/if}} - +
+ +
+
    +
  • + {{#if canEdit}} +
  • + {{/if}} + {{#if canDelete}} +
  • + {{/if}} +
+
+
-
    - {{#if canEdit}} -
  • Edit
  • - {{/if}} - {{#if canDelete}} -
  • Delete
  • - {{/if}} -
-
{{{body}}}
diff --git a/client/views/app/room.coffee b/client/views/app/room.coffee index b55b095ce00..710f6b51e9b 100644 --- a/client/views/app/room.coffee +++ b/client/views/app/room.coffee @@ -416,8 +416,8 @@ Template.room.events input.focus() , 200 - 'click .message-cog': (e) -> - message_id = e.currentTarget.parentNode.parentNode.id + 'click .message-cog, click .message-dropdown-close': (e) -> + message_id = $(e.currentTarget).closest('.message').attr('id') $("\##{message_id} .message-dropdown").toggle() From 5d4abadee7a1ad0b10bc518dcf5d86cd56cfb187 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento Date: Fri, 18 Sep 2015 14:01:23 -0300 Subject: [PATCH 05/12] Merge part of webrtc-ib in webrtc --- packages/rocketchat-webrtc/webrtc.js | 177 ++++++++++++++++++++------- 1 file changed, 135 insertions(+), 42 deletions(-) diff --git a/packages/rocketchat-webrtc/webrtc.js b/packages/rocketchat-webrtc/webrtc.js index dfc03dace1b..c9188e1ffb4 100644 --- a/packages/rocketchat-webrtc/webrtc.js +++ b/packages/rocketchat-webrtc/webrtc.js @@ -3,6 +3,10 @@ webrtc = { pc: undefined, to: undefined, room: undefined, + activeMediastream: undefined, + remoteDataSDP: undefined, + mode: undefined, + lastSeenTimestamp: new Date(), debug: false, config: { iceServers: [ @@ -14,17 +18,28 @@ webrtc = { data.to = webrtc.to; data.room = webrtc.room; data.from = Meteor.user().username; + data.mod = (webrtc.mode ? webrtc.mode : 0); RocketChat.Notifications.notifyUser(data.to, 'webrtc', data); }, stop: function(sendEvent) { + if (webrtc.activeMediastream) { + webrtc.activeMediastream = undefined; + } + if (webrtc.pc) { if (webrtc.pc.signalingState != 'closed') { webrtc.pc.close(); - } - if (sendEvent != false) { - RocketChat.Notifications.notifyUser(webrtc.to, 'webrtc', {to: webrtc.to, room: webrtc.room, from: Meteor.userId(), close: true}); + webrtc.pc = undefined; + webrtc.mode = 0; } } + + + this.onRemoteUrl(); + this.onSelfUrl(); + if (sendEvent != false) { + RocketChat.Notifications.notifyUser(webrtc.to, 'webrtc', {to: webrtc.to, room: webrtc.room, from: Meteor.userId(), close: true}); + } }, log: function() { if (webrtc.debug === true) { @@ -39,6 +54,18 @@ function onError() { console.log(arguments); } +webrtc.activateLocalStream = function() { + var media ={ "audio": true, "video": {mandatory: {minWidth:1280, minHeight:720}}} ; + + // get the local stream, show it in the local video element and send it + navigator.getUserMedia(media, function (stream) { + webrtc.log('getUserMedia got stream'); + webrtc.onSelfUrl(URL.createObjectURL(stream)); + webrtc.activeMediastream = stream; + + }, function(e) { webrtc.log('getUserMedia failed during activateLocalStream ' + e); }); +} + // run start(true) to initiate a call webrtc.start = function (isCaller, fromUsername) { webrtc.pc = new RTCPeerConnection(webrtc.config); @@ -62,7 +89,7 @@ webrtc.start = function (isCaller, fromUsername) { // once remote stream arrives, show it in the remote video element webrtc.pc.onaddstream = function (evt) { - webrtc.log('onaddstream', arguments) + webrtc.log('onaddstream', arguments); webrtc.onRemoteUrl(URL.createObjectURL(evt.stream)); }; @@ -70,23 +97,53 @@ webrtc.start = function (isCaller, fromUsername) { webrtc.log('oniceconnectionstatechange', arguments) var srcElement = evt.srcElement || evt.target; if (srcElement.iceConnectionState == 'disconnected' || srcElement.iceConnectionState == 'closed') { - webrtc.pc.getLocalStreams().forEach(function(stream) { - stream.stop(); - webrtc.onSelfUrl(); - }); - webrtc.pc.getRemoteStreams().forEach(function(stream) { - if (stream.stop) { + if (webrtc.pc) { + webrtc.pc.getLocalStreams().forEach(function(stream) { stream.stop(); - } - webrtc.onRemoteUrl(); - }); - webrtc.pc = undefined; + webrtc.onSelfUrl(); + }); + webrtc.pc.getRemoteStreams().forEach(function(stream) { + if (stream.stop) { + stream.stop(); + } + webrtc.onRemoteUrl(); + }); + webrtc.pc = undefined; + webrtc.mode = 0; + } + } } - var getUserMedia = function() { + + var gotDescription = function(desc) { + webrtc.pc.setLocalDescription(desc, function() {}, onError); + webrtc.send({ "sdp": desc.toJSON(), cid: webrtc.cid }); + + } + + var CreateMonitoringOffer = function() { + + webrtc.pc.createOffer(gotDescription, onError, { 'mandatory': { 'OfferToReceiveAudio': true, 'OfferToReceiveVideo': true } }); + + } + + var AutoConnectStream = function() { + webrtc.pc.addStream(webrtc.activeMediastream); + webrtc.pc.setRemoteDescription(new RTCSessionDescription(webrtc.remoteDataSDP)); + webrtc.pc.createAnswer(gotDescription, onError); + + } + var LocalGetUserMedia = function() { + + + + var media ={ "audio": true, "video": {mandatory: {minWidth:1280, minHeight:720}}} ; + + // get the local stream, show it in the local video element and send it - navigator.getUserMedia({ "audio": true, "video": {mandatory: {minWidth:1280, minHeight:720}} }, function (stream) { + navigator.getUserMedia(media, function (stream) { + webrtc.log('getUserMedia got stream'); webrtc.onSelfUrl(URL.createObjectURL(stream)); webrtc.pc.addStream(stream); @@ -97,36 +154,49 @@ webrtc.start = function (isCaller, fromUsername) { webrtc.pc.createAnswer(gotDescription, onError); } - function gotDescription(desc) { - webrtc.pc.setLocalDescription(desc, function() {}, onError); - webrtc.send({ "sdp": desc.toJSON(), cid: webrtc.cid }); - } - }, function() {}); + }, function(e) { webrtc.log('getUserMedia failed' + e); }); + } if (isCaller) { - getUserMedia(); - } else { - swal({ - title: "Video call from "+fromUsername, - text: "Do you want to accept?", - type: "warning", - showCancelButton: true, - confirmButtonColor: "#DD6B55", - confirmButtonText: "Yes", - cancelButtonText: "No" - }, function(isConfirm){ - if (isConfirm) { - getUserMedia(); - } else { - webrtc.stop(); + webrtc.log('isCaller LocalGetUserMedia'); + if (webrtc.mode) { + if (webrtc.mode === 2) { + CreateMonitoringOffer(); + } else { // node === 1 + + LocalGetUserMedia(); } - }); + } else { + // no mode + LocalGetUserMedia(); + } + + } else { + if (!webrtc.activeMediastream) { + swal({ + title: "Video call from "+fromUsername, + text: "Do you want to accept?", + type: "warning", + showCancelButton: true, + confirmButtonColor: "#DD6B55", + confirmButtonText: "Yes", + cancelButtonText: "No" + }, function(isConfirm){ + if (isConfirm) { + LocalGetUserMedia(); + } else { + webrtc.stop(); + } + }); + } else { + AutoConnectStream(); + } } } RocketChat.Notifications.onUser('webrtc', function(data) { - webrtc.log('stream.on', Meteor.userId(), data) + webrtc.log('processIncomingRtcMessage()', Meteor.userId(), data) if (!webrtc.to) { webrtc.to = data.room.replace(Meteor.userId(), ''); } @@ -135,15 +205,38 @@ RocketChat.Notifications.onUser('webrtc', function(data) { webrtc.room = data.room; } - if (data.close == true) { + + // do not stop local video if in monitoring mode + if (data.close == true) { + + if (webrtc.activeMediastream) { + if (webrtc.pc) { + webrtc.pc.getRemoteStreams().forEach(function(stream) { + if (!stream.stop) { + stream.stop(); + } + }); + webrtc.pc = undefined; + webrtc.mode = 0; + } + + } else { + webrtc.stop(false); - return + + } + return } - if (!webrtc.pc) + + if (!webrtc.pc) { + if ((webrtc.activeMediastream) && (data.sdp != undefined)){ + webrtc.remoteDataSDP = data.sdp; + } webrtc.start(false, data.from); + } - if (data.sdp) { + if (data.sdp != undefined) { webrtc.pc.setRemoteDescription(new RTCSessionDescription(data.sdp)); } else { if( ["closed", "failed", "disconnected", "completed"].indexOf(webrtc.pc.iceConnectionState) === -1) { From 06b0a03d46366c508a0efc6cf2e8bfca1d8831d5 Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt Date: Fri, 18 Sep 2015 15:16:28 -0300 Subject: [PATCH 06/12] Message Action Buttons --- client/lib/tapi18n.coffee | 3 + client/views/app/message.coffee | 11 +- client/views/app/message.html | 11 +- client/views/app/room.coffee | 44 +------ .../client/MessageAction.coffee | 114 +++++++++++++++--- packages/rocketchat-lib/i18n/en.i18n.json | 4 + packages/rocketchat-lib/i18n/pt.i18n.json | 4 + packages/rocketchat-lib/package-tap.i18n | 0 packages/rocketchat-lib/package.js | 18 ++- 9 files changed, 130 insertions(+), 79 deletions(-) create mode 100644 packages/rocketchat-lib/i18n/en.i18n.json create mode 100644 packages/rocketchat-lib/i18n/pt.i18n.json create mode 100644 packages/rocketchat-lib/package-tap.i18n diff --git a/client/lib/tapi18n.coffee b/client/lib/tapi18n.coffee index 1cf705e3952..b93b8f8193a 100644 --- a/client/lib/tapi18n.coffee +++ b/client/lib/tapi18n.coffee @@ -13,3 +13,6 @@ @isRtl = (language) -> # https://en.wikipedia.org/wiki/Right-to-left#cite_note-2 return language?.split('-').shift().toLowerCase() in ['ar', 'dv', 'fa', 'he', 'ku', 'ps', 'sd', 'ug', 'ur', 'yi'] + +UI.registerHelper '_t', (key) -> + return TAPi18next.t key \ No newline at end of file diff --git a/client/views/app/message.coffee b/client/views/app/message.coffee index 66189490c1f..75764bda858 100644 --- a/client/views/app/message.coffee +++ b/client/views/app/message.coffee @@ -1,7 +1,7 @@ Template.message.helpers actions: -> - return Template.instance()?.actions?.getButtons() - + return RocketChat.MessageAction.getButtons(this) + own: -> return 'own' if this.u?._id is Meteor.userId() @@ -59,7 +59,6 @@ Template.message.helpers Template.message.onViewRendered = (context) -> view = this - console.log view this._domrange.onAttached (domRange) -> lastNode = domRange.lastNode() if lastNode.previousElementSibling?.dataset?.date isnt lastNode.dataset.date @@ -95,9 +94,3 @@ Template.message.onViewRendered = (context) -> if view.parentView.parentView.parentView.parentView.parentView.templateInstance?().atBottom isnt true newMessage = document.querySelector(".new-message") newMessage.className = "new-message" - - # if RocketChat.authz.hasAtLeastOnePermission('edit-message', context.rid ) or (RocketChat.settings.get('Message_AllowEditing') and context.u?._id is Meteor.userId()) - # view.instance().actions.addButton({ id: 'edit-message', icon: 'icon-pencil', label: 'Edit' }) - -Template.message.onCreated -> - @actions = new MessageAction diff --git a/client/views/app/message.html b/client/views/app/message.html index 626d0164edf..3c0a4f29863 100644 --- a/client/views/app/message.html +++ b/client/views/app/message.html @@ -15,18 +15,9 @@
    - {{#each actions}} -
  • {{label}}
  • +
  • {{_t i18nLabel}}
  • {{/each}} - - - {{!-- {{#if canEdit}} -
  • Edit
  • - {{/if}} - {{#if canDelete}} -
  • Delete
  • - {{/if}} --}}
diff --git a/client/views/app/room.coffee b/client/views/app/room.coffee index b55b095ce00..d77c44733b0 100644 --- a/client/views/app/room.coffee +++ b/client/views/app/room.coffee @@ -405,17 +405,6 @@ Template.room.events 'click .see-all': (e, instance) -> instance.showUsersOffline.set(!instance.showUsersOffline.get()) - "click .edit-message": (e) -> - message = e.currentTarget.parentNode.parentNode - Template.instance().chatMessages.edit(message) - - $("\##{message.id} .message-dropdown").hide() - - input = Template.instance().find('.input-message') - Meteor.setTimeout -> - input.focus() - , 200 - 'click .message-cog': (e) -> message_id = e.currentTarget.parentNode.parentNode.id @@ -440,33 +429,6 @@ Template.room.events 'click .image-to-download': (event) -> ChatMessage.update {_id: this._arguments[1]._id, 'urls.url': $(event.currentTarget).data('url')}, {$set: {'urls.$.downloadImages': true}} - 'click .delete-message': (event) -> - message = @_arguments[1] - msg = event.currentTarget.parentNode.parentNode - - $("\##{msg.id} .message-dropdown").hide() - - instance = Template.instance() - return if msg.classList.contains("system") - swal { - title: t('Are_you_sure') - text: t('You_will_not_be_able_to_recover') - type: 'warning' - showCancelButton: true - confirmButtonColor: '#DD6B55' - confirmButtonText: t('Yes_delete_it') - cancelButtonText: t('Cancel') - closeOnConfirm: false - html: false - }, -> - swal - title: t('Deleted') - text: t('Your_entry_has_been_deleted') - type: 'success' - timer: 1000 - showConfirmButton: false - - instance.chatMessages.deleteMsg(message) 'click .pin-message': (event) -> message = @_arguments[1] instance = Template.instance() @@ -581,6 +543,12 @@ Template.room.onCreated -> @autorun -> self.subscribe 'fullUserData', Session.get('showUserInfo'), 1 + for button in RocketChat.MessageAction.getButtons() + if _.isFunction button.action + evt = {} + evt["click .#{button.id}"] = button.action + Template.room.events evt + Template.room.onDestroyed -> RocketChat.TabBar.resetButtons() diff --git a/packages/rocketchat-lib/client/MessageAction.coffee b/packages/rocketchat-lib/client/MessageAction.coffee index 2d29afe658b..108d15ab941 100644 --- a/packages/rocketchat-lib/client/MessageAction.coffee +++ b/packages/rocketchat-lib/client/MessageAction.coffee @@ -1,31 +1,105 @@ -class @MessageAction - constructor: -> - @buttons = new ReactiveVar {} - - addButton: (config) => +RocketChat.MessageAction = new class + buttons = new ReactiveVar {} + + ### + config expects the following keys (only id is mandatory): + id (mandatory) + icon: string + i18nLabel: string + action: function(event, instance) + validation: function(message) + order: integer + ### + addButton = (config) -> unless config?.id throw new Meteor.Error "MessageAction-addButton-error", "Button id was not informed." - Tracker.nonreactive => - btns = @buttons.get() + Tracker.nonreactive -> + btns = buttons.get() btns[config.id] = config - @buttons.set btns + buttons.set btns - removeButton: (id) => - Tracker.nonreactive => - btns = @buttons.get() + removeButton = (id) -> + Tracker.nonreactive -> + btns = buttons.get() delete btns[id] - @buttons.set btns + buttons.set btns - updateButton: (id, config) => - Tracker.nonreactive => - btns = @buttons.get() + updateButton = (id, config) -> + Tracker.nonreactive -> + btns = buttons.get() if btns[id] btns[id] = _.extend btns[id], config - @buttons.set btns + buttons.set btns + + getButtons = (message) -> + allButtons = _.toArray buttons.get() + if message + allowedButtons = _.compact _.map allButtons, (button) -> + unless button.validation? + return true + if button.validation(message) + return button + else + allowedButtons = allButtons + + return _.sortBy allowedButtons, 'order' + + resetButtons = -> + buttons.set {} + + addButton: addButton + removeButton: removeButton + updateButton: updateButton + getButtons: getButtons + resetButtons: resetButtons + +Meteor.startup -> + RocketChat.MessageAction.addButton + id: 'edit-message' + icon: 'icon-pencil' + i18nLabel: 'rocketchat-lib:Edit' + action: (event, instance) -> + message = event.currentTarget.parentNode.parentNode + instance.chatMessages.edit(message) + $("\##{message.id} .message-dropdown").hide() + input = instance.find('.input-message') + Meteor.setTimeout -> + input.focus() + , 200 + validation: (message) -> + return RocketChat.authz.hasAtLeastOnePermission('edit-message', message.rid ) or RocketChat.settings.get('Message_AllowEditing') and message.u?._id is Meteor.userId() + order: 1 + RocketChat.MessageAction.addButton + id: 'delete-message' + icon: 'icon-trash-1' + i18nLabel: 'rocketchat-lib:Delete' + action: (event, instance) -> + message = @_arguments[1] + msg = event.currentTarget.parentNode.parentNode + + $("\##{msg.id} .message-dropdown").hide() - getButtons: => - return _.sortBy (_.toArray @buttons.get()), 'order' + return if msg.classList.contains("system") + swal { + title: t('Are_you_sure') + text: t('You_will_not_be_able_to_recover') + type: 'warning' + showCancelButton: true + confirmButtonColor: '#DD6B55' + confirmButtonText: t('Yes_delete_it') + cancelButtonText: t('Cancel') + closeOnConfirm: false + html: false + }, -> + swal + title: t('Deleted') + text: t('Your_entry_has_been_deleted') + type: 'success' + timer: 1000 + showConfirmButton: false - resetButtons: => - @buttons.set {} + instance.chatMessages.deleteMsg(message) + validation: (message) -> + return RocketChat.authz.hasAtLeastOnePermission('delete-message', message.rid ) or RocketChat.settings.get('Message_AllowDeleting') and message.u?._id is Meteor.userId() + order: 2 \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/en.i18n.json b/packages/rocketchat-lib/i18n/en.i18n.json new file mode 100644 index 00000000000..9c76e8e402a --- /dev/null +++ b/packages/rocketchat-lib/i18n/en.i18n.json @@ -0,0 +1,4 @@ +{ + "Edit": "Edit", + "Delete": "Delete" +} \ No newline at end of file diff --git a/packages/rocketchat-lib/i18n/pt.i18n.json b/packages/rocketchat-lib/i18n/pt.i18n.json new file mode 100644 index 00000000000..a5227168f1f --- /dev/null +++ b/packages/rocketchat-lib/i18n/pt.i18n.json @@ -0,0 +1,4 @@ +{ + "Edit": "Editar", + "Delete": "Excluir" +} \ No newline at end of file diff --git a/packages/rocketchat-lib/package-tap.i18n b/packages/rocketchat-lib/package-tap.i18n new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index e63f11d6715..0e7854b0ad5 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -15,6 +15,19 @@ Package.onUse(function(api) { api.use('underscore'); api.use('underscorestring:underscore.string'); + // TAPi18n + api.use('templating', 'client'); + var _ = Npm.require('underscore'); + var fs = Npm.require('fs'); + tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-lib/i18n'), function(filename) { + if (fs.statSync('packages/rocketchat-lib/i18n/' + filename).size > 16) { + return 'i18n/' + filename; + } + })); + api.use(["tap:i18n@1.5.1"], ["client", "server"]); + api.imply('tap:i18n'); + api.addFiles("package-tap.i18n", ["client", "server"]); + // COMMON api.addFiles('lib/core.coffee'); api.addFiles('lib/callbacks.coffee'); @@ -23,7 +36,6 @@ Package.onUse(function(api) { api.addFiles('settings/lib/settings.coffee'); api.addFiles('settings/lib/rocketchat.coffee'); - // CLIENT api.addFiles('client/Notifications.coffee', 'client'); api.addFiles('client/TabBar.coffee', 'client'); @@ -32,7 +44,6 @@ Package.onUse(function(api) { api.addFiles('settings/client/startup.coffee', 'client'); api.addFiles('settings/client/rocketchat.coffee', 'client'); - // SERVER api.addFiles('server/functions/checkUsernameAvailability.coffee', 'server'); api.addFiles('server/functions/setUsername.coffee', 'server'); @@ -47,6 +58,7 @@ Package.onUse(function(api) { api.addFiles('server/Notifications.coffee', 'server'); + // Settings api.addFiles('settings/server/methods.coffee', 'server'); api.addFiles('settings/server/publication.coffee', 'server'); api.addFiles('settings/server/startup.coffee', 'server'); @@ -55,6 +67,8 @@ Package.onUse(function(api) { api.addFiles('server/cdn.coffee', 'server'); + // TAPi18n -- needs to be added last + api.addFiles(tapi18nFiles, ["client", "server"]); // EXPORT api.export('RocketChat'); From e2027851f39f6328039cc5547dee0f4a710b374d Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt Date: Fri, 18 Sep 2015 15:28:45 -0300 Subject: [PATCH 07/12] message id fixed --- client/views/app/room.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/views/app/room.coffee b/client/views/app/room.coffee index 3d89274ab12..573dc2adb2b 100644 --- a/client/views/app/room.coffee +++ b/client/views/app/room.coffee @@ -405,8 +405,8 @@ Template.room.events 'click .see-all': (e, instance) -> instance.showUsersOffline.set(!instance.showUsersOffline.get()) - 'click .message-cog': (e) -> - message_id = e.currentTarget.parentNode.parentNode.id + 'click .message-cog, click .message-dropdown-close': (e) -> + message_id = $(e.currentTarget).closest('.message').attr('id') $("\##{message_id} .message-dropdown").toggle() "click .editing-commands-cancel > a": (e) -> From 39e3efe7e344da7284e4f844ed1376384a6fac7c Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt Date: Fri, 18 Sep 2015 16:43:27 -0300 Subject: [PATCH 08/12] Hide other popovers when opening one --- client/views/app/room.coffee | 8 ++++++-- packages/rocketchat-lib/client/MessageAction.coffee | 7 +++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/client/views/app/room.coffee b/client/views/app/room.coffee index 573dc2adb2b..0c6b3efa500 100644 --- a/client/views/app/room.coffee +++ b/client/views/app/room.coffee @@ -405,9 +405,13 @@ Template.room.events 'click .see-all': (e, instance) -> instance.showUsersOffline.set(!instance.showUsersOffline.get()) - 'click .message-cog, click .message-dropdown-close': (e) -> + 'click .message-cog': (e) -> message_id = $(e.currentTarget).closest('.message').attr('id') - $("\##{message_id} .message-dropdown").toggle() + $('.message-dropdown:visible').hide() + $("\##{message_id} .message-dropdown").show() + + 'click .message-dropdown-close': -> + $('.message-dropdown:visible').hide() "click .editing-commands-cancel > a": (e) -> Template.instance().chatMessages.clearEditing() diff --git a/packages/rocketchat-lib/client/MessageAction.coffee b/packages/rocketchat-lib/client/MessageAction.coffee index 108d15ab941..d43de43796a 100644 --- a/packages/rocketchat-lib/client/MessageAction.coffee +++ b/packages/rocketchat-lib/client/MessageAction.coffee @@ -60,7 +60,7 @@ Meteor.startup -> icon: 'icon-pencil' i18nLabel: 'rocketchat-lib:Edit' action: (event, instance) -> - message = event.currentTarget.parentNode.parentNode + message = $(event.currentTarget).closest('.message')[0] instance.chatMessages.edit(message) $("\##{message.id} .message-dropdown").hide() input = instance.find('.input-message') @@ -70,16 +70,15 @@ Meteor.startup -> validation: (message) -> return RocketChat.authz.hasAtLeastOnePermission('edit-message', message.rid ) or RocketChat.settings.get('Message_AllowEditing') and message.u?._id is Meteor.userId() order: 1 + RocketChat.MessageAction.addButton id: 'delete-message' icon: 'icon-trash-1' i18nLabel: 'rocketchat-lib:Delete' action: (event, instance) -> message = @_arguments[1] - msg = event.currentTarget.parentNode.parentNode - + msg = $(event.currentTarget).closest('.message')[0] $("\##{msg.id} .message-dropdown").hide() - return if msg.classList.contains("system") swal { title: t('Are_you_sure') From a39a01ddd8c32adaf0a23dd8093087d69655931c Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt Date: Fri, 18 Sep 2015 16:46:29 -0300 Subject: [PATCH 09/12] Fix ldap package i18n --- packages/rocketchat-ldap/package.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/rocketchat-ldap/package.js b/packages/rocketchat-ldap/package.js index 8333f584058..0d510d5fdff 100644 --- a/packages/rocketchat-ldap/package.js +++ b/packages/rocketchat-ldap/package.js @@ -12,11 +12,11 @@ Npm.depends({ // Loads all i18n.json files into tapi18nFiles var _ = Npm.require('underscore'); var fs = Npm.require('fs'); -tapi18nFiles = fs.readdirSync('packages/rocketchat-ldap/i18n').forEach(function(filename) { +tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-ldap/i18n'), function(filename) { if (fs.statSync('packages/rocketchat-ldap/i18n/' + filename).size > 16) { return 'i18n/' + filename; } -}); +})); Package.onUse(function(api) { api.versionsFrom('1.0.3.1'); @@ -35,7 +35,6 @@ Package.onUse(function(api) { // Common // TAP api.addFiles('package-tap.i18n'); - api.addFiles(tapi18nFiles); // Client api.addFiles('ldap_client.js', 'client'); @@ -43,6 +42,7 @@ Package.onUse(function(api) { api.addFiles('ldap_server.js', 'server'); api.addFiles('config_server.coffee', 'server'); + api.addFiles(tapi18nFiles); api.export('LDAP', 'server'); api.export('LDAP_DEFAULTS', 'server'); From 87dec63fa05d70299d7cfbd017e7f9b7e2d65939 Mon Sep 17 00:00:00 2001 From: Aaron Ogle Date: Fri, 18 Sep 2015 14:48:50 -0500 Subject: [PATCH 10/12] Deepend dropshadow color. Changed close icon to arrow. Animate in. --- client/stylesheets/base.less | 25 +++++++++++++++++++++++-- client/views/app/message.html | 2 +- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/client/stylesheets/base.less b/client/stylesheets/base.less index 2700f9cb8a0..e11be9089ff 100644 --- a/client/stylesheets/base.less +++ b/client/stylesheets/base.less @@ -2396,6 +2396,24 @@ a.github-fork { visibility: visible; } + @keyframes dropdown-in { + 0% { + display: none; + opacity: 0; + } + + 1% { + display: block; + opacity: 0; + transform: scale(0); + } + + 100% { + opacity: 1; + transform: scale(1); + } + } + .message-dropdown { position: absolute; top: -5px; @@ -2406,7 +2424,10 @@ a.github-fork { border: 1px solid #eee; border-radius: 4px; overflow: hidden; - box-shadow: 1px 1px 4px #eee; + box-shadow: 1px 1px 4px #B3B3B3; + transition: transform .3s ease-in-out, opacity .3s ease-in-out; + animation: dropdown-in .3s ease-in-out; + ul { display: flex; display: -webkit-flex; @@ -2421,7 +2442,7 @@ a.github-fork { cursor: pointer; color: #666; &:first-child { - padding-left: 0px; + padding-left: 6px; background-color: #f8f8f8; border-right: 1px solid #eee; } diff --git a/client/views/app/message.html b/client/views/app/message.html index 0bf638ea5c0..729a6e3777c 100644 --- a/client/views/app/message.html +++ b/client/views/app/message.html @@ -15,7 +15,7 @@
    -
  • +
  • {{#if canEdit}}
  • {{/if}} From bb000ed2d63f9ebe82aef26ff0e85e2bf106612c Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt Date: Fri, 18 Sep 2015 17:14:34 -0300 Subject: [PATCH 11/12] Only show menu if you have available actions --- client/views/app/message.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/views/app/message.html b/client/views/app/message.html index cb8664d3e9c..2ff13ac47cd 100644 --- a/client/views/app/message.html +++ b/client/views/app/message.html @@ -10,7 +10,7 @@ {{#if private}} {{_ "Only_you_can_see_this_message"}} {{/if}} - + {{#if actions.length}}
    @@ -22,6 +22,7 @@
+ {{/if}}
From d6b0dcaac6a51341135080e6a2ec5e606585445d Mon Sep 17 00:00:00 2001 From: Marcelo Schmidt Date: Fri, 18 Sep 2015 17:15:39 -0300 Subject: [PATCH 12/12] Reduced time for message options --- client/stylesheets/base.less | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/stylesheets/base.less b/client/stylesheets/base.less index e11be9089ff..c44cd969208 100644 --- a/client/stylesheets/base.less +++ b/client/stylesheets/base.less @@ -2425,8 +2425,8 @@ a.github-fork { border-radius: 4px; overflow: hidden; box-shadow: 1px 1px 4px #B3B3B3; - transition: transform .3s ease-in-out, opacity .3s ease-in-out; - animation: dropdown-in .3s ease-in-out; + transition: transform .15s ease-in-out, opacity .15s ease-in-out; + animation: dropdown-in .15s ease-in-out; ul { display: flex;