diff --git a/packages/rocketchat-lib/client/MessageAction.coffee b/packages/rocketchat-lib/client/MessageAction.coffee
deleted file mode 100644
index 80837c3a0beb..000000000000
--- a/packages/rocketchat-lib/client/MessageAction.coffee
+++ /dev/null
@@ -1,247 +0,0 @@
-import moment from 'moment'
-import toastr from 'toastr'
-
-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
- return false
-
- 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
-
- getButtonById = (id) ->
- allButtons = buttons.get()
- return allButtons[id]
-
- getButtons = (message, context) ->
- allButtons = _.toArray buttons.get()
- if message
- allowedButtons = _.compact _.map allButtons, (button) ->
- if not button.context? or button.context.indexOf(context) > -1
- if not button.validation? or button.validation(message, context)
- return button
- else
- allowedButtons = allButtons
-
- return _.sortBy allowedButtons, 'order'
-
- resetButtons = ->
- buttons.set {}
-
- getPermaLink = (msgId) ->
- roomData = ChatSubscription.findOne({rid: Session.get('openedRoom')})
- if roomData
- routePath = RocketChat.roomTypes.getRouteLink(roomData.t, roomData)
- else
- routePath = document.location.pathname
- return Meteor.absoluteUrl().replace(/\/$/, '') + routePath + '?msg=' + msgId
-
- hideDropDown = () ->
- $('.message-dropdown:visible').hide()
-
- addButton: addButton
- removeButton: removeButton
- updateButton: updateButton
- getButtons: getButtons
- getButtonById: getButtonById
- resetButtons: resetButtons
- getPermaLink: getPermaLink
- hideDropDown: hideDropDown
-
-Meteor.startup ->
-
- $(document).click (event) =>
- target = $(event.target)
- if !target.closest('.message-cog-container').length and !target.is('.message-cog-container')
- RocketChat.MessageAction.hideDropDown()
-
- RocketChat.MessageAction.addButton
- id: 'reply-message'
- icon: 'icon-reply'
- i18nLabel: 'Reply'
- context: [
- 'message'
- 'message-mobile'
- ]
- action: (event, instance) ->
- message = @_arguments[1]
- input = instance.find('.input-message')
- url = RocketChat.MessageAction.getPermaLink(message._id)
- text = '[ ](' + url + ') @' + message.u.username + ' '
- if input.value
- input.value += if input.value.endsWith(' ') then '' else ' '
- input.value += text
- input.focus()
- RocketChat.MessageAction.hideDropDown()
- validation: (message) ->
- if not RocketChat.models.Subscriptions.findOne({ rid: message.rid })?
- return false
- return true
- order: 1
-
- RocketChat.MessageAction.addButton
- id: 'edit-message'
- icon: 'icon-pencil'
- i18nLabel: 'Edit'
- context: [
- 'message'
- 'message-mobile'
- ]
- action: (e, instance) ->
- message = $(e.currentTarget).closest('.message')[0]
- chatMessages[Session.get('openedRoom')].edit(message)
- RocketChat.MessageAction.hideDropDown()
- input = instance.find('.input-message')
- Meteor.setTimeout ->
- input.focus()
- input.updateAutogrow()
- , 200
- validation: (message) ->
- if not RocketChat.models.Subscriptions.findOne({ rid: message.rid })?
- return false
-
- hasPermission = RocketChat.authz.hasAtLeastOnePermission('edit-message', message.rid)
- isEditAllowed = RocketChat.settings.get 'Message_AllowEditing'
- editOwn = message.u?._id is Meteor.userId()
-
- return unless hasPermission or (isEditAllowed and editOwn)
-
- blockEditInMinutes = RocketChat.settings.get 'Message_AllowEditing_BlockEditInMinutes'
- if blockEditInMinutes? and blockEditInMinutes isnt 0
- msgTs = moment(message.ts) if message.ts?
- currentTsDiff = moment().diff(msgTs, 'minutes') if msgTs?
- return currentTsDiff < blockEditInMinutes
- else
- return true
- order: 2
-
- RocketChat.MessageAction.addButton
- id: 'delete-message'
- icon: 'icon-trash-alt'
- i18nLabel: 'Delete'
- context: [
- 'message'
- 'message-mobile'
- ]
- action: (event, instance) ->
- message = @_arguments[1]
- RocketChat.MessageAction.hideDropDown()
- chatMessages[Session.get('openedRoom')].confirmDeleteMsg(message)
- validation: (message) ->
- if not RocketChat.models.Subscriptions.findOne({ rid: message.rid })?
- return false
-
- hasPermission = RocketChat.authz.hasAtLeastOnePermission('delete-message', message.rid)
- isDeleteAllowed = RocketChat.settings.get 'Message_AllowDeleting'
- deleteOwn = message.u?._id is Meteor.userId()
-
- return unless hasPermission or (isDeleteAllowed and deleteOwn)
-
- blockDeleteInMinutes = RocketChat.settings.get 'Message_AllowDeleting_BlockDeleteInMinutes'
- if blockDeleteInMinutes? and blockDeleteInMinutes isnt 0
- msgTs = moment(message.ts) if message.ts?
- currentTsDiff = moment().diff(msgTs, 'minutes') if msgTs?
- return currentTsDiff < blockDeleteInMinutes
- else
- return true
- order: 3
-
- RocketChat.MessageAction.addButton
- id: 'permalink'
- icon: 'icon-link'
- i18nLabel: 'Permalink'
- classes: 'clipboard'
- context: [
- 'message'
- 'message-mobile'
- ]
- action: (event, instance) ->
- message = @_arguments[1]
- permalink = RocketChat.MessageAction.getPermaLink(message._id)
- RocketChat.MessageAction.hideDropDown()
- if Meteor.isCordova
- cordova.plugins.clipboard.copy(permalink);
- else
- $(event.currentTarget).attr('data-clipboard-text', permalink);
- toastr.success(TAPi18n.__('Copied'))
- validation: (message) ->
- if not RocketChat.models.Subscriptions.findOne({ rid: message.rid })?
- return false
-
- return true
- order: 4
-
- RocketChat.MessageAction.addButton
- id: 'copy'
- icon: 'icon-paste'
- i18nLabel: 'Copy'
- classes: 'clipboard'
- context: [
- 'message'
- 'message-mobile'
- ]
- action: (event, instance) ->
- message = @_arguments[1].msg
- RocketChat.MessageAction.hideDropDown()
- if Meteor.isCordova
- cordova.plugins.clipboard.copy(message);
- else
- $(event.currentTarget).attr('data-clipboard-text', message)
- toastr.success(TAPi18n.__('Copied'))
- validation: (message) ->
- if not RocketChat.models.Subscriptions.findOne({ rid: message.rid })?
- return false
-
- return true
- order: 5
-
- RocketChat.MessageAction.addButton
- id: 'quote-message'
- icon: 'icon-quote-left'
- i18nLabel: 'Quote'
- context: [
- 'message'
- 'message-mobile'
- ]
- action: (event, instance) ->
- message = @_arguments[1]
- input = instance.find('.input-message')
- url = RocketChat.MessageAction.getPermaLink(message._id)
- text = '[ ](' + url + ') '
- if input.value
- input.value += if input.value.endsWith(' ') then '' else ' '
- input.value += text
- input.focus()
- RocketChat.MessageAction.hideDropDown()
- validation: (message) ->
- if not RocketChat.models.Subscriptions.findOne({ rid: message.rid })?
- return false
-
- return true
- order: 6
diff --git a/packages/rocketchat-lib/client/MessageAction.js b/packages/rocketchat-lib/client/MessageAction.js
new file mode 100644
index 000000000000..db2ee342a494
--- /dev/null
+++ b/packages/rocketchat-lib/client/MessageAction.js
@@ -0,0 +1,287 @@
+import moment from 'moment';
+
+import toastr from 'toastr';
+
+RocketChat.MessageAction = new class {
+ /*
+ config expects the following keys (only id is mandatory):
+ id (mandatory)
+ icon: string
+ i18nLabel: string
+ action: function(event, instance)
+ validation: function(message)
+ order: integer
+ */
+
+ constructor() {
+ this.buttons = new ReactiveVar({});
+ }
+
+ addButton(config) {
+ if (!config || !config.id) {
+ return false;
+ }
+ return Tracker.nonreactive(() => {
+ const btns = this.buttons.get();
+ btns[config.id] = config;
+ return this.buttons.set(btns);
+ });
+ }
+
+ removeButton(id) {
+ return Tracker.nonreactive(() => {
+ const btns = this.buttons.get();
+ delete btns[id];
+ return this.buttons.set(btns);
+ });
+ }
+
+ updateButton(id, config) {
+ return Tracker.nonreactive(() => {
+ const btns = this.buttons.get();
+ if (btns[id]) {
+ btns[id] = _.extend(btns[id], config);
+ return this.buttons.set(btns);
+ }
+ });
+ }
+
+ getButtonById(id) {
+ const allButtons = this.buttons.get();
+ return allButtons[id];
+ }
+
+ getButtons(message, context) {
+ const allButtons = _.toArray(this.buttons.get());
+ let allowedButtons = allButtons;
+ if (message) {
+ allowedButtons = _.compact(_.map(allButtons, function(button) {
+ if (button.context == null || button.context.includes(context)) {
+ if (button.validation == null || button.validation(message, context)) {
+ return button;
+ }
+ }
+ }));
+ }
+ return _.sortBy(allowedButtons, 'order');
+ }
+
+ resetButtons() {
+ return this.buttons.set({});
+ }
+
+ getPermaLink(msgId) {
+ const roomData = ChatSubscription.findOne({
+ rid: Session.get('openedRoom')
+ });
+ let routePath = document.location.pathname;
+ if (roomData) {
+ routePath = RocketChat.roomTypes.getRouteLink(roomData.t, roomData);
+ }
+ return `${ Meteor.absoluteUrl().replace(/\/$/, '') + routePath }?msg=${ msgId }`;
+ }
+
+ hideDropDown() {
+ return $('.message-dropdown:visible').hide();
+ }
+};
+
+Meteor.startup(function() {
+ $(document).click((event) => {
+ const target = $(event.target);
+ if (!target.closest('.message-cog-container').length && !target.is('.message-cog-container')) {
+ return RocketChat.MessageAction.hideDropDown();
+ }
+ });
+
+ RocketChat.MessageAction.addButton({
+ id: 'reply-message',
+ icon: 'icon-reply',
+ i18nLabel: 'Reply',
+ context: ['message', 'message-mobile'],
+ action(event, instance) {
+ const message = this._arguments[1];
+ const input = instance.find('.input-message');
+ const url = RocketChat.MessageAction.getPermaLink(message._id);
+ const text = `[ ](${ url }) @${ message.u.username } `;
+ if (input.value) {
+ input.value += input.value.endsWith(' ') ? '' : ' ';
+ }
+ input.value += text;
+ input.focus();
+ return RocketChat.MessageAction.hideDropDown();
+ },
+ validation(message) {
+ if (RocketChat.models.Subscriptions.findOne({
+ rid: message.rid
+ }) == null) {
+ return false;
+ }
+ return true;
+ },
+ order: 1
+ });
+ /* globals chatMessages*/
+ RocketChat.MessageAction.addButton({
+ id: 'edit-message',
+ icon: 'icon-pencil',
+ i18nLabel: 'Edit',
+ context: ['message', 'message-mobile'],
+ action(e, instance) {
+ const message = $(e.currentTarget).closest('.message')[0];
+ chatMessages[Session.get('openedRoom')].edit(message);
+ RocketChat.MessageAction.hideDropDown();
+ const input = instance.find('.input-message');
+ Meteor.setTimeout(() => {
+ input.focus();
+ input.updateAutogrow();
+ }, 200);
+ },
+ validation(message) {
+ if (RocketChat.models.Subscriptions.findOne({
+ rid: message.rid
+ }) == null) {
+ return false;
+ }
+ const hasPermission = RocketChat.authz.hasAtLeastOnePermission('edit-message', message.rid);
+ const isEditAllowed = RocketChat.settings.get('Message_AllowEditing');
+ const editOwn = message.u && message.u._id === Meteor.userId();
+ if (!(hasPermission || (isEditAllowed && editOwn))) {
+ return;
+ }
+ const blockEditInMinutes = RocketChat.settings.get('Message_AllowEditing_BlockEditInMinutes');
+ if (blockEditInMinutes) {
+ let msgTs;
+ if (message.ts != null) {
+ msgTs = moment(message.ts);
+ }
+ let currentTsDiff;
+ if (msgTs != null) {
+ currentTsDiff = moment().diff(msgTs, 'minutes');
+ }
+ return currentTsDiff < blockEditInMinutes;
+ } else {
+ return true;
+ }
+ },
+ order: 2
+ });
+ RocketChat.MessageAction.addButton({
+ id: 'delete-message',
+ icon: 'icon-trash-alt',
+ i18nLabel: 'Delete',
+ context: ['message', 'message-mobile'],
+ action() {
+ const message = this._arguments[1];
+ RocketChat.MessageAction.hideDropDown();
+ return chatMessages[Session.get('openedRoom')].confirmDeleteMsg(message);
+ },
+ validation(message) {
+ if (RocketChat.models.Subscriptions.findOne({rid: message.rid}) == null) {
+ return false;
+ }
+ const hasPermission = RocketChat.authz.hasAtLeastOnePermission('delete-message', message.rid);
+ const isDeleteAllowed = RocketChat.settings.get('Message_AllowDeleting');
+ const deleteOwn = message.u && message.u._id === Meteor.userId();
+ if (!(hasPermission || (isDeleteAllowed && deleteOwn))) {
+ return;
+ }
+ const blockDeleteInMinutes = RocketChat.settings.get('Message_AllowDeleting_BlockDeleteInMinutes');
+ if ((blockDeleteInMinutes != null) && blockDeleteInMinutes !== 0) {
+ let msgTs;
+ if (message.ts != null) {
+ msgTs = moment(message.ts);
+ }
+ let currentTsDiff;
+ if (msgTs != null) {
+ currentTsDiff = moment().diff(msgTs, 'minutes');
+ }
+ return currentTsDiff < blockDeleteInMinutes;
+ } else {
+ return true;
+ }
+ },
+ order: 3
+ });
+ /* globals cordova*/
+ RocketChat.MessageAction.addButton({
+ id: 'permalink',
+ icon: 'icon-link',
+ i18nLabel: 'Permalink',
+ classes: 'clipboard',
+ context: ['message', 'message-mobile'],
+ action() {
+ const message = this._arguments[1];
+ const permalink = RocketChat.MessageAction.getPermaLink(message._id);
+ RocketChat.MessageAction.hideDropDown();
+ if (Meteor.isCordova) {
+ cordova.plugins.clipboard.copy(permalink);
+ } else {
+ $(event.currentTarget).attr('data-clipboard-text', permalink);
+ }
+ return toastr.success(TAPi18n.__('Copied'));
+ },
+ validation(message) {
+ if (RocketChat.models.Subscriptions.findOne({
+ rid: message.rid
+ }) == null) {
+ return false;
+ }
+ return true;
+ },
+ order: 4
+ });
+ RocketChat.MessageAction.addButton({
+ id: 'copy',
+ icon: 'icon-paste',
+ i18nLabel: 'Copy',
+ classes: 'clipboard',
+ context: ['message', 'message-mobile'],
+ action() {
+ const message = this._arguments[1].msg;
+ RocketChat.MessageAction.hideDropDown();
+ if (Meteor.isCordova) {
+ cordova.plugins.clipboard.copy(message);
+ } else {
+ $(event.currentTarget).attr('data-clipboard-text', message);
+ }
+ return toastr.success(TAPi18n.__('Copied'));
+ },
+ validation(message) {
+ if (RocketChat.models.Subscriptions.findOne({
+ rid: message.rid
+ }) == null) {
+ return false;
+ }
+ return true;
+ },
+ order: 5
+ });
+ return RocketChat.MessageAction.addButton({
+ id: 'quote-message',
+ icon: 'icon-quote-left',
+ i18nLabel: 'Quote',
+ context: ['message', 'message-mobile'],
+ action(event, instance) {
+ const message = this._arguments[1];
+ const input = instance.find('.input-message');
+ const url = RocketChat.MessageAction.getPermaLink(message._id);
+ const text = `[ ](${ url }) `;
+ if (input.value) {
+ input.value += input.value.endsWith(' ') ? '' : ' ';
+ }
+ input.value += text;
+ input.focus();
+ return RocketChat.MessageAction.hideDropDown();
+ },
+ validation(message) {
+ if (RocketChat.models.Subscriptions.findOne({
+ rid: message.rid
+ }) == null) {
+ return false;
+ }
+ return true;
+ },
+ order: 6
+ });
+});
diff --git a/packages/rocketchat-lib/client/Notifications.coffee b/packages/rocketchat-lib/client/Notifications.coffee
deleted file mode 100644
index 9a51ceca3482..000000000000
--- a/packages/rocketchat-lib/client/Notifications.coffee
+++ /dev/null
@@ -1,72 +0,0 @@
-RocketChat.Notifications = new class
- constructor: ->
- @logged = Meteor.userId() isnt null
- @loginCb = []
- Tracker.autorun =>
- if Meteor.userId() isnt null and this.logged is false
- cb() for cb in this.loginCb
-
- @logged = Meteor.userId() isnt null
-
- @debug = false
- @streamAll = new Meteor.Streamer 'notify-all'
- @streamLogged = new Meteor.Streamer 'notify-logged'
- @streamRoom = new Meteor.Streamer 'notify-room'
- @streamRoomUsers = new Meteor.Streamer 'notify-room-users'
- @streamUser = new Meteor.Streamer 'notify-user'
-
- if @debug is true
- @onAll -> console.log "RocketChat.Notifications: onAll", arguments
- @onUser -> console.log "RocketChat.Notifications: onAll", arguments
-
- onLogin: (cb) ->
- @loginCb.push(cb)
- if @logged
- cb()
-
- notifyRoom: (room, eventName, args...) ->
- console.log "RocketChat.Notifications: notifyRoom", arguments if @debug is true
-
- args.unshift "#{room}/#{eventName}"
- @streamRoom.emit.apply @streamRoom, args
-
- notifyUser: (userId, eventName, args...) ->
- console.log "RocketChat.Notifications: notifyUser", arguments if @debug is true
-
- args.unshift "#{userId}/#{eventName}"
- @streamUser.emit.apply @streamUser, args
-
- notifyUsersOfRoom: (room, eventName, args...) ->
- console.log "RocketChat.Notifications: notifyUsersOfRoom", arguments if @debug is true
-
- args.unshift "#{room}/#{eventName}"
- @streamRoomUsers.emit.apply @streamRoomUsers, args
-
- onAll: (eventName, callback) ->
- @streamAll.on eventName, callback
-
- onLogged: (eventName, callback) ->
- @onLogin =>
- @streamLogged.on eventName, callback
-
- onRoom: (room, eventName, callback) ->
- if @debug is true
- @streamRoom.on room, -> console.log "RocketChat.Notifications: onRoom #{room}", arguments
-
- @streamRoom.on "#{room}/#{eventName}", callback
-
- onUser: (eventName, callback) ->
- @streamUser.on "#{Meteor.userId()}/#{eventName}", callback
-
-
- unAll: (callback) ->
- @streamAll.removeListener 'notify', callback
-
- unLogged: (callback) ->
- @streamLogged.removeListener 'notify', callback
-
- unRoom: (room, eventName, callback) ->
- @streamRoom.removeListener "#{room}/#{eventName}", callback
-
- unUser: (callback) ->
- @streamUser.removeListener Meteor.userId(), callback
diff --git a/packages/rocketchat-lib/client/Notifications.js b/packages/rocketchat-lib/client/Notifications.js
new file mode 100644
index 000000000000..4a474c9aec24
--- /dev/null
+++ b/packages/rocketchat-lib/client/Notifications.js
@@ -0,0 +1,86 @@
+RocketChat.Notifications = new class {
+ constructor() {
+ this.logged = Meteor.userId() !== null;
+ this.loginCb = [];
+ Tracker.autorun(() => {
+ if (Meteor.userId() !== null && this.logged === false) {
+ this.loginCb.forEach(cb => cb());
+ }
+ return this.logged = Meteor.userId() !== null;
+ });
+ this.debug = false;
+ this.streamAll = new Meteor.Streamer('notify-all');
+ this.streamLogged = new Meteor.Streamer('notify-logged');
+ this.streamRoom = new Meteor.Streamer('notify-room');
+ this.streamRoomUsers = new Meteor.Streamer('notify-room-users');
+ this.streamUser = new Meteor.Streamer('notify-user');
+ if (this.debug === true) {
+ this.onAll(function() {
+ return console.log('RocketChat.Notifications: onAll', arguments);
+ });
+ this.onUser(function() {
+ return console.log('RocketChat.Notifications: onAll', arguments);
+ });
+ }
+ }
+
+ onLogin(cb) {
+ this.loginCb.push(cb);
+ if (this.logged) {
+ return cb();
+ }
+ }
+ notifyRoom(room, eventName, ...args) {
+ if (this.debug === true) {
+ console.log('RocketChat.Notifications: notifyRoom', arguments);
+ }
+ args.unshift(`${ room }/${ eventName }`);
+ return this.streamRoom.emit.apply(this.streamRoom, args);
+ }
+ notifyUser(userId, eventName, ...args) {
+ if (this.debug === true) {
+ console.log('RocketChat.Notifications: notifyUser', arguments);
+ }
+ args.unshift(`${ userId }/${ eventName }`);
+ return this.streamUser.emit.apply(this.streamUser, args);
+ }
+ notifyUsersOfRoom(room, eventName, ...args) {
+ if (this.debug === true) {
+ console.log('RocketChat.Notifications: notifyUsersOfRoom', arguments);
+ }
+ args.unshift(`${ room }/${ eventName }`);
+ return this.streamRoomUsers.emit.apply(this.streamRoomUsers, args);
+ }
+ onAll(eventName, callback) {
+ return this.streamAll.on(eventName, callback);
+ }
+ onLogged(eventName, callback) {
+ return this.onLogin(() => {
+ return this.streamLogged.on(eventName, callback);
+ });
+ }
+ onRoom(room, eventName, callback) {
+ if (this.debug === true) {
+ this.streamRoom.on(room, function() {
+ return console.log(`RocketChat.Notifications: onRoom ${ room }`, arguments);
+ });
+ }
+ return this.streamRoom.on(`${ room }/${ eventName }`, callback);
+ }
+ onUser(eventName, callback) {
+ return this.streamUser.on(`${ Meteor.userId() }/${ eventName }`, callback);
+ }
+ unAll(callback) {
+ return this.streamAll.removeListener('notify', callback);
+ }
+ unLogged(callback) {
+ return this.streamLogged.removeListener('notify', callback);
+ }
+ unRoom(room, eventName, callback) {
+ return this.streamRoom.removeListener(`${ room }/${ eventName }`, callback);
+ }
+ unUser(callback) {
+ return this.streamUser.removeListener(Meteor.userId(), callback);
+ }
+
+};
diff --git a/packages/rocketchat-lib/client/lib/openRoom.js b/packages/rocketchat-lib/client/lib/openRoom.js
new file mode 100644
index 000000000000..b283b51c08ab
--- /dev/null
+++ b/packages/rocketchat-lib/client/lib/openRoom.js
@@ -0,0 +1,98 @@
+/* globals fireGlobalEvent readMessage currentTracker*/
+currentTracker = undefined;
+
+function openRoom(type, name) {
+ Session.set('openedRoom', null);
+
+ return Meteor.defer(() =>
+ currentTracker = Tracker.autorun(function(c) {
+ const user = Meteor.user();
+ if ((user && user.username == null) || user == null && RocketChat.settings.get('Accounts_AllowAnonymousAccess') === false) {
+ BlazeLayout.render('main');
+ return;
+ }
+
+ if (RoomManager.open(type + name).ready() !== true) {
+ BlazeLayout.render('main', { modal: RocketChat.Layout.isEmbedded(), center: 'loading' });
+ return;
+ }
+ if (currentTracker) {
+ currentTracker = undefined;
+ }
+ c.stop();
+
+ const room = RocketChat.roomTypes.findRoom(type, name, user);
+ if (room == null) {
+ if (type === 'd') {
+ Meteor.call('createDirectMessage', name, function(err) {
+ if (!err) {
+ RoomManager.close(type + name);
+ return openRoom('d', name);
+ } else {
+ Session.set('roomNotFound', {type, name});
+ BlazeLayout.render('main', {center: 'roomNotFound'});
+ return;
+ }
+ });
+ } else {
+ Meteor.call('getRoomByTypeAndName', type, name, function(err, record) {
+ if (err) {
+ Session.set('roomNotFound', {type, name});
+ return BlazeLayout.render('main', {center: 'roomNotFound'});
+ } else {
+ delete record.$loki;
+ RocketChat.models.Rooms.upsert({ _id: record._id }, _.omit(record, '_id'));
+ RoomManager.close(type + name);
+ return openRoom(type, name);
+ }
+ });
+ }
+ return;
+ }
+
+ const mainNode = document.querySelector('.main-content');
+ if (mainNode) {
+ for (const child of Array.from(mainNode.children)) {
+ if (child) { mainNode.removeChild(child); }
+ }
+ const roomDom = RoomManager.getDomOfRoom(type + name, room._id);
+ mainNode.appendChild(roomDom);
+ if (roomDom.classList.contains('room-container')) {
+ roomDom.querySelector('.messages-box > .wrapper').scrollTop = roomDom.oldScrollTop;
+ }
+ }
+
+ Session.set('openedRoom', room._id);
+
+ fireGlobalEvent('room-opened', _.omit(room, 'usernames'));
+
+ Session.set('editRoomTitle', false);
+ RoomManager.updateMentionsMarksOfRoom(type + name);
+ Meteor.setTimeout(() => readMessage.readNow(), 2000);
+ // KonchatNotification.removeRoomNotification(params._id)
+
+ if (Meteor.Device.isDesktop() && window.chatMessages && window.chatMessages[room._id] != null) {
+ setTimeout(() => $('.message-form .input-message').focus(), 100);
+ }
+
+ // update user's room subscription
+ const sub = ChatSubscription.findOne({rid: room._id});
+ if (sub && sub.open === false) {
+ Meteor.call('openRoom', room._id, function(err) {
+ if (err) {
+ return handleError(err);
+ }
+ });
+ }
+
+ if (FlowRouter.getQueryParam('msg')) {
+ const msg = { _id: FlowRouter.getQueryParam('msg'), rid: room._id };
+ RoomHistoryManager.getSurroundingMessages(msg);
+ }
+
+ return RocketChat.callbacks.run('enter-room', sub);
+ })
+ );
+}
+export { openRoom };
+this.openRoom = openRoom;
diff --git a/packages/rocketchat-lib/client/lib/roomExit.coffee b/packages/rocketchat-lib/client/lib/roomExit.coffee
deleted file mode 100644
index d7da9ed4a871..000000000000
--- a/packages/rocketchat-lib/client/lib/roomExit.coffee
+++ /dev/null
@@ -1,20 +0,0 @@
-@roomExit = ->
- RocketChat.callbacks.run 'roomExit'
-
- BlazeLayout.render 'main', {center: 'none'}
-
- if currentTracker?
- currentTracker.stop()
-
- mainNode = document.querySelector('.main-content')
- if mainNode?
- for child in mainNode.children
- if child?
- if child.classList.contains('room-container')
- wrapper = child.querySelector('.messages-box > .wrapper')
- if wrapper
- if wrapper.scrollTop >= wrapper.scrollHeight - wrapper.clientHeight
- child.oldScrollTop = 10e10
- else
- child.oldScrollTop = wrapper.scrollTop
- mainNode.removeChild child
diff --git a/packages/rocketchat-lib/client/lib/roomExit.js b/packages/rocketchat-lib/client/lib/roomExit.js
new file mode 100644
index 000000000000..36f1260e3420
--- /dev/null
+++ b/packages/rocketchat-lib/client/lib/roomExit.js
@@ -0,0 +1,31 @@
+/*globals currentTracker */
+this.roomExit = function() {
+ RocketChat.callbacks.run('roomExit');
+ BlazeLayout.render('main', {
+ center: 'none'
+ });
+
+ if (typeof currentTracker !== 'undefined') {
+ currentTracker.stop();
+ }
+ const mainNode = document.querySelector('.main-content');
+ if (mainNode == null) {
+ return;
+ }
+ return [...mainNode.children].forEach(child => {
+ if (child == null) {
+ return;
+ }
+ if (child.classList.contains('room-container')) {
+ const wrapper = child.querySelector('.messages-box > .wrapper');
+ if (wrapper) {
+ if (wrapper.scrollTop >= wrapper.scrollHeight - wrapper.clientHeight) {
+ child.oldScrollTop = 10e10;
+ } else {
+ child.oldScrollTop = wrapper.scrollTop;
+ }
+ }
+ }
+ mainNode.removeChild(child);
+ });
+};
diff --git a/packages/rocketchat-lib/client/lib/roomTypes.coffee b/packages/rocketchat-lib/client/lib/roomTypes.coffee
deleted file mode 100644
index afe19195bf91..000000000000
--- a/packages/rocketchat-lib/client/lib/roomTypes.coffee
+++ /dev/null
@@ -1,90 +0,0 @@
-RocketChat.roomTypes = new class roomTypesClient extends roomTypesCommon
- checkCondition: (roomType) ->
- return not roomType.condition? or roomType.condition()
-
- getTypes: ->
- orderedTypes = []
-
- _.sortBy(@roomTypesOrder, 'order').forEach (type) =>
- orderedTypes.push @roomTypes[type.identifier]
-
- return orderedTypes
-
- getIcon: (roomType) ->
- return @roomTypes[roomType]?.icon
-
- getRoomName: (roomType, roomData) ->
- return @roomTypes[roomType]?.roomName roomData
-
- getSecondaryRoomName: (roomType, roomData) ->
- return @roomTypes[roomType]?.secondaryRoomName?(roomData)
-
- getIdentifiers: (except) ->
- except = [].concat except
- list = _.reject @roomTypesOrder, (t) -> return except.indexOf(t.identifier) isnt -1
- return _.map list, (t) -> return t.identifier
-
- getUserStatus: (roomType, roomId) ->
- return @roomTypes[roomType]?.getUserStatus?(roomId)
-
- findRoom: (roomType, identifier, user) ->
- return @roomTypes[roomType]?.findRoom identifier, user
-
- canSendMessage: (roomId) ->
- return ChatSubscription.find({ rid: roomId }).count() > 0
-
- readOnly: (roomId, user) ->
-
- fields = { ro: 1 }
-
- # if a user has been specified then we want to see if that user has been muted in the room
- if user
- fields.muted = 1
-
- room = ChatRoom.findOne({ _id: roomId }, fields : fields)
-
- unless user
- return room?.ro;
-
- userOwner = RoomRoles.findOne({ rid: roomId, "u._id": user._id, roles: 'owner' }, { fields: { _id: 1 } })
-
- return room?.ro is true and Array.isArray(room?.muted) and room?.muted.indexOf(user.username) != -1 and !userOwner
-
- archived: (roomId) ->
- fields = { archived: 1 }
-
- room = ChatRoom.findOne({ _id: roomId }, fields : fields)
-
- return room?.archived is true
-
- verifyCanSendMessage: (roomId) ->
- room = ChatRoom.findOne({ _id: roomId }, { fields: { t: 1 } })
- return if not room?.t?
-
- roomType = room.t
-
- return @roomTypes[roomType]?.canSendMessage roomId if @roomTypes[roomType]?.canSendMessage?
-
- return @canSendMessage roomId
-
- verifyShowJoinLink: (roomId) ->
- room = ChatRoom.findOne({ _id: roomId }, { fields: { t: 1 } })
- return if not room?.t?
-
- roomType = room.t
-
- if not @roomTypes[roomType]?.showJoinLink?
- return false
-
- return @roomTypes[roomType].showJoinLink roomId
-
- getNotSubscribedTpl: (roomId) ->
- room = ChatRoom.findOne({ _id: roomId }, { fields: { t: 1 } })
- return if not room?.t?
-
- roomType = room.t
-
- if not @roomTypes[roomType]?.notSubscribedTpl?
- return false
-
- return @roomTypes[roomType].notSubscribedTpl
diff --git a/packages/rocketchat-lib/client/lib/roomTypes.js b/packages/rocketchat-lib/client/lib/roomTypes.js
new file mode 100644
index 000000000000..9cfc41585961
--- /dev/null
+++ b/packages/rocketchat-lib/client/lib/roomTypes.js
@@ -0,0 +1,115 @@
+import roomTypesCommon from '../../lib/roomTypesCommon';
+
+RocketChat.roomTypes = new class extends roomTypesCommon {
+ checkCondition(roomType) {
+ return roomType.condition == null || roomType.condition();
+ }
+ getTypes() {
+ return _.sortBy(this.roomTypesOrder, 'order').map((type) => this.roomTypes[type.identifier]);
+ }
+ getIcon(roomType) {
+ return this.roomTypes[roomType] && this.roomTypes[roomType].icon;
+ }
+ getRoomName(roomType, roomData) {
+ return this.roomTypes[roomType] && this.roomTypes[roomType].roomName && this.roomTypes[roomType].roomName(roomData);
+ }
+ getSecondaryRoomName(roomType, roomData) {
+ return this.roomTypes[roomType] && typeof this.roomTypes[roomType].secondaryRoomName === 'function' && this.roomTypes[roomType].secondaryRoomName(roomData);
+ }
+ getIdentifiers(e) {
+ const except = [].concat(e);
+ const list = _.reject(this.roomTypesOrder, (t) => except.indexOf(t.identifier) !== -1);
+ return _.map(list, (t) => t.identifier);
+ }
+ getUserStatus(roomType, roomId) {
+ this.roomTypes[roomType] && typeof this.roomTypes[roomType].getUserStatus === 'function' && this.roomTypes[roomType].getUserStatus(roomId);
+ }
+ findRoom(roomType, identifier, user) {
+ return this.roomTypes[roomType] && this.roomTypes[roomType].findRoom(identifier, user);
+ }
+ canSendMessage(roomId) {
+ return ChatSubscription.find({
+ rid: roomId
+ }).count() > 0;
+ }
+ readOnly(roomId, user) {
+ const fields = {
+ ro: 1
+ };
+ if (user) {
+ fields.muted = 1;
+ }
+ const room = ChatRoom.findOne({
+ _id: roomId
+ }, {
+ fields
+ });
+ if (!user) {
+ return room && room.ro;
+ }
+ /* globals RoomRoles */
+ const userOwner = RoomRoles.findOne({
+ rid: roomId,
+ 'u._id': user._id,
+ roles: 'owner'
+ }, {
+ fields: {
+ _id: 1
+ }
+ });
+ return room && (room.ro === true && Array.isArray(room.muted) && room.muted.indexOf(user.username) !== -1 && !userOwner);
+ }
+ archived(roomId) {
+ const fields = {
+ archived: 1
+ };
+ const room = ChatRoom.findOne({
+ _id: roomId
+ }, {
+ fields
+ });
+ return room && room.archived === true;
+ }
+ verifyCanSendMessage(roomId) {
+ const room = ChatRoom.findOne({ _id: roomId }, { fields: { t: 1 }});
+
+ if (!room || !room.t) {
+ return;
+ }
+
+ const roomType = room.t;
+ if (this.roomTypes[roomType] && this.roomTypes[roomType].canSendMessage) {
+ return this.roomTypes[roomType].canSendMessage(roomId);
+ }
+ return this.canSendMessage(roomId);
+ }
+ verifyShowJoinLink(roomId) {
+ const room = ChatRoom.findOne({
+ _id: roomId
+ }, {
+ fields: {
+ t: 1
+ }
+ });
+ if (!room || !room.t) {
+ return;
+ }
+ const roomType = room.t;
+ if (this.roomTypes[roomType] && !this.roomTypes[roomType].showJoinLink) {
+ return false;
+ }
+ return this.roomTypes[roomType].showJoinLink(roomId);
+ }
+ getNotSubscribedTpl(roomId) {
+ const room = ChatRoom.findOne({ _id: roomId }, { fields: { t: 1 }});
+ if (!room || !room.t) {
+ return;
+ }
+ const roomType = room.t;
+ if (this.roomTypes[roomType] && !this.roomTypes[roomType].notSubscribedTpl) {
+ return false;
+ }
+ return this.roomTypes[roomType].notSubscribedTpl;
+ }
+
+};
diff --git a/packages/rocketchat-lib/client/lib/settings.coffee b/packages/rocketchat-lib/client/lib/settings.coffee
deleted file mode 100644
index 38c08e546ba2..000000000000
--- a/packages/rocketchat-lib/client/lib/settings.coffee
+++ /dev/null
@@ -1,65 +0,0 @@
-###
-# RocketChat.settings holds all packages settings
-# @namespace RocketChat.settings
-###
-
-RocketChat.settings.cachedCollection = new RocketChat.CachedCollection({ name: 'public-settings', eventType: 'onAll', userRelated: false })
-RocketChat.settings.collection = RocketChat.settings.cachedCollection.collection
-RocketChat.settings.cachedCollection.init()
-
-RocketChat.settings.dict = new ReactiveDict 'settings'
-
-RocketChat.settings.get = (_id) ->
- return RocketChat.settings.dict.get(_id)
-
-RocketChat.settings.init = ->
- initialLoad = true
- RocketChat.settings.collection.find().observe
- added: (record) ->
- Meteor.settings[record._id] = record.value
- RocketChat.settings.dict.set record._id, record.value
- RocketChat.settings.load record._id, record.value, initialLoad
- changed: (record) ->
- Meteor.settings[record._id] = record.value
- RocketChat.settings.dict.set record._id, record.value
- RocketChat.settings.load record._id, record.value, initialLoad
- removed: (record) ->
- delete Meteor.settings[record._id]
- RocketChat.settings.dict.set record._id, undefined
- RocketChat.settings.load record._id, undefined, initialLoad
- initialLoad = false
-
-RocketChat.settings.init()
-
-Meteor.startup ->
- if Meteor.isCordova is false
- Tracker.autorun (c) ->
- siteUrl = RocketChat.settings.get('Site_Url')
- if not siteUrl or not Meteor.userId()?
- return
-
- if RocketChat.authz.hasRole(Meteor.userId(), 'admin') is false or Meteor.settings.public.sandstorm
- return c.stop()
-
- Meteor.setTimeout ->
- if __meteor_runtime_config__.ROOT_URL isnt location.origin
- currentUrl = location.origin + __meteor_runtime_config__.ROOT_URL_PATH_PREFIX
- swal
- type: 'warning'
- title: t('Warning')
- text: t("The_setting_s_is_configured_to_s_and_you_are_accessing_from_s", t('Site_Url'), siteUrl, currentUrl) + '
' + t("Do_you_want_to_change_to_s_question", currentUrl)
- showCancelButton: true
- confirmButtonText: t('Yes')
- cancelButtonText: t('Cancel')
- closeOnConfirm: false
- html: true
- , ->
- Meteor.call 'saveSetting', 'Site_Url', currentUrl, ->
- swal
- title: t('Saved')
- type: 'success'
- timer: 1000
- showConfirmButton: false
- , 100
-
- return c.stop()
diff --git a/packages/rocketchat-lib/client/lib/settings.js b/packages/rocketchat-lib/client/lib/settings.js
new file mode 100644
index 000000000000..0f0c946ecd81
--- /dev/null
+++ b/packages/rocketchat-lib/client/lib/settings.js
@@ -0,0 +1,87 @@
+
+/*
+* RocketChat.settings holds all packages settings
+* @namespace RocketChat.settings
+*/
+
+/* globals ReactiveDict*/
+
+RocketChat.settings.cachedCollection = new RocketChat.CachedCollection({
+ name: 'public-settings',
+ eventType: 'onAll',
+ userRelated: false
+});
+
+RocketChat.settings.collection = RocketChat.settings.cachedCollection.collection;
+
+RocketChat.settings.cachedCollection.init();
+
+RocketChat.settings.dict = new ReactiveDict('settings');
+
+RocketChat.settings.get = function(_id) {
+ return RocketChat.settings.dict.get(_id);
+};
+
+RocketChat.settings.init = function() {
+ let initialLoad = true;
+ RocketChat.settings.collection.find().observe({
+ added(record) {
+ Meteor.settings[record._id] = record.value;
+ RocketChat.settings.dict.set(record._id, record.value);
+ return RocketChat.settings.load(record._id, record.value, initialLoad);
+ },
+ changed(record) {
+ Meteor.settings[record._id] = record.value;
+ RocketChat.settings.dict.set(record._id, record.value);
+ return RocketChat.settings.load(record._id, record.value, initialLoad);
+ },
+ removed(record) {
+ delete Meteor.settings[record._id];
+ RocketChat.settings.dict.set(record._id, null);
+ return RocketChat.settings.load(record._id, null, initialLoad);
+ }
+ });
+ return initialLoad = false;
+};
+
+RocketChat.settings.init();
+
+Meteor.startup(function() {
+ if (Meteor.isCordova === true) {
+ return;
+ }
+ Tracker.autorun(function(c) {
+ const siteUrl = RocketChat.settings.get('Site_Url');
+ if (!siteUrl || (Meteor.userId() == null)) {
+ return;
+ }
+ if (RocketChat.authz.hasRole(Meteor.userId(), 'admin') === false || Meteor.settings['public'].sandstorm) {
+ return c.stop();
+ }
+ Meteor.setTimeout(function() {
+ if (__meteor_runtime_config__.ROOT_URL !== location.origin) {
+ const currentUrl = location.origin + __meteor_runtime_config__.ROOT_URL_PATH_PREFIX;
+ swal({
+ type: 'warning',
+ title: t('Warning'),
+ text: `${ t('The_setting_s_is_configured_to_s_and_you_are_accessing_from_s', t('Site_Url'), siteUrl, currentUrl) }
${ t('Do_you_want_to_change_to_s_question', currentUrl) }`,
+ showCancelButton: true,
+ confirmButtonText: t('Yes'),
+ cancelButtonText: t('Cancel'),
+ closeOnConfirm: false,
+ html: true
+ }, function() {
+ Meteor.call('saveSetting', 'Site_Url', currentUrl, function() {
+ swal({
+ title: t('Saved'),
+ type: 'success',
+ timer: 1000,
+ showConfirmButton: false
+ });
+ });
+ });
+ }
+ }, 100);
+ return c.stop();
+ });
+});
diff --git a/packages/rocketchat-lib/client/methods/sendMessage.coffee b/packages/rocketchat-lib/client/methods/sendMessage.coffee
deleted file mode 100644
index 68cb0a2f8c6e..000000000000
--- a/packages/rocketchat-lib/client/methods/sendMessage.coffee
+++ /dev/null
@@ -1,26 +0,0 @@
-Meteor.methods
- sendMessage: (message) ->
- if not Meteor.userId()
- return false
-
- if _.trim(message.msg) isnt ''
- if isNaN(TimeSync.serverOffset())
- message.ts = new Date()
- else
- message.ts = new Date(Date.now() + TimeSync.serverOffset())
-
- user = Meteor.user()
- message.u =
- _id: Meteor.userId()
- username: user.username
-
- if RocketChat.settings.get('UI_Use_Real_Name')
- message.u.name = user.name
-
- message.temp = true
-
- message = RocketChat.callbacks.run 'beforeSaveMessage', message
-
- RocketChat.promises.run('onClientMessageReceived', message).then (message) ->
- ChatMessage.insert message
- RocketChat.callbacks.run 'afterSaveMessage', message
diff --git a/packages/rocketchat-lib/client/methods/sendMessage.js b/packages/rocketchat-lib/client/methods/sendMessage.js
new file mode 100644
index 000000000000..85cce415c2a8
--- /dev/null
+++ b/packages/rocketchat-lib/client/methods/sendMessage.js
@@ -0,0 +1,22 @@
+Meteor.methods({
+ sendMessage(message) {
+ if (!Meteor.userId() || _.trim(message.msg) === '') {
+ return false;
+ }
+ const user = Meteor.user();
+ message.ts = isNaN(TimeSync.serverOffset()) ? new Date() : new Date(Date.now() + TimeSync.serverOffset());
+ message.u = {
+ _id: Meteor.userId(),
+ username: user.username
+ };
+ if (RocketChat.settings.get('UI_Use_Real_Name')) {
+ message.u.name = user.name;
+ }
+ message.temp = true;
+ message = RocketChat.callbacks.run('beforeSaveMessage', message);
+ RocketChat.promises.run('onClientMessageReceived', message).then(function(message) {
+ ChatMessage.insert(message);
+ return RocketChat.callbacks.run('afterSaveMessage', message);
+ });
+ }
+});
diff --git a/packages/rocketchat-lib/client/models/Uploads.coffee b/packages/rocketchat-lib/client/models/Uploads.coffee
deleted file mode 100644
index 4572e735b99b..000000000000
--- a/packages/rocketchat-lib/client/models/Uploads.coffee
+++ /dev/null
@@ -1,3 +0,0 @@
-RocketChat.models.Uploads = new class extends RocketChat.models._Base
- constructor: ->
- @_initModel 'uploads'
diff --git a/packages/rocketchat-lib/client/models/Uploads.js b/packages/rocketchat-lib/client/models/Uploads.js
new file mode 100644
index 000000000000..eefe630c708c
--- /dev/null
+++ b/packages/rocketchat-lib/client/models/Uploads.js
@@ -0,0 +1,7 @@
+
+RocketChat.models.Uploads = new class extends RocketChat.models._Base {
+ constructor() {
+ super();
+ this._initModel('uploads');
+ }
+};
diff --git a/packages/rocketchat-lib/client/models/_Base.coffee b/packages/rocketchat-lib/client/models/_Base.coffee
deleted file mode 100644
index fb485723241a..000000000000
--- a/packages/rocketchat-lib/client/models/_Base.coffee
+++ /dev/null
@@ -1,44 +0,0 @@
-RocketChat.models._Base = class
- _baseName: ->
- return 'rocketchat_'
-
- _initModel: (name) ->
- check name, String
-
- @model = new Mongo.Collection @_baseName() + name
-
- find: ->
- return @model.find.apply @model, arguments
-
- findOne: ->
- return @model.findOne.apply @model, arguments
-
- insert: ->
- return @model.insert.apply @model, arguments
-
- update: ->
- return @model.update.apply @model, arguments
-
- upsert: ->
- return @model.upsert.apply @model, arguments
-
- remove: ->
- return @model.remove.apply @model, arguments
-
- allow: ->
- return @model.allow.apply @model, arguments
-
- deny: ->
- return @model.deny.apply @model, arguments
-
- ensureIndex: ->
- return
-
- dropIndex: ->
- return
-
- tryEnsureIndex: ->
- return
-
- tryDropIndex: ->
- return
diff --git a/packages/rocketchat-lib/client/models/_Base.js b/packages/rocketchat-lib/client/models/_Base.js
new file mode 100644
index 000000000000..55623317be66
--- /dev/null
+++ b/packages/rocketchat-lib/client/models/_Base.js
@@ -0,0 +1,52 @@
+RocketChat.models._Base = class {
+
+ _baseName() {
+ return 'rocketchat_';
+ }
+
+ _initModel(name) {
+ check(name, String);
+ return this.model = new Mongo.Collection(this._baseName() + name);
+ }
+
+ find() {
+ return this.model.find.apply(this.model, arguments);
+ }
+
+ findOne() {
+ return this.model.findOne.apply(this.model, arguments);
+ }
+
+ insert() {
+ return this.model.insert.apply(this.model, arguments);
+ }
+
+ update() {
+ return this.model.update.apply(this.model, arguments);
+ }
+
+ upsert() {
+ return this.model.upsert.apply(this.model, arguments);
+ }
+
+ remove() {
+ return this.model.remove.apply(this.model, arguments);
+ }
+
+ allow() {
+ return this.model.allow.apply(this.model, arguments);
+ }
+
+ deny() {
+ return this.model.deny.apply(this.model, arguments);
+ }
+
+ ensureIndex() {}
+
+ dropIndex() {}
+
+ tryEnsureIndex() {}
+
+ tryDropIndex() {}
+
+};
diff --git a/packages/rocketchat-lib/lib/callbacks.coffee b/packages/rocketchat-lib/lib/callbacks.coffee
deleted file mode 100644
index d0e3feb8ff32..000000000000
--- a/packages/rocketchat-lib/lib/callbacks.coffee
+++ /dev/null
@@ -1,129 +0,0 @@
-# https://github.com/TelescopeJS/Telescope/blob/master/packages/telescope-lib/lib/callbacks.js
-
-###
-# Callback hooks provide an easy way to add extra steps to common operations.
-# @namespace RocketChat.callbacks
-###
-RocketChat.callbacks = {}
-
-if Meteor.isServer
- RocketChat.callbacks.showTime = true
- RocketChat.callbacks.showTotalTime = true
-else
- RocketChat.callbacks.showTime = false
- RocketChat.callbacks.showTotalTime = false
-
-###
-# Callback priorities
-###
-RocketChat.callbacks.priority =
- HIGH: -1000
- MEDIUM: 0
- LOW: 1000
-
-###
-# Add a callback function to a hook
-# @param {String} hook - The name of the hook
-# @param {Function} callback - The callback function
-###
-RocketChat.callbacks.add = (hook, callback, priority, id) ->
- # if callback array doesn't exist yet, initialize it
- priority ?= RocketChat.callbacks.priority.MEDIUM
- unless _.isNumber priority
- priority = RocketChat.callbacks.priority.MEDIUM
- callback.priority = priority
- callback.id = id or Random.id()
- RocketChat.callbacks[hook] ?= []
-
- if RocketChat.callbacks.showTime is true
- err = new Error
- callback.stack = err.stack
-
- # if not id?
- # console.log('Callback without id', callback.stack)
-
- # Avoid adding the same callback twice
- for cb in RocketChat.callbacks[hook]
- if cb.id is callback.id
- return
-
- RocketChat.callbacks[hook].push callback
- return
-
-###
-# Remove a callback from a hook
-# @param {string} hook - The name of the hook
-# @param {string} id - The callback's id
-###
-
-RocketChat.callbacks.remove = (hookName, id) ->
- RocketChat.callbacks[hookName] = _.reject RocketChat.callbacks[hookName], (callback) ->
- callback.id is id
- return
-
-###
-# Successively run all of a hook's callbacks on an item
-# @param {String} hook - The name of the hook
-# @param {Object} item - The post, comment, modifier, etc. on which to run the callbacks
-# @param {Object} [constant] - An optional constant that will be passed along to each callback
-# @returns {Object} Returns the item after it's been through all the callbacks for this hook
-###
-
-RocketChat.callbacks.run = (hook, item, constant) ->
- callbacks = RocketChat.callbacks[hook]
- if !!callbacks?.length
- if RocketChat.callbacks.showTotalTime is true
- totalTime = 0
-
- # if the hook exists, and contains callbacks to run
- result = _.sortBy(callbacks, (callback) -> return callback.priority or RocketChat.callbacks.priority.MEDIUM).reduce (result, callback) ->
- # console.log(callback.name);
- if RocketChat.callbacks.showTime is true or RocketChat.callbacks.showTotalTime is true
- time = Date.now()
-
- callbackResult = callback result, constant
-
- if RocketChat.callbacks.showTime is true or RocketChat.callbacks.showTotalTime is true
- currentTime = Date.now() - time
- totalTime += currentTime
- if RocketChat.callbacks.showTime is true
- if Meteor.isServer
- RocketChat.statsTracker.timing('callbacks.time', currentTime, ["hook:#{hook}", "callback:#{callback.id}"]);
- else
- console.log String(currentTime), hook, callback.id, callback.stack?.split?('\n')[2]?.match(/\(.+\)/)?[0]
-
- return if typeof callbackResult == 'undefined' then result else callbackResult
- , item
-
- if RocketChat.callbacks.showTotalTime is true
- if Meteor.isServer
- RocketChat.statsTracker.timing('callbacks.totalTime', totalTime, ["hook:#{hook}"]);
- else
- console.log hook+':', totalTime
-
- return result
- else
- # else, just return the item unchanged
- return item
-
-###
-# Successively run all of a hook's callbacks on an item, in async mode (only works on server)
-# @param {String} hook - The name of the hook
-# @param {Object} item - The post, comment, modifier, etc. on which to run the callbacks
-# @param {Object} [constant] - An optional constant that will be passed along to each callback
-###
-
-RocketChat.callbacks.runAsync = (hook, item, constant) ->
- callbacks = RocketChat.callbacks[hook]
- if Meteor.isServer and !!callbacks?.length
- # use defer to avoid holding up client
- Meteor.defer ->
- # run all post submit server callbacks on post object successively
- _.sortBy(callbacks, (callback) -> return callback.priority or RocketChat.callbacks.priority.MEDIUM).forEach (callback) ->
- # console.log(callback.name);
- callback item, constant
- return
- return
- else
- return item
- return
diff --git a/packages/rocketchat-lib/lib/callbacks.js b/packages/rocketchat-lib/lib/callbacks.js
new file mode 100644
index 000000000000..86f56a2eea8a
--- /dev/null
+++ b/packages/rocketchat-lib/lib/callbacks.js
@@ -0,0 +1,131 @@
+/*
+* Callback hooks provide an easy way to add extra steps to common operations.
+* @namespace RocketChat.callbacks
+*/
+
+RocketChat.callbacks = {};
+
+if (Meteor.isServer) {
+ RocketChat.callbacks.showTime = true;
+ RocketChat.callbacks.showTotalTime = true;
+} else {
+ RocketChat.callbacks.showTime = false;
+ RocketChat.callbacks.showTotalTime = false;
+}
+
+
+/*
+* Callback priorities
+*/
+
+RocketChat.callbacks.priority = {
+ HIGH: -1000,
+ MEDIUM: 0,
+ LOW: 1000
+};
+
+
+/*
+* Add a callback function to a hook
+* @param {String} hook - The name of the hook
+* @param {Function} callback - The callback function
+*/
+
+RocketChat.callbacks.add = function(hook, callback, priority, id) {
+ if (priority == null) {
+ priority = RocketChat.callbacks.priority.MEDIUM;
+ }
+ if (!_.isNumber(priority)) {
+ priority = RocketChat.callbacks.priority.MEDIUM;
+ }
+ callback.priority = priority;
+ callback.id = id || Random.id();
+ RocketChat.callbacks[hook] = RocketChat.callbacks[hook] || [];
+ if (RocketChat.callbacks.showTime === true) {
+ const err = new Error;
+ callback.stack = err.stack;
+ }
+ if (RocketChat.callbacks[hook].find((cb) => cb.id === callback.id)) {
+ return;
+ }
+ RocketChat.callbacks[hook].push(callback);
+};
+
+
+/*
+* Remove a callback from a hook
+* @param {string} hook - The name of the hook
+* @param {string} id - The callback's id
+*/
+
+RocketChat.callbacks.remove = function(hookName, id) {
+ RocketChat.callbacks[hookName] = _.reject(RocketChat.callbacks[hookName], (callback) => callback.id === id);
+};
+
+
+/*
+* Successively run all of a hook's callbacks on an item
+* @param {String} hook - The name of the hook
+* @param {Object} item - The post, comment, modifier, etc. on which to run the callbacks
+* @param {Object} [constant] - An optional constant that will be passed along to each callback
+* @returns {Object} Returns the item after it's been through all the callbacks for this hook
+*/
+
+RocketChat.callbacks.run = function(hook, item, constant) {
+ const callbacks = RocketChat.callbacks[hook];
+ if (callbacks && callbacks.length) {
+ let totalTime = 0;
+ const result = _.sortBy(callbacks, function(callback) {
+ return callback.priority || RocketChat.callbacks.priority.MEDIUM;
+ }).reduce(function(result, callback) {
+ let time = 0;
+ if (RocketChat.callbacks.showTime === true || RocketChat.callbacks.showTotalTime === true) {
+ time = Date.now();
+ }
+ const callbackResult = callback(result, constant);
+ if (RocketChat.callbacks.showTime === true || RocketChat.callbacks.showTotalTime === true) {
+ const currentTime = Date.now() - time;
+ totalTime += currentTime;
+ if (RocketChat.callbacks.showTime === true) {
+ if (Meteor.isServer) {
+ RocketChat.statsTracker.timing('callbacks.time', currentTime, [`hook:${ hook }`, `callback:${ callback.id }`]);
+ } else {
+ let stack = callback.stack && typeof callback.stack.split === 'function' && callback.stack.split('\n');
+ stack = stack && stack[2] && (stack[2].match(/\(.+\)/)||[])[0];
+ console.log(String(currentTime), hook, callback.id, stack);
+ }
+ }
+ }
+ return (typeof callbackResult === 'undefined') ? result : callbackResult;
+ }, item);
+ if (RocketChat.callbacks.showTotalTime === true) {
+ if (Meteor.isServer) {
+ RocketChat.statsTracker.timing('callbacks.totalTime', totalTime, [`hook:${ hook }`]);
+ } else {
+ console.log(`${ hook }:`, totalTime);
+ }
+ }
+ return result;
+ } else {
+ return item;
+ }
+};
+
+
+/*
+* Successively run all of a hook's callbacks on an item, in async mode (only works on server)
+* @param {String} hook - The name of the hook
+* @param {Object} item - The post, comment, modifier, etc. on which to run the callbacks
+* @param {Object} [constant] - An optional constant that will be passed along to each callback
+*/
+
+RocketChat.callbacks.runAsync = function(hook, item, constant) {
+ const callbacks = RocketChat.callbacks[hook];
+ if (Meteor.isServer && callbacks && callbacks.length) {
+ Meteor.defer(function() {
+ _.sortBy(callbacks, (callback) => callback.priority || RocketChat.callbacks.priority.MEDIUM).forEach((callback) => callback(item, constant));
+ });
+ } else {
+ return item;
+ }
+};
diff --git a/packages/rocketchat-lib/lib/promises.coffee b/packages/rocketchat-lib/lib/promises.coffee
deleted file mode 100644
index a23ab907b738..000000000000
--- a/packages/rocketchat-lib/lib/promises.coffee
+++ /dev/null
@@ -1,93 +0,0 @@
-# https://github.com/TelescopeJS/Telescope/blob/master/packages/telescope-lib/lib/callbacks.js
-
-###
-# Callback hooks provide an easy way to add extra steps to common operations.
-# @namespace RocketChat.promises
-###
-RocketChat.promises = {}
-
-###
-# Callback priorities
-###
-RocketChat.promises.priority =
- HIGH: -1000
- MEDIUM: 0
- LOW: 1000
-
-###
-# Add a callback function to a hook
-# @param {String} hook - The name of the hook
-# @param {Function} callback - The callback function
-###
-
-RocketChat.promises.add = (hook, callback, priority, id) ->
- # if callback array doesn't exist yet, initialize it
- priority ?= RocketChat.promises.priority.MEDIUM
- unless _.isNumber priority
- priority = RocketChat.promises.priority.MEDIUM
- callback.priority = priority
- callback.id = id or Random.id()
- RocketChat.promises[hook] ?= []
-
- # Avoid adding the same callback twice
- for cb in RocketChat.promises[hook]
- if cb.id is callback.id
- return
-
- RocketChat.promises[hook].push callback
- return
-
-###
-# Remove a callback from a hook
-# @param {string} hook - The name of the hook
-# @param {string} id - The callback's id
-###
-
-RocketChat.promises.remove = (hookName, id) ->
- RocketChat.promises[hookName] = _.reject RocketChat.promises[hookName], (callback) ->
- callback.id is id
- return
-
-###
-# Successively run all of a hook's callbacks on an item
-# @param {String} hook - The name of the hook
-# @param {Object} item - The post, comment, modifier, etc. on which to run the callbacks
-# @param {Object} [constant] - An optional constant that will be passed along to each callback
-# @returns {Object} Returns the item after it's been through all the callbacks for this hook
-###
-
-RocketChat.promises.run = (hook, item, constant) ->
- callbacks = RocketChat.promises[hook]
- if !!callbacks?.length
- # if the hook exists, and contains callbacks to run
- callbacks = _.sortBy(callbacks, (callback) -> return callback.priority or RocketChat.promises.priority.MEDIUM)
- return callbacks.reduce (previousPromise, callback) ->
- return new Promise (resolve, reject) ->
- previousPromise.then (result) ->
- callback(result, constant).then(resolve, reject)
- , Promise.resolve(item)
- else
- # else, just return the item unchanged
- return Promise.resolve(item)
-
-###
-# Successively run all of a hook's callbacks on an item, in async mode (only works on server)
-# @param {String} hook - The name of the hook
-# @param {Object} item - The post, comment, modifier, etc. on which to run the callbacks
-# @param {Object} [constant] - An optional constant that will be passed along to each callback
-###
-
-RocketChat.promises.runAsync = (hook, item, constant) ->
- callbacks = RocketChat.promises[hook]
- if Meteor.isServer and !!callbacks?.length
- # use defer to avoid holding up client
- Meteor.defer ->
- # run all post submit server callbacks on post object successively
- _.sortBy(callbacks, (callback) -> return callback.priority or RocketChat.promises.priority.MEDIUM).forEach (callback) ->
- # console.log(callback.name);
- callback item, constant
- return
- return
- else
- return item
- return
diff --git a/packages/rocketchat-lib/lib/promises.js b/packages/rocketchat-lib/lib/promises.js
new file mode 100644
index 000000000000..1e040f172bc5
--- /dev/null
+++ b/packages/rocketchat-lib/lib/promises.js
@@ -0,0 +1,89 @@
+
+/*
+* Callback hooks provide an easy way to add extra steps to common operations.
+* @namespace RocketChat.promises
+*/
+
+RocketChat.promises = {};
+
+
+/*
+* Callback priorities
+*/
+
+RocketChat.promises.priority = {
+ HIGH: -1000,
+ MEDIUM: 0,
+ LOW: 1000
+};
+
+
+/*
+* Add a callback function to a hook
+* @param {String} hook - The name of the hook
+* @param {Function} callback - The callback function
+*/
+
+RocketChat.promises.add = function(hook, callback, p = RocketChat.promises.priority.MEDIUM, id) {
+ const priority = !_.isNumber(p) ? RocketChat.promises.priority.MEDIUM : p;
+ callback.priority = priority;
+ callback.id = id || Random.id();
+ RocketChat.promises[hook] = RocketChat.promises[hook] || [];
+ if (RocketChat.promises[hook].find(cb => cb.id === callback.id)) {
+ return;
+ }
+ RocketChat.promises[hook].push(callback);
+};
+
+
+/*
+* Remove a callback from a hook
+* @param {string} hook - The name of the hook
+* @param {string} id - The callback's id
+*/
+
+RocketChat.promises.remove = function(hookName, id) {
+ RocketChat.promises[hookName] = _.reject(RocketChat.promises[hookName], (callback) => callback.id === id);
+};
+
+
+/*
+* Successively run all of a hook's callbacks on an item
+* @param {String} hook - The name of the hook
+* @param {Object} item - The post, comment, modifier, etc. on which to run the callbacks
+* @param {Object} [constant] - An optional constant that will be passed along to each callback
+* @returns {Object} Returns the item after it's been through all the callbacks for this hook
+*/
+
+RocketChat.promises.run = function(hook, item, constant) {
+ let callbacks = RocketChat.promises[hook];
+ if (callbacks == null || callbacks.length === 0) {
+ return Promise.resolve(item);
+ }
+ callbacks = _.sortBy(callbacks, (callback) => callback.priority || RocketChat.promises.priority.MEDIUM);
+ return callbacks.reduce(function(previousPromise, callback) {
+ return new Promise(function(resolve, reject) {
+ return previousPromise.then((result) => callback(result, constant).then(resolve, reject));
+ });
+ }, Promise.resolve(item));
+};
+
+
+/*
+* Successively run all of a hook's callbacks on an item, in async mode (only works on server)
+* @param {String} hook - The name of the hook
+* @param {Object} item - The post, comment, modifier, etc. on which to run the callbacks
+* @param {Object} [constant] - An optional constant that will be passed along to each callback
+*/
+
+RocketChat.promises.runAsync = function(hook, item, constant) {
+ const callbacks = RocketChat.promises[hook];
+ if (!Meteor.isServer || callbacks == null || callbacks.length === 0) {
+ return item;
+ }
+ Meteor.defer(() => {
+ _.sortBy(callbacks, (callback) => callback.priority || RocketChat.promises.priority.MEDIUM).forEach(function(callback) {
+ callback(item, constant);
+ });
+ });
+};
diff --git a/packages/rocketchat-lib/lib/roomTypesCommon.coffee b/packages/rocketchat-lib/lib/roomTypesCommon.coffee
deleted file mode 100644
index a351dc258922..000000000000
--- a/packages/rocketchat-lib/lib/roomTypesCommon.coffee
+++ /dev/null
@@ -1,75 +0,0 @@
-class @roomTypesCommon
- roomTypes: {}
- roomTypesOrder: []
- mainOrder: 1
-
- ### Adds a room type to app
- @param identifier An identifier to the room type. If a real room, MUST BE the same of `db.rocketchat_room.t` field, if not, can be null
- @param order Order number of the type
- @param config
- template: template name to render on sideNav
- icon: icon class
- route:
- name: route name
- action: route action function
- ###
- add: (identifier, order, config) ->
- unless identifier?
- identifier = Random.id()
-
- if @roomTypes[identifier]?
- return false
-
- if not order?
- order = @mainOrder + 10
- @mainOrder += 10
-
- # @TODO validate config options
- @roomTypesOrder.push
- identifier: identifier
- order: order
- @roomTypes[identifier] = config
-
- if config.route?.path? and config.route?.name? and config.route?.action?
- routeConfig =
- name: config.route.name
- action: config.route.action
-
- if Meteor.isClient
- routeConfig.triggersExit = [ roomExit ]
-
- FlowRouter.route config.route.path, routeConfig
-
- hasCustomLink: (roomType) ->
- return @roomTypes[roomType]?.route?.link?
-
- ###
- @param roomType: room type (e.g.: c (for channels), d (for direct channels))
- @param subData: the user's subscription data
- ###
- getRouteLink: (roomType, subData) ->
- unless @roomTypes[roomType]?
- return false
-
- routeData = {}
-
- if @roomTypes[roomType]?.route?.link?
- routeData = @roomTypes[roomType].route.link(subData)
- else if subData?.name?
- routeData = { name: subData.name }
-
- return FlowRouter.path @roomTypes[roomType].route.name, routeData
-
- openRouteLink: (roomType, subData, queryParams) ->
- unless @roomTypes[roomType]?
- return false
-
- routeData = {}
-
- if @roomTypes[roomType]?.route?.link?
- routeData = @roomTypes[roomType].route.link(subData)
- else if subData?.name?
- routeData = { name: subData.name }
-
- return FlowRouter.go @roomTypes[roomType].route.name, routeData, queryParams
-
diff --git a/packages/rocketchat-lib/lib/roomTypesCommon.js b/packages/rocketchat-lib/lib/roomTypesCommon.js
new file mode 100644
index 000000000000..1df20edae0b3
--- /dev/null
+++ b/packages/rocketchat-lib/lib/roomTypesCommon.js
@@ -0,0 +1,84 @@
+/* globals roomExit*/
+this.roomTypesCommon = class {
+ constructor() {
+ this.roomTypes = {};
+ this.roomTypesOrder = [];
+ this.mainOrder = 1;
+ }
+
+ /* Adds a room type to app
+ @param identifier An identifier to the room type. If a real room, MUST BE the same of `db.rocketchat_room.t` field, if not, can be null
+ @param order Order number of the type
+ @param config
+ template: template name to render on sideNav
+ icon: icon class
+ route:
+ name: route name
+ action: route action function
+ */
+
+ add(identifier = Random.id(), order, config) {
+ if (this.roomTypes[identifier] != null) {
+ return false;
+ }
+ if (order == null) {
+ order = this.mainOrder + 10;
+ this.mainOrder += 10;
+ }
+ this.roomTypesOrder.push({
+ identifier,
+ order
+ });
+ this.roomTypes[identifier] = config;
+ if (config.route && config.route.path && config.route.name && config.route.action) {
+ const routeConfig = {
+ name: config.route.name,
+ action: config.route.action
+ };
+ if (Meteor.isClient) {
+ routeConfig.triggersExit = [roomExit];
+ }
+ return FlowRouter.route(config.route.path, routeConfig);
+ }
+ }
+
+ hasCustomLink(roomType) {
+ return this.roomTypes[roomType] && this.roomTypes[roomType].route && this.roomTypes[roomType].route.link != null;
+ }
+
+ /*
+ @param roomType: room type (e.g.: c (for channels), d (for direct channels))
+ @param subData: the user's subscription data
+ */
+
+ getRouteLink(roomType, subData) {
+ if (this.roomTypes[roomType] == null) {
+ return false;
+ }
+ let routeData = {};
+ if (this.roomTypes[roomType] && this.roomTypes[roomType].route && this.roomTypes[roomType].route.link) {
+ routeData = this.roomTypes[roomType].route.link(subData);
+ } else if (subData && subData.name) {
+ routeData = {
+ name: subData.name
+ };
+ }
+ return FlowRouter.path(this.roomTypes[roomType].route.name, routeData);
+ }
+
+ openRouteLink(roomType, subData, queryParams) {
+ if (this.roomTypes[roomType] == null) {
+ return false;
+ }
+ let routeData = {};
+ if (this.roomTypes[roomType] && this.roomTypes[roomType].route && this.roomTypes[roomType].route.link) {
+ routeData = this.roomTypes[roomType].route.link(subData);
+ } else if (subData && subData.name) {
+ routeData = {
+ name: subData.name
+ };
+ }
+ return FlowRouter.go(this.roomTypes[roomType].route.name, routeData, queryParams);
+ }
+};
+export default this.roomTypesCommon;
diff --git a/packages/rocketchat-lib/lib/settings.coffee b/packages/rocketchat-lib/lib/settings.coffee
deleted file mode 100644
index cdc221064b39..000000000000
--- a/packages/rocketchat-lib/lib/settings.coffee
+++ /dev/null
@@ -1,83 +0,0 @@
-###
-# RocketChat.settings holds all packages settings
-# @namespace RocketChat.settings
-###
-RocketChat.settings =
- callbacks: {}
- regexCallbacks: {}
- ts: new Date
-
- get: (_id, callback) ->
- if callback?
- RocketChat.settings.onload _id, callback
- if _id is '*' and Meteor.settings?
- for key, value of Meteor.settings
- callback key, value
- return
-
- if _.isRegExp(_id)
- for key, value of Meteor.settings when _id.test(key)
- callback key, value
- return
-
- if Meteor.settings?[_id]?
- callback _id, Meteor.settings?[_id]
- else
- if _.isRegExp(_id)
- items = []
- for key, value of Meteor.settings when _id.test(key)
- items.push
- key: key
- value: value
- return items
-
- return Meteor.settings?[_id]
-
- set: (_id, value, callback) ->
- Meteor.call 'saveSetting', _id, value, callback
-
- batchSet: (settings, callback) ->
-
- # async -> sync
- # http://daemon.co.za/2012/04/simple-async-with-only-underscore/
-
- save = (setting) ->
- return (callback) ->
- Meteor.call 'saveSetting', setting._id, setting.value, setting.editor, callback
-
- actions = _.map settings, (setting) -> save(setting)
- _(actions).reduceRight(_.wrap, (err, success) -> return callback err, success)()
-
- load: (key, value, initialLoad) ->
- if RocketChat.settings.callbacks[key]?
- for callback in RocketChat.settings.callbacks[key]
- callback key, value, initialLoad
-
- if RocketChat.settings.callbacks['*']?
- for callback in RocketChat.settings.callbacks['*']
- callback key, value, initialLoad
-
- for cbKey, cbValue of RocketChat.settings.regexCallbacks
- if cbValue.regex.test(key)
- callback(key, value, initialLoad) for callback in cbValue.callbacks
-
-
- onload: (key, callback) ->
- # if key is '*'
- # for key, value in Meteor.settings
- # callback key, value, false
- # else if Meteor.settings?[_id]?
- # callback key, Meteor.settings[_id], false
-
- keys = [].concat key
-
- for k in keys
- if _.isRegExp k
- RocketChat.settings.regexCallbacks[k.source] ?= {
- regex: k
- callbacks: []
- }
- RocketChat.settings.regexCallbacks[k.source].callbacks.push callback
- else
- RocketChat.settings.callbacks[k] ?= []
- RocketChat.settings.callbacks[k].push callback
diff --git a/packages/rocketchat-lib/lib/settings.js b/packages/rocketchat-lib/lib/settings.js
new file mode 100644
index 000000000000..9c14943dac63
--- /dev/null
+++ b/packages/rocketchat-lib/lib/settings.js
@@ -0,0 +1,99 @@
+
+/*
+* RocketChat.settings holds all packages settings
+* @namespace RocketChat.settings
+*/
+RocketChat.settings = {
+ callbacks: {},
+ regexCallbacks: {},
+ ts: new Date,
+ get(_id, callback) {
+ if (callback != null) {
+ RocketChat.settings.onload(_id, callback);
+ if (!Meteor.settings) {
+ return;
+ }
+ if (_id === '*') {
+ return Object.keys(Meteor.settings).forEach(key => {
+ const value = Meteor.settings[key];
+ callback(key, value);
+ });
+ }
+ if (_.isRegExp(_id) && Meteor.settings) {
+ return Object.keys(Meteor.settings).forEach(key => {
+ if (!_id.test(key)) {
+ return;
+ }
+ const value = Meteor.settings[key];
+ callback(key, value);
+ });
+ }
+ return Meteor.settings[_id] != null && callback(_id, Meteor.settings[_id]);
+ } else {
+ if (!Meteor.settings) {
+ return;
+ }
+ if (_.isRegExp(_id)) {
+ return Object.keys(Meteor.settings).reduce((items, key) => {
+ const value = Meteor.settings[key];
+ if (_id.test(key)) {
+ items.push({
+ key,
+ value
+ });
+ }
+ return items;
+ }, []);
+ }
+ return Meteor.settings && Meteor.settings[_id];
+ }
+ },
+ set(_id, value, callback) {
+ return Meteor.call('saveSetting', _id, value, callback);
+ },
+ batchSet(settings, callback) {
+ // async -> sync
+ // http://daemon.co.za/2012/04/simple-async-with-only-underscore/
+ const save = function(setting) {
+ return function(callback) {
+ return Meteor.call('saveSetting', setting._id, setting.value, setting.editor, callback);
+ };
+ };
+ const actions = _.map(settings, (setting) => save(setting));
+ return _(actions).reduceRight(_.wrap, (err, success) => callback(err, success))();
+ },
+ load(key, value, initialLoad) {
+ ['*', key].forEach(key => {
+ if (RocketChat.settings.callbacks[key]) {
+ RocketChat.settings.callbacks[key].forEach(callback => callback(key, value, initialLoad));
+ }
+ });
+ Object.keys(RocketChat.settings.regexCallbacks).forEach(cbKey => {
+ const cbValue = RocketChat.settings.regexCallbacks[cbKey];
+ if (!cbValue.regex.test(key)) {
+ return;
+ }
+ cbValue.callbacks.forEach(callback => callback(key, value, initialLoad));
+ });
+ },
+ onload(key, callback) {
+ // if key is '*'
+ // for key, value in Meteor.settings
+ // callback key, value, false
+ // else if Meteor.settings?[_id]?
+ // callback key, Meteor.settings[_id], false
+ const keys = [].concat(key);
+ keys.forEach(k => {
+ if (_.isRegExp(k)) {
+ RocketChat.settings.regexCallbacks[name = k.source] = RocketChat.settings.regexCallbacks[name = k.source] || {
+ regex: k,
+ callbacks: []
+ };
+ RocketChat.settings.regexCallbacks[k.source].callbacks.push(callback);
+ } else {
+ RocketChat.settings.callbacks[k] = RocketChat.settings.callbacks[k] || [];
+ RocketChat.settings.callbacks[k].push(callback);
+ }
+ });
+ }
+};
diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js
index b09e0428bd3d..3d7f8402927a 100644
--- a/packages/rocketchat-lib/package.js
+++ b/packages/rocketchat-lib/package.js
@@ -52,12 +52,12 @@ Package.onUse(function(api) {
// COMMON LIB
api.addFiles('lib/getURL.js');
- api.addFiles('lib/settings.coffee');
- api.addFiles('lib/callbacks.coffee');
+ api.addFiles('lib/settings.js');
+ api.addFiles('lib/callbacks.js');
api.addFiles('lib/fileUploadRestrictions.js');
api.addFiles('lib/placeholders.js');
- api.addFiles('lib/promises.coffee');
- api.addFiles('lib/roomTypesCommon.coffee');
+ api.addFiles('lib/promises.js');
+ api.addFiles('lib/roomTypesCommon.js');
api.addFiles('lib/slashCommand.js');
api.addFiles('lib/Message.js');
api.addFiles('lib/MessageTypes.js');
@@ -174,29 +174,29 @@ Package.onUse(function(api) {
api.addFiles('lib/startup/settingsOnLoadSiteUrl.js');
// CLIENT LIB
- api.addFiles('client/Notifications.coffee', 'client');
+ api.addFiles('client/Notifications.js', 'client');
api.addFiles('client/OAuthProxy.js', 'client');
api.addFiles('client/lib/TabBar.js', 'client');
api.addFiles('client/lib/RocketChatTabBar.js', 'client');
api.addFiles('client/lib/cachedCollection.js', 'client');
- api.addFiles('client/lib/openRoom.coffee', 'client');
- api.addFiles('client/lib/roomExit.coffee', 'client');
- api.addFiles('client/lib/settings.coffee', 'client');
- api.addFiles('client/lib/roomTypes.coffee', 'client');
+ api.addFiles('client/lib/openRoom.js', 'client');
+ api.addFiles('client/lib/roomExit.js', 'client');
+ api.addFiles('client/lib/settings.js', 'client');
+ api.addFiles('client/lib/roomTypes.js', 'client');
api.addFiles('client/lib/userRoles.js', 'client');
api.addFiles('client/lib/Layout.js', 'client');
// CLIENT METHODS
- api.addFiles('client/methods/sendMessage.coffee', 'client');
+ api.addFiles('client/methods/sendMessage.js', 'client');
api.addFiles('client/AdminBox.js', 'client');
- api.addFiles('client/MessageAction.coffee', 'client');
+ api.addFiles('client/MessageAction.js', 'client');
api.addFiles('client/defaultTabBars.js', 'client');
api.addFiles('client/CustomTranslations.js', 'client');
// CLIENT MODELS
- api.addFiles('client/models/_Base.coffee', 'client');
- api.addFiles('client/models/Uploads.coffee', 'client');
+ api.addFiles('client/models/_Base.js', 'client');
+ api.addFiles('client/models/Uploads.js', 'client');
// CLIENT VIEWS
api.addFiles('client/views/customFieldsForm.html', 'client');