Do not highlight usernames inside links (#366)
sweet! * Do not highlight usernames inside words Fixes #156 * Do not search on separate words * Add accuracy options to markjs
This commit is contained in:
parent
f8d94c2dc2
commit
aeb221b32f
2
build/.gitignore
vendored
Normal file
2
build/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
node_modules
|
||||||
|
web_modules
|
5
build/javascript/package-lock.json
generated
5
build/javascript/package-lock.json
generated
@ -1467,6 +1467,11 @@
|
|||||||
"global": "^4.3.2"
|
"global": "^4.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mark.js": {
|
||||||
|
"version": "8.11.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz",
|
||||||
|
"integrity": "sha1-GA8fnr74sOY45BZq1S24eb6y/8U="
|
||||||
|
},
|
||||||
"mdn-data": {
|
"mdn-data": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz",
|
||||||
|
@ -6,12 +6,13 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@joeattardi/emoji-button": "^4.5.0",
|
"@joeattardi/emoji-button": "^4.5.0",
|
||||||
"@justinribeiro/lite-youtube": "^0.9.1",
|
"@justinribeiro/lite-youtube": "^0.9.1",
|
||||||
|
"@videojs/http-streaming": "2.3.0",
|
||||||
"@videojs/themes": "^1.0.1",
|
"@videojs/themes": "^1.0.1",
|
||||||
"htm": "^3.0.4",
|
"htm": "^3.0.4",
|
||||||
|
"mark.js": "^8.11.1",
|
||||||
"preact": "^10.5.7",
|
"preact": "^10.5.7",
|
||||||
"tailwindcss": "^1.9.6",
|
"tailwindcss": "^1.9.6",
|
||||||
"video.js": "7.10.2",
|
"video.js": "7.10.2"
|
||||||
"@videojs/http-streaming": "2.3.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"cssnano": "^4.1.10",
|
"cssnano": "^4.1.10",
|
||||||
@ -27,6 +28,7 @@
|
|||||||
"@justinribeiro/lite-youtube",
|
"@justinribeiro/lite-youtube",
|
||||||
"htm",
|
"htm",
|
||||||
"preact",
|
"preact",
|
||||||
|
"mark.js/dist/mark.es6.min.js",
|
||||||
"tailwindcss/dist/tailwind.min.css"
|
"tailwindcss/dist/tailwind.min.css"
|
||||||
],
|
],
|
||||||
"alias": {
|
"alias": {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { h, Component } from '/js/web_modules/preact.js';
|
import { h, Component } from '/js/web_modules/preact.js';
|
||||||
import htm from '/js/web_modules/htm.js';
|
import htm from '/js/web_modules/htm.js';
|
||||||
|
import Mark from '/js/web_modules/markjs/dist/mark.es6.min.js';
|
||||||
const html = htm.bind(h);
|
const html = htm.bind(h);
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -10,11 +11,27 @@ import { convertToText } from '../../utils/chat.js';
|
|||||||
import { SOCKET_MESSAGE_TYPES } from '../../utils/websocket.js';
|
import { SOCKET_MESSAGE_TYPES } from '../../utils/websocket.js';
|
||||||
|
|
||||||
export default class ChatMessageView extends Component {
|
export default class ChatMessageView extends Component {
|
||||||
render() {
|
async componentDidUpdate(prevProps) {
|
||||||
const { message, username } = this.props;
|
const { message, username } = this.props;
|
||||||
const { author, body, timestamp } = message;
|
if (prevProps.message === message && this.state.formattedMessage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { body } = message;
|
||||||
|
|
||||||
const formattedMessage = formatMessageText(body, username);
|
const formattedMessage = await formatMessageText(body, username);
|
||||||
|
this.setState({
|
||||||
|
formattedMessage
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const { message } = this.props;
|
||||||
|
const { author, timestamp } = message;
|
||||||
|
|
||||||
|
const { formattedMessage } = this.state;
|
||||||
|
if (!formattedMessage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const formattedTimestamp = formatTimestamp(timestamp);
|
const formattedTimestamp = formatTimestamp(timestamp);
|
||||||
|
|
||||||
const isSystemMessage = message.type === SOCKET_MESSAGE_TYPES.SYSTEM;
|
const isSystemMessage = message.type === SOCKET_MESSAGE_TYPES.SYSTEM;
|
||||||
@ -60,21 +77,30 @@ function getChatMessageClassString() {
|
|||||||
return 'message flex flex-row items-start p-3 m-3 rounded-lg shadow-s text-sm';
|
return 'message flex flex-row items-start p-3 m-3 rounded-lg shadow-s text-sm';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatMessageText(message, username) {
|
export async function formatMessageText(message, username) {
|
||||||
let formattedText = highlightUsername(message, username);
|
let formattedText = getMessageWithEmbeds(message);
|
||||||
formattedText = getMessageWithEmbeds(formattedText);
|
formattedText = convertToMarkup(formattedText);
|
||||||
return convertToMarkup(formattedText);
|
return await highlightUsername(formattedText, username);
|
||||||
}
|
}
|
||||||
|
|
||||||
function highlightUsername(message, username) {
|
function highlightUsername(message, username) {
|
||||||
const pattern = new RegExp(
|
// https://github.com/julmot/mark.js/issues/115
|
||||||
'@?' + username.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'),
|
const node = document.createElement('span');
|
||||||
'gi'
|
node.innerHTML = message;
|
||||||
);
|
return new Promise(res => {
|
||||||
return message.replace(
|
new Mark(node).mark(username, {
|
||||||
pattern,
|
element: 'span',
|
||||||
'<span class="highlighted px-1 rounded font-bold bg-orange-500">$&</span>'
|
className: 'highlighted px-1 rounded font-bold bg-orange-500',
|
||||||
);
|
separateWordSearch: false,
|
||||||
|
accuracy: {
|
||||||
|
value: 'exactly',
|
||||||
|
limiters: [",", ".", "'", '?', '@'],
|
||||||
|
},
|
||||||
|
done() {
|
||||||
|
res(node.innerHTML);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMessageWithEmbeds(message) {
|
function getMessageWithEmbeds(message) {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { c as createCommonjsModule, g as getDefaultExportFromCjs, d as document_1, w as window_1, a as core, b as commonjsGlobal } from '../../../common/core-b8f2ee39.js';
|
import { c as createCommonjsModule, g as getDefaultExportFromCjs, a as commonjsGlobal } from '../../../common/_commonjsHelpers-37fa8da4.js';
|
||||||
|
import { d as document_1, w as window_1, c as core } from '../../../common/core-440932cf.js';
|
||||||
|
|
||||||
//[4] NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
|
//[4] NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
|
||||||
//[4a] NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
|
//[4a] NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
|
||||||
|
25
webroot/js/web_modules/common/_commonjsHelpers-37fa8da4.js
Normal file
25
webroot/js/web_modules/common/_commonjsHelpers-37fa8da4.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
||||||
|
|
||||||
|
function getDefaultExportFromCjs (x) {
|
||||||
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createCommonjsModule(fn, basedir, module) {
|
||||||
|
return module = {
|
||||||
|
path: basedir,
|
||||||
|
exports: {},
|
||||||
|
require: function (path, base) {
|
||||||
|
return commonjsRequire(path, (base === undefined || base === null) ? module.path : base);
|
||||||
|
}
|
||||||
|
}, fn(module, module.exports), module.exports;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDefaultExportFromNamespaceIfNotNamed (n) {
|
||||||
|
return n && Object.prototype.hasOwnProperty.call(n, 'default') && Object.keys(n).length === 1 ? n['default'] : n;
|
||||||
|
}
|
||||||
|
|
||||||
|
function commonjsRequire () {
|
||||||
|
throw new Error('Dynamic requires are not currently supported by @rollup/plugin-commonjs');
|
||||||
|
}
|
||||||
|
|
||||||
|
export { commonjsGlobal as a, getDefaultExportFromNamespaceIfNotNamed as b, createCommonjsModule as c, getDefaultExportFromCjs as g };
|
29619
webroot/js/web_modules/common/core-440932cf.js
Normal file
29619
webroot/js/web_modules/common/core-440932cf.js
Normal file
File diff suppressed because it is too large
Load Diff
1
webroot/js/web_modules/import-map.json
vendored
1
webroot/js/web_modules/import-map.json
vendored
@ -5,6 +5,7 @@
|
|||||||
"@videojs/http-streaming/dist/videojs-http-streaming.min.js": "./@videojs/http-streaming/dist/videojs-http-streaming.min.js",
|
"@videojs/http-streaming/dist/videojs-http-streaming.min.js": "./@videojs/http-streaming/dist/videojs-http-streaming.min.js",
|
||||||
"@videojs/themes/fantasy/index.css": "./@videojs/themes/fantasy/index.css",
|
"@videojs/themes/fantasy/index.css": "./@videojs/themes/fantasy/index.css",
|
||||||
"htm": "./htm.js",
|
"htm": "./htm.js",
|
||||||
|
"mark.js/dist/mark.es6.min.js": "./markjs/dist/mark.es6.min.js",
|
||||||
"preact": "./preact.js",
|
"preact": "./preact.js",
|
||||||
"tailwindcss/dist/tailwind.min.css": "./tailwindcss/dist/tailwind.min.css",
|
"tailwindcss/dist/tailwind.min.css": "./tailwindcss/dist/tailwind.min.css",
|
||||||
"video.js": "./video.js/core.js",
|
"video.js": "./video.js/core.js",
|
||||||
|
13
webroot/js/web_modules/markjs/dist/mark.es6.min.js
vendored
Normal file
13
webroot/js/web_modules/markjs/dist/mark.es6.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -1 +1,2 @@
|
|||||||
export { a as default } from '../common/core-b8f2ee39.js';
|
import '../common/_commonjsHelpers-37fa8da4.js';
|
||||||
|
export { c as default } from '../common/core-440932cf.js';
|
||||||
|
Loading…
Reference in New Issue
Block a user