From e6f5f612a7779fa587336508165002ba52a54159 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Wed, 17 Apr 2019 15:27:29 -0300 Subject: [PATCH 1/5] created function to allow change default configs --- app/emoji/client/emojiParser.js | 64 +++++----- app/highlight-words/client/client.js | 12 +- app/lib/client/lib/formatDate.js | 11 +- app/logger/client/logger.js | 115 +++++++++--------- app/mentions/client/client.js | 18 ++- app/threads/client/flextab/thread.js | 2 +- app/ui-utils/client/config.js | 6 + app/ui-utils/client/lib/RoomHistoryManager.js | 3 +- app/ui-utils/client/lib/RoomManager.js | 4 +- package-lock.json | 46 ++++++- 10 files changed, 180 insertions(+), 101 deletions(-) create mode 100644 app/ui-utils/client/config.js diff --git a/app/emoji/client/emojiParser.js b/app/emoji/client/emojiParser.js index ff1a7b3dee1b..9c7172aa3227 100644 --- a/app/emoji/client/emojiParser.js +++ b/app/emoji/client/emojiParser.js @@ -1,61 +1,61 @@ 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, '\''); - 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, '
'); - // '
' to '
' for emojis such at line breaks - message.html = message.html.replace(/
/g, '
'); + message.html = Object.entries(emoji.packages).reduce((value, [, emojiPackage]) => emojiPackage.render(value), message.html); - Object.keys(emoji.packages).forEach((emojiPackage) => { - message.html = emoji.packages[emojiPackage].render(message.html); - }); + const checkEmojiOnly = $(`
${ message.html }
`); + let emojiOnly = true; - 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]); - if (child.hasClass('emoji') || child.hasClass('emojione')) { - checkEmojiOnly[0].childNodes[childNode] = child.addClass('big'); + for (let i = 0, len = checkEmojiOnly[0].childNodes.length; i < len; i++) { + const childNode = checkEmojiOnly[0].childNodes[i]; + + 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..2d03dc678612 100644 --- a/app/highlight-words/client/client.js +++ b/app/highlight-words/client/client.js @@ -3,12 +3,19 @@ * @param {Object} message - The message object */ 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'; +let to_highlight; + +Tracker.autorun(() => { + to_highlight = getUserPreference(Meteor.userId(), 'highlights'); +}); + function HighlightWordsClient(message) { let msg = message; if (!_.isString(message)) { @@ -19,10 +26,7 @@ function HighlightWordsClient(message) { } } - const to_highlight = getUserPreference(Meteor.user(), 'highlights'); - msg = highlightWords(msg, to_highlight); - - message.html = msg; + message.html = highlightWords(msg, to_highlight); return message; } diff --git a/app/lib/client/lib/formatDate.js b/app/lib/client/lib/formatDate.js index 2d2bd13b785a..8d5d68f95b79 100644 --- a/app/lib/client/lib/formatDate.js +++ b/app/lib/client/lib/formatDate.js @@ -1,10 +1,17 @@ import { Meteor } from 'meteor/meteor'; +import { Tracker } from 'meteor/tracker'; import { getUserPreference, t } from '../../../utils'; import { settings } from '../../../settings'; import moment from 'moment'; +let clockMode; + +Tracker.autorun(() => { + clockMode = getUserPreference(Meteor.userId(), 'clockMode', false); +}); + export const formatTime = (time) => { - switch (getUserPreference(Meteor.userId(), 'clockMode', false)) { + switch (clockMode) { case 1: return moment(time).format('h:mm A'); case 2: @@ -15,7 +22,7 @@ export const formatTime = (time) => { }; 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: 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..a3738d823db6 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; + +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/threads/client/flextab/thread.js b/app/threads/client/flextab/thread.js index 96f70d058cd3..da1a517ee65d 100644 --- a/app/threads/client/flextab/thread.js +++ b/app/threads/client/flextab/thread.js @@ -76,7 +76,7 @@ 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.chatMessages.wrapper.scrollTop = this.chatMessages.wrapper.scrollHeight - this.chatMessages.wrapper.clientHeight; this.sendToBottom = _.throttle(() => { this.chatMessages.wrapper.scrollTop = this.chatMessages.wrapper.scrollHeight; 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 cd0ec20625ad..803ccf321a2e 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 16ab3968accc..01fb45268e25 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/package-lock.json b/package-lock.json index 1dcf04d4efac..1b9c6bd96517 100644 --- a/package-lock.json +++ b/package-lock.json @@ -674,6 +674,19 @@ "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" }, + "@rocket.chat/apps-engine": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@rocket.chat/apps-engine/-/apps-engine-1.4.1.tgz", + "integrity": "sha512-zANc5wqUBo2eQpiUjdlH8wE/Yqhm96v6wSUcgUnSkAUpcw36kNlVcghKVsB/qvtQyOuJxRaQYuyR6V33oqtTDg==", + "requires": { + "adm-zip": "^0.4.9", + "lodash.clonedeep": "^4.5.0", + "semver": "^5.5.0", + "stack-trace": "0.0.10", + "typescript": "^2.9.2", + "uuid": "^3.2.1" + } + }, "@rocket.chat/eslint-config": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@rocket.chat/eslint-config/-/eslint-config-0.2.0.tgz", @@ -8875,6 +8888,18 @@ "hoek": "2.x.x", "joi": "6.x.x", "wreck": "5.x.x" + }, + "dependencies": { + "wreck": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/wreck/-/wreck-5.6.1.tgz", + "integrity": "sha1-r/ADBAATiJ11YZtccYcN0qjdBpo=", + "dev": true, + "requires": { + "boom": "2.x.x", + "hoek": "2.x.x" + } + } } }, "heavy": { @@ -8886,6 +8911,20 @@ "boom": "2.x.x", "hoek": "2.x.x", "joi": "5.x.x" + }, + "dependencies": { + "joi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-5.1.0.tgz", + "integrity": "sha1-FSrQfbjunGQBmX/1/SwSiWBwv1g=", + "dev": true, + "requires": { + "hoek": "^2.2.x", + "isemail": "1.x.x", + "moment": "2.x.x", + "topo": "1.x.x" + } + } } }, "hoek": { @@ -13845,7 +13884,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" }, "simple-get": { @@ -16417,6 +16456,11 @@ "resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.16.0.tgz", "integrity": "sha512-V60F7OHPH7vPlgIU73vYyeebKxWjQqCTlge+MvKlVn09PIhCOi/ZotowYdgREHB5S1dyHOr906ui6NheYXjlVQ==" }, + "typescript": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", + "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==" + }, "ua-parser-js": { "version": "0.7.19", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.19.tgz", From 2583c55dc11ca21e498037686e2bc3c8e93957d0 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Wed, 17 Apr 2019 17:29:17 -0300 Subject: [PATCH 2/5] search loading and improve highlightWords --- .../creationDialog/CreateDiscussion.html | 10 ++--- app/highlight-words/client/client.js | 39 +++++++++------- app/highlight-words/client/helper.js | 44 +++++++------------ app/highlight-words/tests/helper.tests.js | 26 ++++++++--- app/theme/client/imports/forms/popup-list.css | 2 - app/ui/client/components/popupList.html | 18 +++++--- app/ui/client/components/popupList.js | 2 + app/ui/client/views/app/createChannel.html | 9 +--- app/ui/client/views/app/room.js | 2 +- 9 files changed, 80 insertions(+), 72 deletions(-) diff --git a/app/discussion/client/views/creationDialog/CreateDiscussion.html b/app/discussion/client/views/creationDialog/CreateDiscussion.html index 68f300872b08..df30ab31834f 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}} {{/with}} + {{/with}}
{{ description }}
diff --git a/app/highlight-words/client/client.js b/app/highlight-words/client/client.js index 2d03dc678612..c3e5102d1d16 100644 --- a/app/highlight-words/client/client.js +++ b/app/highlight-words/client/client.js @@ -8,26 +8,31 @@ import { callbacks } from '../../callbacks'; import { getUserPreference } from '../../utils'; import _ from 'underscore'; import s from 'underscore.string'; -import { highlightWords } from './helper'; - -let to_highlight; +import { highlightWords, getRegexHighlight, getRegexHighlightUrl } from './helper'; Tracker.autorun(() => { - to_highlight = getUserPreference(Meteor.userId(), 'highlights'); -}); + const toHighlight = (getUserPreference(Meteor.userId(), 'highlights') || []).filter((highlight) => !s.isBlank(highlight)).map((highlight) => ({ + highlight, + regex: getRegexHighlight(highlight), + urlRegex: getRegexHighlightUrl(highlight), + })); -function HighlightWordsClient(message) { - let msg = message; - if (!_.isString(message)) { - if (s.trim(message.html)) { - msg = message.html; - } else { - return message; - } + if (!toHighlight.length) { + return callbacks.remove('renderMessage', 'highlight-words'); } - message.html = highlightWords(msg, to_highlight); - return message; -} + function HighlightWordsClient(message) { + let msg = message; -callbacks.add('renderMessage', HighlightWordsClient, callbacks.priority.MEDIUM + 1, 'highlight-words'); + if (!_.isString(message)) { + if (!s.trim(message.html)) { + return message; + } + msg = message.html; + } + + 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/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/ui/client/components/popupList.html b/app/ui/client/components/popupList.html index 6374a40c1500..ccc18059c780 100644 --- a/app/ui/client/components/popupList.html +++ b/app/ui/client/components/popupList.html @@ -6,16 +6,20 @@ + +