diff --git a/app/discussion/client/views/creationDialog/CreateDiscussion.html b/app/discussion/client/views/creationDialog/CreateDiscussion.html
index 847cbb6e9944..837be516fde8 100644
--- a/app/discussion/client/views/creationDialog/CreateDiscussion.html
+++ b/app/discussion/client/views/creationDialog/CreateDiscussion.html
@@ -96,13 +96,11 @@
- {{#with config}} {{#if autocomplete 'isShowing'}}
-
- {{#if autocomplete 'isLoaded'}}
- {{> popupList data=config items=items}}
+ {{#with config}}
+ {{#if autocomplete 'isShowing'}}
+ {{> popupList data=config items=items ready=(autocomplete 'isLoaded')}}
{{/if}}
-
- {{/if}} {{/with}}
+ {{/with}}
{{ description }}
diff --git a/app/emoji/client/emojiParser.js b/app/emoji/client/emojiParser.js
index ff1a7b3dee1b..809b3c41569a 100644
--- a/app/emoji/client/emojiParser.js
+++ b/app/emoji/client/emojiParser.js
@@ -1,61 +1,62 @@
+import s from 'underscore.string';
+
import { Meteor } from 'meteor/meteor';
+import { Tracker } from 'meteor/tracker';
+
import { getUserPreference } from '../../utils';
import { callbacks } from '../../callbacks';
import { emoji } from '../lib/rocketchat';
-import { isSetNotNull } from './function-isSet';
-import s from 'underscore.string';
/*
* emojiParser is a function that will replace emojis
* @param {Object} message - The message object
*/
-callbacks.add('renderMessage', (message) => {
- if (isSetNotNull(() => getUserPreference(Meteor.userId(), 'useEmojis')) &&
- !getUserPreference(Meteor.userId(), 'useEmojis')) {
- return message;
+
+Tracker.autorun(() => {
+ if (!getUserPreference(Meteor.userId(), 'useEmojis')) {
+ return callbacks.remove('renderMessage', 'emoji');
}
+ callbacks.add('renderMessage', (message) => {
+ if (s.trim(message.html)) {
+ // ' to apostrophe (') for emojis such as :')
+ message.html = message.html.replace(/'/g, '\'');
+
+ // '
' to '
' for emojis such at line breaks
+ message.html = message.html.replace(/
/g, '
');
- if (s.trim(message.html)) {
- // ' to apostrophe (') for emojis such as :')
- message.html = message.html.replace(/'/g, '\'');
+ message.html = Object.entries(emoji.packages).reduce((value, [, emojiPackage]) => emojiPackage.render(value), message.html);
- // '
' to '
' for emojis such at line breaks
- message.html = message.html.replace(/
/g, '
');
+ const checkEmojiOnly = $(`${ message.html }
`);
+ let emojiOnly = true;
- Object.keys(emoji.packages).forEach((emojiPackage) => {
- message.html = emoji.packages[emojiPackage].render(message.html);
- });
- const checkEmojiOnly = $(`${ message.html }
`);
- let emojiOnly = true;
- for (const childNode in checkEmojiOnly[0].childNodes) {
- if (checkEmojiOnly[0].childNodes.hasOwnProperty(childNode)) {
- const child = $(checkEmojiOnly[0].childNodes[childNode]);
+ for (let i = 0, len = checkEmojiOnly[0].childNodes.length; i < len; i++) {
+ const childNode = checkEmojiOnly[0].childNodes[i];
- if (child.hasClass('emoji') || child.hasClass('emojione')) {
- checkEmojiOnly[0].childNodes[childNode] = child.addClass('big');
+ if (childNode.classList && (childNode.classList.contains('emoji') || childNode.classList.contains('emojione'))) {
+ childNode.classList.add('big');
continue;
}
- if (s.trim(child.text()) === '') {
+ if (s.trim(childNode.innerText) === '') {
continue;
}
emojiOnly = false;
break;
}
- }
- if (emojiOnly) {
- message.html = checkEmojiOnly.unwrap().html();
- }
+ if (emojiOnly) {
+ message.html = checkEmojiOnly.unwrap().html();
+ }
- // apostrophe (') back to '
- message.html = message.html.replace(/\'/g, ''');
+ // apostrophe (') back to '
+ message.html = message.html.replace(/\'/g, ''');
- // apostrophe '
' back to '
'
- message.html = message.html.replace(/
/g, '
');
- }
+ // apostrophe '
' back to '
'
+ message.html = message.html.replace(/
/g, '
');
+ }
- return message;
-}, callbacks.priority.LOW, 'emoji');
+ return message;
+ }, callbacks.priority.LOW, 'emoji');
+});
diff --git a/app/highlight-words/client/client.js b/app/highlight-words/client/client.js
index a740542bf242..b2e811b3b870 100644
--- a/app/highlight-words/client/client.js
+++ b/app/highlight-words/client/client.js
@@ -2,28 +2,39 @@
* Highlights is a named function that will process Highlights
* @param {Object} message - The message object
*/
+import _ from 'underscore';
+import s from 'underscore.string';
+
import { Meteor } from 'meteor/meteor';
+import { Tracker } from 'meteor/tracker';
+
import { callbacks } from '../../callbacks';
import { getUserPreference } from '../../utils';
-import _ from 'underscore';
-import s from 'underscore.string';
-import { highlightWords } from './helper';
+import { highlightWords, getRegexHighlight, getRegexHighlightUrl } from './helper';
-function HighlightWordsClient(message) {
- let msg = message;
- if (!_.isString(message)) {
- if (s.trim(message.html)) {
- msg = message.html;
- } else {
- return message;
- }
+Tracker.autorun(() => {
+ const toHighlight = (getUserPreference(Meteor.userId(), 'highlights') || []).filter((highlight) => !s.isBlank(highlight)).map((highlight) => ({
+ highlight,
+ regex: getRegexHighlight(highlight),
+ urlRegex: getRegexHighlightUrl(highlight),
+ }));
+
+ if (!toHighlight.length) {
+ return callbacks.remove('renderMessage', 'highlight-words');
}
- const to_highlight = getUserPreference(Meteor.user(), 'highlights');
- msg = highlightWords(msg, to_highlight);
+ function HighlightWordsClient(message) {
+ let msg = message;
- message.html = msg;
- return message;
-}
+ if (!_.isString(message)) {
+ if (!s.trim(message.html)) {
+ return message;
+ }
+ msg = message.html;
+ }
-callbacks.add('renderMessage', HighlightWordsClient, callbacks.priority.MEDIUM + 1, 'highlight-words');
+ message.html = highlightWords(msg, toHighlight);
+ return message;
+ }
+ callbacks.add('renderMessage', HighlightWordsClient, callbacks.priority.MEDIUM + 1, 'highlight-words');
+});
diff --git a/app/highlight-words/client/helper.js b/app/highlight-words/client/helper.js
index 3f7ef9edd3fa..a82bbdc2a4e0 100644
--- a/app/highlight-words/client/helper.js
+++ b/app/highlight-words/client/helper.js
@@ -1,42 +1,28 @@
import s from 'underscore.string';
-export const checkHighlightedWordsInUrls = (msg, highlight) => {
- const urlRegex = new RegExp(`https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\\+~#=]{2,256}\.[a-z]{2,6}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)(${ s.escapeRegExp(highlight) })\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)`, 'gmi');
- const urlMatches = msg.match(urlRegex);
-
- return urlMatches;
-};
+export const checkHighlightedWordsInUrls = (msg, urlRegex) => msg.match(urlRegex);
export const removeHighlightedUrls = (msg, highlight, urlMatches) => {
+ const highlightRegex = new RegExp(highlight, 'gmi');
- urlMatches.forEach((match) => {
- const highlightRegex = new RegExp(highlight, 'gmi');
+ return urlMatches.reduce((msg, match) => {
const withTemplate = match.replace(highlightRegex, `${ highlight }`);
const regexWithTemplate = new RegExp(withTemplate, 'i');
-
- msg = msg.replace(regexWithTemplate, match);
- });
-
- return msg;
+ return msg.replace(regexWithTemplate, match);
+ }, msg);
};
-export const highlightWords = (msg, to_highlight) => {
- const highlightTemplate = '$1$2$3';
+const highlightTemplate = '$1$2$3';
- if (Array.isArray(to_highlight)) {
- to_highlight.forEach((highlight) => {
- if (!s.isBlank(highlight)) {
- const regex = new RegExp(`(^|\\b|[\\s\\n\\r\\t.,،'\\\"\\+!?:-])(${ s.escapeRegExp(highlight) })($|\\b|[\\s\\n\\r\\t.,،'\\\"\\+!?:-])(?![^<]*>|[^<>]*<\\/)`, 'gmi');
- const urlMatches = checkHighlightedWordsInUrls(msg, highlight);
+export const getRegexHighlight = (highlight) => new RegExp(`(^|\\b|[\\s\\n\\r\\t.,،'\\\"\\+!?:-])(${ s.escapeRegExp(highlight) })($|\\b|[\\s\\n\\r\\t.,،'\\\"\\+!?:-])(?![^<]*>|[^<>]*<\\/)`, 'gmi');
- msg = msg.replace(regex, highlightTemplate);
+export const getRegexHighlightUrl = (highlight) => new RegExp(`https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\\+~#=]{2,256}\.[a-z]{2,6}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)(${ s.escapeRegExp(highlight) })\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)`, 'gmi');
- if (urlMatches) {
- msg = removeHighlightedUrls(msg, highlight, urlMatches);
- }
- }
- });
- }
+export const highlightWords = (msg, highlights) => highlights.reduce((msg, { highlight, regex, urlRegex }) => {
+ const urlMatches = checkHighlightedWordsInUrls(msg, urlRegex);
+ if (!urlMatches) {
+ return msg.replace(regex, highlightTemplate);
- return msg;
-};
+ }
+ return removeHighlightedUrls(msg.replace(regex, highlightTemplate), highlight, urlMatches);
+}, msg);
diff --git a/app/highlight-words/tests/helper.tests.js b/app/highlight-words/tests/helper.tests.js
index 033b18dcde03..16e3812138bd 100644
--- a/app/highlight-words/tests/helper.tests.js
+++ b/app/highlight-words/tests/helper.tests.js
@@ -2,32 +2,48 @@
import 'babel-polyfill';
import assert from 'assert';
-import { highlightWords } from '../client/helper';
+import { highlightWords, getRegexHighlight, getRegexHighlightUrl } from '../client/helper';
describe('helper', () => {
describe('highlightWords', () => {
it('highlights the correct words', () => {
- const res = highlightWords('here is some word', ['word']);
+ const res = highlightWords('here is some word', ['word'].map((highlight) => ({
+ highlight,
+ regex: getRegexHighlight(highlight),
+ urlRegex: getRegexHighlightUrl(highlight),
+ })));
assert.equal(res, 'here is some word');
});
describe('handles links', () => {
it('not highlighting one link', () => {
- const res = highlightWords('here we go https://somedomain.com/here-some.word/pulls more words after', ['word']);
+ const res = highlightWords('here we go https://somedomain.com/here-some.word/pulls more words after', ['word'].map((highlight) => ({
+ highlight,
+ regex: getRegexHighlight(highlight),
+ urlRegex: getRegexHighlightUrl(highlight),
+ })));
assert.equal(res, 'here we go https://somedomain.com/here-some.word/pulls more words after');
});
it('not highlighting two links', () => {
const msg = 'here https://somedomain.com/here-some-foo/pulls more words after http://www.domain.com/some.foo/bar words after';
- const res = highlightWords(msg, ['foo']);
+ const res = highlightWords(msg, ['foo'].map((highlight) => ({
+ highlight,
+ regex: getRegexHighlight(highlight),
+ urlRegex: getRegexHighlightUrl(highlight),
+ })));
assert.equal(res, msg);
});
it('not highlighting link but keep words on message highlighted', () => {
- const res = highlightWords('here we go https://somedomain.com/here-some.foo/pulls more foo after', ['foo']);
+ const res = highlightWords('here we go https://somedomain.com/here-some.foo/pulls more foo after', ['foo'].map((highlight) => ({
+ highlight,
+ regex: getRegexHighlight(highlight),
+ urlRegex: getRegexHighlightUrl(highlight),
+ })));
assert.equal(res, 'here we go https://somedomain.com/here-some.foo/pulls more foo after');
});
diff --git a/app/lib/client/lib/formatDate.js b/app/lib/client/lib/formatDate.js
index 2d2bd13b785a..e1ae40d79357 100644
--- a/app/lib/client/lib/formatDate.js
+++ b/app/lib/client/lib/formatDate.js
@@ -1,21 +1,34 @@
+import moment from 'moment';
+
import { Meteor } from 'meteor/meteor';
+import { Tracker } from 'meteor/tracker';
+
import { getUserPreference, t } from '../../../utils';
import { settings } from '../../../settings';
-import moment from 'moment';
+
+let lastDay = t('yesterday');
+let clockMode;
+let sameDay;
+const dayFormat = ['h:mm A', 'H:mm'];
+
+Meteor.startup(() => Tracker.autorun(() => {
+ clockMode = getUserPreference(Meteor.userId(), 'clockMode', false);
+ sameDay = dayFormat[clockMode - 1] || 'h:mm A';
+ lastDay = t('yesterday');
+}));
export const formatTime = (time) => {
- switch (getUserPreference(Meteor.userId(), 'clockMode', false)) {
+ switch (clockMode) {
case 1:
- return moment(time).format('h:mm A');
case 2:
- return moment(time).format('H:mm');
+ return moment(time).format(sameDay);
default:
return moment(time).format(settings.get('Message_TimeFormat'));
}
};
export const formatDateAndTime = (time) => {
- switch (getUserPreference(Meteor.userId(), 'clockMode', false)) {
+ switch (clockMode) {
case 1:
return moment(time).format('MMMM D, Y h:mm A');
case 2:
@@ -25,15 +38,16 @@ export const formatDateAndTime = (time) => {
}
};
-export const timeAgo = (time) => {
- const now = new Date();
- const yesterday = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1);
-
- return (
- (now.getDate() === time.getDate() && moment(time).format('LT')) ||
- (yesterday.getDate() === time.getDate() && t('yesterday')) ||
- moment(time).format('L')
- );
+const sameElse = function(now) {
+ const diff = Math.ceil(this.diff(now, 'years', true));
+ return diff < 0 ? 'MMM D YYYY' : 'MMM D';
};
+export const timeAgo = (date) => moment(date).calendar(null, {
+ lastDay: `[${ lastDay }]`,
+ sameDay,
+ lastWeek: 'dddd',
+ sameElse,
+});
+
export const formatDate = (time) => moment(time).format(settings.get('Message_DateFormat'));
diff --git a/app/logger/client/logger.js b/app/logger/client/logger.js
index 4ca8ffce787c..92556c3dc874 100644
--- a/app/logger/client/logger.js
+++ b/app/logger/client/logger.js
@@ -1,35 +1,70 @@
import { Template } from 'meteor/templating';
import _ from 'underscore';
-Template.log = false;
+import { getConfig } from '../../ui-utils/client/config';
-Template.logMatch = /.*/;
+Template.log = !!(getConfig('debug') || getConfig('debug-template'));
+
+if (Template.log) {
-Template.enableLogs = function(log) {
Template.logMatch = /.*/;
- if (log === false) {
- return Template.log = false;
- } else {
- Template.log = true;
- if (log instanceof RegExp) {
- return Template.logMatch = log;
+
+ Template.enableLogs = function(log) {
+ Template.logMatch = /.*/;
+ if (log === false) {
+ return Template.log = false;
+ } else {
+ Template.log = true;
+ if (log instanceof RegExp) {
+ return Template.logMatch = log;
+ }
}
- }
-};
+ };
-const wrapHelpersAndEvents = function(original, prefix, color) {
- return function(dict) {
+ const wrapHelpersAndEvents = function(original, prefix, color) {
+ return function(dict) {
- const template = this;
- const fn1 = function(name, fn) {
- if (fn instanceof Function) {
- return dict[name] = function(...args) {
+ const template = this;
+ const fn1 = function(name, fn) {
+ if (fn instanceof Function) {
+ return dict[name] = function(...args) {
+
+ const result = fn.apply(this, args);
+ if (Template.log === true) {
+ const completeName = `${ prefix }:${ template.viewName.replace('Template.', '') }.${ name }`;
+ if (Template.logMatch.test(completeName)) {
+ console.log(`%c${ completeName }`, `color: ${ color }`, {
+ args,
+ scope: this,
+ result,
+ });
+ }
+ }
+ return result;
+ };
+ }
+ };
+ _.each(name, (fn, name) => {
+ fn1(name, fn);
+ });
+ return original.call(template, dict);
+ };
+ };
+ Template.prototype.helpers = wrapHelpersAndEvents(Template.prototype.helpers, 'helper', 'blue');
+
+ Template.prototype.events = wrapHelpersAndEvents(Template.prototype.events, 'event', 'green');
+
+ const wrapLifeCycle = function(original, prefix, color) {
+ return function(fn) {
+ const template = this;
+ if (fn instanceof Function) {
+ const wrap = function(...args) {
const result = fn.apply(this, args);
if (Template.log === true) {
const completeName = `${ prefix }:${ template.viewName.replace('Template.', '') }.${ name }`;
if (Template.logMatch.test(completeName)) {
- console.log(`%c${ completeName }`, `color: ${ color }`, {
+ console.log(`%c${ completeName }`, `color: ${ color }; font-weight: bold`, {
args,
scope: this,
result,
@@ -38,46 +73,16 @@ const wrapHelpersAndEvents = function(original, prefix, color) {
}
return result;
};
+ return original.call(template, wrap);
+ } else {
+ return original.call(template, fn);
}
};
- _.each(name, (fn, name) => {
- fn1(name, fn);
- });
- return original.call(template, dict);
- };
-};
-
-Template.prototype.helpers = wrapHelpersAndEvents(Template.prototype.helpers, 'helper', 'blue');
-
-Template.prototype.events = wrapHelpersAndEvents(Template.prototype.events, 'event', 'green');
-
-const wrapLifeCycle = function(original, prefix, color) {
- return function(fn) {
- const template = this;
- if (fn instanceof Function) {
- const wrap = function(...args) {
- const result = fn.apply(this, args);
- if (Template.log === true) {
- const completeName = `${ prefix }:${ template.viewName.replace('Template.', '') }.${ name }`;
- if (Template.logMatch.test(completeName)) {
- console.log(`%c${ completeName }`, `color: ${ color }; font-weight: bold`, {
- args,
- scope: this,
- result,
- });
- }
- }
- return result;
- };
- return original.call(template, wrap);
- } else {
- return original.call(template, fn);
- }
};
-};
-Template.prototype.onCreated = wrapLifeCycle(Template.prototype.onCreated, 'onCreated', 'blue');
+ Template.prototype.onCreated = wrapLifeCycle(Template.prototype.onCreated, 'onCreated', 'blue');
-Template.prototype.onRendered = wrapLifeCycle(Template.prototype.onRendered, 'onRendered', 'green');
+ Template.prototype.onRendered = wrapLifeCycle(Template.prototype.onRendered, 'onRendered', 'green');
-Template.prototype.onDestroyed = wrapLifeCycle(Template.prototype.onDestroyed, 'onDestroyed', 'red');
+ Template.prototype.onDestroyed = wrapLifeCycle(Template.prototype.onDestroyed, 'onDestroyed', 'red');
+}
diff --git a/app/mentions/client/client.js b/app/mentions/client/client.js
index a227c6256865..082fe9dd138d 100644
--- a/app/mentions/client/client.js
+++ b/app/mentions/client/client.js
@@ -1,12 +1,24 @@
import { Meteor } from 'meteor/meteor';
+import { Tracker } from 'meteor/tracker';
import { callbacks } from '../../callbacks';
import { settings } from '../../settings';
import { MentionsParser } from '../lib/MentionsParser';
+let me;
+let useRealName;
+let pattern;
+
+Meteor.startup(() => Tracker.autorun(() => {
+ me = Meteor.userId() && Meteor.user().username;
+ pattern = settings.get('UTF8_Names_Validation');
+ useRealName = settings.get('UI_Use_Real_Name');
+}));
+
+
const instance = new MentionsParser({
- pattern: () => settings.get('UTF8_Names_Validation'),
- useRealName: () => settings.get('UI_Use_Real_Name'),
- me: () => Meteor.userId() && Meteor.user().username,
+ pattern: () => pattern,
+ useRealName: () => useRealName,
+ me: () => me,
});
callbacks.add('renderMessage', (message) => instance.parse(message), callbacks.priority.MEDIUM, 'mentions-message');
diff --git a/app/theme/client/imports/forms/popup-list.css b/app/theme/client/imports/forms/popup-list.css
index 1abcc9ca6fa0..35349a13d96d 100644
--- a/app/theme/client/imports/forms/popup-list.css
+++ b/app/theme/client/imports/forms/popup-list.css
@@ -5,8 +5,6 @@
width: 100%;
- padding: 0 4px;
-
&__list {
overflow-y: auto;
diff --git a/app/threads/client/flextab/thread.js b/app/threads/client/flextab/thread.js
index eaec26f4e13a..557ae08280d1 100644
--- a/app/threads/client/flextab/thread.js
+++ b/app/threads/client/flextab/thread.js
@@ -75,8 +75,6 @@ Template.thread.onRendered(function() {
this.chatMessages.initializeWrapper(this.find('.js-scroll-thread'));
this.chatMessages.initializeInput(this.find('.js-input-message'), { rid, tmid });
- this.chatMessages.wrapper.scrollTop = this.chatMessages.wrapper.scrollHeight - this.chatMessages.wrapper.clientHeight;
-
this.sendToBottom = _.throttle(() => {
this.chatMessages.wrapper.scrollTop = this.chatMessages.wrapper.scrollHeight;
}, 300);
@@ -94,7 +92,13 @@ Template.thread.onRendered(function() {
const tmid = this.state.get('tmid');
this.threadsObserve && this.threadsObserve.stop();
- this.threadsObserve = Messages.find({ tmid, _updatedAt: { $gt: new Date() } }).observe({
+ this.threadsObserve = Messages.find({ tmid, _updatedAt: { $gt: new Date() } }, {
+ fields: {
+ collapsed: 0,
+ threadMsg: 0,
+ repliesCount: 0,
+ },
+ }).observe({
added: ({ _id, ...message }) => {
const { atBottom } = this;
this.Threads.upsert({ _id }, message);
diff --git a/app/threads/client/flextab/threads.js b/app/threads/client/flextab/threads.js
index c42e782f7221..8b4b594887dd 100644
--- a/app/threads/client/flextab/threads.js
+++ b/app/threads/client/flextab/threads.js
@@ -10,12 +10,14 @@ import { call } from '../../../ui-utils';
import { Messages, Subscriptions } from '../../../models';
import { messageContext } from '../../../ui-utils/client/lib/messageContext';
import { messageArgs } from '../../../ui-utils/client/lib/messageArgs';
+import { getConfig } from '../../../ui-utils/client/config';
import { upsert } from '../upsert';
import './threads.html';
-const LIST_SIZE = 50;
+const LIST_SIZE = parseInt(getConfig('threadsListSize')) || 50;
+
const sort = { tlm: -1 };
Template.threads.events({
diff --git a/app/ui-message/client/message.html b/app/ui-message/client/message.html
index a08666cff188..e78b42a76034 100644
--- a/app/ui-message/client/message.html
+++ b/app/ui-message/client/message.html
@@ -101,7 +101,7 @@
{{_ "No_messages_yet" }}
{{/if}}
- {{ formatDate msg.dlm }}
+ {{ formatDateAndTime msg.dlm }}
{{/if}}
@@ -111,7 +111,7 @@
{{> icon icon="thread"}}
{{msg.tcount}} {{_ i18nKeyReply}}
- {{ formatDate msg.tlm}}
+ {{ formatDateAndTime msg.tlm}}
{{/if}}
diff --git a/app/ui-message/client/message.js b/app/ui-message/client/message.js
index 738d0fdc47b1..5f3b571a696f 100644
--- a/app/ui-message/client/message.js
+++ b/app/ui-message/client/message.js
@@ -1,12 +1,11 @@
import _ from 'underscore';
-import moment from 'moment';
import { Meteor } from 'meteor/meteor';
import { Blaze } from 'meteor/blaze';
import { Template } from 'meteor/templating';
import { TAPi18n } from 'meteor/tap:i18n';
-import { timeAgo } from '../../lib/client/lib/formatDate';
+import { timeAgo, formatDateAndTime } from '../../lib/client/lib/formatDate';
import { DateFormat } from '../../lib/client';
import { renderMessageBody, MessageTypes, MessageAction, call, normalizeThreadMessage } from '../../ui-utils/client';
import { RoomRoles, UserRoles, Roles, Messages } from '../../models/client';
@@ -84,9 +83,7 @@ Template.message.helpers({
? 'replies'
: 'reply';
},
- formatDate(date) {
- return moment(date).format('LLL');
- },
+ formatDateAndTime,
encodeURI(text) {
return encodeURI(text);
},
@@ -519,10 +516,6 @@ const setNewDayAndGroup = (currentNode, previousNode, forceDate, period, noDate)
classList.add('new-day');
}
- if (previousDataset.tmid !== currentDataset.tmid) {
- return classList.remove('sequential');
- }
-
if (previousDataset.username !== currentDataset.username || parseInt(currentDataset.timestamp) - parseInt(previousDataset.timestamp) > period) {
return classList.remove('sequential');
}
@@ -559,7 +552,7 @@ Template.message.onViewRendered = function() {
nextNode.classList.remove('new-day');
}
if (nextDataset.groupable !== 'false') {
- if (nextDataset.tmid !== currentDataset.tmid || nextDataset.username !== currentDataset.username || parseInt(nextDataset.timestamp) - parseInt(currentDataset.timestamp) > settings.Message_GroupingPeriod) {
+ if (nextDataset.username !== currentDataset.username || parseInt(nextDataset.timestamp) - parseInt(currentDataset.timestamp) > settings.Message_GroupingPeriod) {
nextNode.classList.remove('sequential');
} else if (!nextNode.classList.contains('new-day') && !currentNode.classList.contains('temp') && !currentNode.dataset.tmid) {
nextNode.classList.add('sequential');
diff --git a/app/ui-utils/client/config.js b/app/ui-utils/client/config.js
new file mode 100644
index 000000000000..195b1b7db8e0
--- /dev/null
+++ b/app/ui-utils/client/config.js
@@ -0,0 +1,6 @@
+const url = new URL(window.location);
+const keys = new Set();
+export const getConfig = (key) => {
+ keys.add(key);
+ return url.searchParams.get(key) || localStorage.getItem(`rc-config-${ key }`);
+};
diff --git a/app/ui-utils/client/lib/RoomHistoryManager.js b/app/ui-utils/client/lib/RoomHistoryManager.js
index 33c6de31722f..93ed3e774576 100644
--- a/app/ui-utils/client/lib/RoomHistoryManager.js
+++ b/app/ui-utils/client/lib/RoomHistoryManager.js
@@ -4,6 +4,7 @@ import { Meteor } from 'meteor/meteor';
import { ReactiveVar } from 'meteor/reactive-var';
import { Blaze } from 'meteor/blaze';
import { ChatMessage, ChatSubscription, ChatRoom } from '../../../models';
+import { getConfig } from '../config';
import { RoomManager } from './RoomManager';
import { readMessage } from './readMessages';
import { renderMessageBody } from './renderMessageBody';
@@ -66,7 +67,7 @@ function upsertMessageBulk({ msgs, subscription }) {
});
}
-const defaultLimit = parseInt(localStorage && localStorage.getItem('rc-defaultLimit')) || 50 ;
+const defaultLimit = parseInt(getConfig('roomListLimit')) || 50 ;
export const RoomHistoryManager = new class {
constructor() {
diff --git a/app/ui-utils/client/lib/RoomManager.js b/app/ui-utils/client/lib/RoomManager.js
index 4c02125d58ff..9dd8631cbf5e 100644
--- a/app/ui-utils/client/lib/RoomManager.js
+++ b/app/ui-utils/client/lib/RoomManager.js
@@ -14,10 +14,10 @@ import { CachedCollectionManager } from '../../../ui-cached-collection';
import _ from 'underscore';
import { upsertMessage, RoomHistoryManager } from './RoomHistoryManager';
import { mainReady } from './mainReady';
+import { getConfig } from '../config';
-
-const maxRoomsOpen = parseInt(localStorage && localStorage.getItem('rc-maxRoomsOpen')) || 5 ;
+const maxRoomsOpen = parseInt(getConfig('maxRoomsOpen')) || 5 ;
const onDeleteMessageStream = (msg) => {
ChatMessage.remove({ _id: msg._id });
diff --git a/app/ui/client/components/popupList.html b/app/ui/client/components/popupList.html
index a24033e30c07..49318e3aea9e 100644
--- a/app/ui/client/components/popupList.html
+++ b/app/ui/client/components/popupList.html
@@ -6,16 +6,20 @@
-
+
+ {{_ "Loading"}}.
+
+