From d18a9a057b7b916701ed9a7e582f105b618a20e3 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 12 Sep 2017 20:47:05 +0700 Subject: [PATCH] Implement simple regexp based highlighter --- .../src/components/CommentBodyHighlighter.js | 69 ++++++++++++++----- .../coral-admin/src/components/IfHasLink.js | 5 +- .../routes/Moderation/components/Comment.js | 4 +- client/coral-admin/src/utils/index.js | 1 + client/coral-admin/src/utils/regexp.js | 1 + package.json | 2 - yarn.lock | 31 +-------- 7 files changed, 57 insertions(+), 56 deletions(-) create mode 100644 client/coral-admin/src/utils/regexp.js diff --git a/client/coral-admin/src/components/CommentBodyHighlighter.js b/client/coral-admin/src/components/CommentBodyHighlighter.js index 9a430f7c7..f0c9f9c8d 100644 --- a/client/coral-admin/src/components/CommentBodyHighlighter.js +++ b/client/coral-admin/src/components/CommentBodyHighlighter.js @@ -1,25 +1,56 @@ import React from 'react'; -import Highlighter from 'react-highlight-words'; -import Linkify from 'react-linkify'; -const linkify = new Linkify(); +import {linkRegexp} from '../utils/regexp'; + +const wordSeperator = /([.\s'"?!])/; + +function markWords(body, words, index) { + const tokens = body.split(wordSeperator); + const content = []; + let tmp = []; + tokens.forEach((token, i) => { + if (words.indexOf(token.toLowerCase()) >= 0) { + content.push(...tmp); + tmp = []; + content.push({token}); + return; + } + tmp.push(token); + }); + content.push(...tmp); + return content; +} + +function markLinks(body) { + const tokens = body.split(linkRegexp); + const content = []; + let tmp = []; + tokens + .filter((token) => token) + .forEach((token, i) => { + if (token.match(linkRegexp)) { + content.push(...tmp); + tmp = []; + content.push({token}); + return; + } + tmp.push(token); + }); + content.push(...tmp); + return content; +} export default ({suspectWords, bannedWords, body, ...rest}) => { - - const links = linkify.getMatches(body); - const linkText = links ? links.map((link) => link.raw) : []; - - const searchWords = [ - ...suspectWords, - ...bannedWords, - ...linkText - ]; - + const words = [...suspectWords, ...bannedWords].map((word) => word.toLowerCase()); + const content = markLinks(body) + .map((element, index) => { + if (typeof element !== 'string') { + return element; + } + return markWords(element, words, index); + }); return ( - +
+ {content} +
); }; diff --git a/client/coral-admin/src/components/IfHasLink.js b/client/coral-admin/src/components/IfHasLink.js index cd37ea951..e6a96503d 100644 --- a/client/coral-admin/src/components/IfHasLink.js +++ b/client/coral-admin/src/components/IfHasLink.js @@ -1,9 +1,8 @@ import React from 'react'; -import Linkify from 'react-linkify'; -const linkify = new Linkify(); +import {linkRegexp} from '../utils/regexp'; export default ({text, children}) => { - const hasLinks = !!linkify.getMatches(text); + const hasLinks = text.match(linkRegexp); if (!hasLinks) { return null; diff --git a/client/coral-admin/src/routes/Moderation/components/Comment.js b/client/coral-admin/src/routes/Moderation/components/Comment.js index 9d9428bc4..a3edb4196 100644 --- a/client/coral-admin/src/routes/Moderation/components/Comment.js +++ b/client/coral-admin/src/routes/Moderation/components/Comment.js @@ -127,7 +127,7 @@ class Comment extends React.Component {
-

+

{t('comment.view_context')} -

+
mod === 'PRE'; export const getModPath = (type = 'all', assetId) => assetId ? `/admin/moderate/${type}/${assetId}` : `/admin/moderate/${type}`; + diff --git a/client/coral-admin/src/utils/regexp.js b/client/coral-admin/src/utils/regexp.js new file mode 100644 index 000000000..1544824dc --- /dev/null +++ b/client/coral-admin/src/utils/regexp.js @@ -0,0 +1 @@ +export const linkRegexp = /([-a-zA-Z0-9@:%_+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_+.~#?&//=]*)?)/; diff --git a/package.json b/package.json index 29ba80ae8..99939b46d 100644 --- a/package.json +++ b/package.json @@ -154,9 +154,7 @@ "react": "^15.4.2", "react-apollo": "^1.4.12", "react-dom": "^15.4.2", - "react-highlight-words": "^0.6.0", "react-input-autosize": "^1.1.4", - "react-linkify": "^0.1.3", "react-mdl": "^1.7.2", "react-mdl-selectfield": "^0.2.0", "react-recaptcha": "^2.2.6", diff --git a/yarn.lock b/yarn.lock index 1ca8acdbb..1fd1f5711 100644 --- a/yarn.lock +++ b/yarn.lock @@ -922,7 +922,7 @@ babel-register@^6.26.0: mkdirp "^0.5.1" source-map-support "^0.4.15" -babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0, babel-runtime@^6.6.1: +babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0, babel-runtime@^6.6.1: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" dependencies: @@ -3396,12 +3396,6 @@ hide-powered-by@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/hide-powered-by/-/hide-powered-by-1.0.0.tgz#4a85ad65881f62857fc70af7174a1184dccce32b" -highlight-words-core@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/highlight-words-core/-/highlight-words-core-1.0.3.tgz#0886d0e757c8ca3928cbc873042bd544f8f6b2e5" - dependencies: - babel-runtime "^6.11.6" - history@^3.0.0: version "3.3.0" resolved "https://registry.yarnpkg.com/history/-/history-3.3.0.tgz#fcedcce8f12975371545d735461033579a6dae9c" @@ -4395,12 +4389,6 @@ license-webpack-plugin@^1.0.0: dependencies: ejs "^2.5.7" -linkify-it@^1.2.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-1.2.4.tgz#0773526c317c8fd13bd534ee1d180ff88abf881a" - dependencies: - uc.micro "^1.0.1" - linkify-it@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" @@ -6379,12 +6367,6 @@ react-dom@^15.3.1, react-dom@^15.4.2: object-assign "^4.1.0" prop-types "~15.5.7" -react-highlight-words@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/react-highlight-words/-/react-highlight-words-0.6.0.tgz#e12e9fedda4333e410ea408cdedffc77122020aa" - dependencies: - highlight-words-core "^1.0.2" - react-input-autosize@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-1.1.4.tgz#cbc45072d4084ddc57806db8e3b34e644b8366ac" @@ -6392,13 +6374,6 @@ react-input-autosize@^1.1.4: create-react-class "^15.5.2" prop-types "^15.5.8" -react-linkify@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/react-linkify/-/react-linkify-0.1.3.tgz#6e886180bda6c8fdc5f9f8a7ebe82fc0f48db7ad" - dependencies: - linkify-it "^1.2.0" - tlds "^1.57.0" - react-mdl-selectfield@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/react-mdl-selectfield/-/react-mdl-selectfield-0.2.0.tgz#36e1a97233036c057ab2bdb31ec09ad8d9988411" @@ -7456,10 +7431,6 @@ title-case-minors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/title-case-minors/-/title-case-minors-1.0.0.tgz#51f17037c294747a1d1cda424b5004c86d8eb115" -tlds@^1.57.0: - version "1.185.0" - resolved "https://registry.yarnpkg.com/tlds/-/tlds-1.185.0.tgz#9d5ddaae379778a98e3edc3a131d46a40cbc3ba4" - tmp@^0.0.31: version "0.0.31" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7"