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"
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz",
|
||||
|
@ -6,12 +6,13 @@
|
||||
"dependencies": {
|
||||
"@joeattardi/emoji-button": "^4.5.0",
|
||||
"@justinribeiro/lite-youtube": "^0.9.1",
|
||||
"@videojs/http-streaming": "2.3.0",
|
||||
"@videojs/themes": "^1.0.1",
|
||||
"htm": "^3.0.4",
|
||||
"mark.js": "^8.11.1",
|
||||
"preact": "^10.5.7",
|
||||
"tailwindcss": "^1.9.6",
|
||||
"video.js": "7.10.2",
|
||||
"@videojs/http-streaming": "2.3.0"
|
||||
"video.js": "7.10.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cssnano": "^4.1.10",
|
||||
@ -27,6 +28,7 @@
|
||||
"@justinribeiro/lite-youtube",
|
||||
"htm",
|
||||
"preact",
|
||||
"mark.js/dist/mark.es6.min.js",
|
||||
"tailwindcss/dist/tailwind.min.css"
|
||||
],
|
||||
"alias": {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { h, Component } from '/js/web_modules/preact.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);
|
||||
|
||||
import {
|
||||
@ -10,11 +11,27 @@ import { convertToText } from '../../utils/chat.js';
|
||||
import { SOCKET_MESSAGE_TYPES } from '../../utils/websocket.js';
|
||||
|
||||
export default class ChatMessageView extends Component {
|
||||
render() {
|
||||
async componentDidUpdate(prevProps) {
|
||||
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 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';
|
||||
}
|
||||
|
||||
export function formatMessageText(message, username) {
|
||||
let formattedText = highlightUsername(message, username);
|
||||
formattedText = getMessageWithEmbeds(formattedText);
|
||||
return convertToMarkup(formattedText);
|
||||
export async function formatMessageText(message, username) {
|
||||
let formattedText = getMessageWithEmbeds(message);
|
||||
formattedText = convertToMarkup(formattedText);
|
||||
return await highlightUsername(formattedText, username);
|
||||
}
|
||||
|
||||
function highlightUsername(message, username) {
|
||||
const pattern = new RegExp(
|
||||
'@?' + username.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'),
|
||||
'gi'
|
||||
);
|
||||
return message.replace(
|
||||
pattern,
|
||||
'<span class="highlighted px-1 rounded font-bold bg-orange-500">$&</span>'
|
||||
);
|
||||
// https://github.com/julmot/mark.js/issues/115
|
||||
const node = document.createElement('span');
|
||||
node.innerHTML = message;
|
||||
return new Promise(res => {
|
||||
new Mark(node).mark(username, {
|
||||
element: 'span',
|
||||
className: 'highlighted px-1 rounded font-bold bg-orange-500',
|
||||
separateWordSearch: false,
|
||||
accuracy: {
|
||||
value: 'exactly',
|
||||
limiters: [",", ".", "'", '?', '@'],
|
||||
},
|
||||
done() {
|
||||
res(node.innerHTML);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
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]
|
||||
//[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/themes/fantasy/index.css": "./@videojs/themes/fantasy/index.css",
|
||||
"htm": "./htm.js",
|
||||
"mark.js/dist/mark.es6.min.js": "./markjs/dist/mark.es6.min.js",
|
||||
"preact": "./preact.js",
|
||||
"tailwindcss/dist/tailwind.min.css": "./tailwindcss/dist/tailwind.min.css",
|
||||
"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