white-space: nowrap;
However, the above does not work on Safari. In Safari, use this instead:
white-space: pre; overflow-x: auto; word-wrap: normal;
https://stackoverflow.com/questions/657795/how-to-remove-word-wrap-from-textarea/25556711#25556711
Code as we know it. Open source stuff goes here
white-space: nowrap;
white-space: pre; overflow-x: auto; word-wrap: normal;
function escapeRegExp(text) { return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); }Lookbehind:
String.prototype.splitKeep = function (tokens) { const escaped = escapeRegExp(tokens); return this.split(new RegExp(`(?=[${escaped}])|(?<=[${escaped}])`, "g")); };Match. Safari does not support lookbehind, use match approach:
String.prototype.splitKeep = function (tokens) { const tokensEscaped = tokens .split("") .map((s) => escapeRegExp(s)) .join("|"); const wordMatch = `[^${escapeRegExp(tokens)}]+`; return this.match(new RegExp(tokensEscaped + "|" + wordMatch, "g")); };Loop-based approach:
String.prototype.splitKeep = function (tokens) { let toPush = ""; const splitList = []; for (const c of this) { if (tokens.includes(c)) { if (toPush.length > 0) { splitList.push(toPush); } splitList.push(c); toPush = ""; continue; } toPush += c; } if (toPush.length > 0) { splitList.push(toPush); } return splitList; };Benchmark code:
console.time("test"); for (let i = 0; i < 10000; ++i) { "pin1yin1".splitKeep("12345 "); } console.timeEnd("test");Results:
% node splitkeep-lookbehind.js test: 19.35ms % node splitkeep-lookbehind.js test: 18.951ms % node splitkeep-match.js test: 54.635ms % node splitkeep-match.js test: 51.998ms % node splitkeep-loop.js test: 14.647ms % node splitkeep-loop.js test: 13.035ms
Instead of this:
const VARIANT_CHAR = /variant of \p{Script=Han}/u; // 'variant of chineseCharacterHere' sorts last sort((a, b) => VARIANT_CHAR.test(a.definitions.join(' ')) && VARIANT_CHAR.test(b.definitions.join(' ')) ? 0 : VARIANT_CHAR.test(a.definitions.join(' ')) ? 1 : VARIANT_CHAR.test(b.definitions.join(' ')) ? -1 : 0 )
Just do this:
const VARIANT_CHAR = /variant of \p{Script=Han}/u; // 'variant of chineseCharacterHere' sorts last sort((a, b) => VARIANT_CHAR.test(a.definitions.join(' ')) - VARIANT_CHAR.test(b.definitions.join(' ')) )
$ xcrun safari-web-extension-converter xcrun: error: unable to find utility "safari-web-extension-converter", not a developer tool or in PATHDo this first:
sudo xcode-select -s /Applications/Xcode.app
. . . newHzl[hanzi].pinyin = newHzl[hanzi].pinyin.filter(eachPinyin => pinyinEnglish[eachPinyin]); } // for loopThat yields this error:
error: TS2532 [ERROR]: Object is possibly 'undefined'. newHzl[hanzi].pinyin = newHzl[hanzi].pinyin.filter(Got a similar error code on following code, and removed the error by checking if a variable has nothing, if nothing then skip(continue)
for (const [hanzi, { pinyinEnglish }] of Object.entries(hzl)) { if (!pinyinEnglish) { continue; } for (const pinyin of Object.keys(pinyinEnglish)) { if (pinyinEnglish[pinyin].length === 0) { delete pinyinEnglish[pinyin]; } } . . .I tried to do the same solution on the post's first code, but it still yields a compile error of Object is possibly 'undefined'
. . . if (!newHzl[hanzi].pinyin) { continue; } newHzl[hanzi].pinyin = newHzl[hanzi].pinyin.filter(eachPinyin => pinyinEnglish[eachPinyin]); } // for loopThe workaround is to introduce a variable so the compiler will not have a hard time inferring the code's control flow:
. . . const hanziPinyin = newHzl[hanzi].pinyin; if (!hanziPinyin) { continue; } newHzl[hanzi].pinyin = hanziPinyin.filter(eachPinyin => pinyinEnglish[eachPinyin]); } // for loopThe problem went away
String.prototype.splitKeep = function (tokens) { const escaped = escapeRegExp(tokens); return this.split(new RegExp(`(?=[${escaped}])|(?<=[${escaped}])`, 'g')); }; // Not built-in yet https://github.com/tc39/proposal-regex-escaping // Use a good one for the meantime https://stackoverflow.com/questions/3115150/how-to-escape-regular-expression-special-characters-using-javascript function escapeRegExp(text) { return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); }Add this when using TypeScript:
declare global { interface String { splitKeep(tokens: string): string[]; } }November 14 For browsers that the regex component don't have lookbehind capability yet, use match method:
String.prototype.splitKeep = function (tokens) { const tokensEscaped = tokens .split('') .map((s) => escapeRegExp(s)) .join('|'); const wordMatch = `[^${escapeRegExp(tokens)}]+`; return this.match(new RegExp(tokensEscaped + '|' + wordMatch, 'g')); };
<div id="something">Click or double click me</div> <hr/> <div id="good">Click or double click me</div> <style> #something, #good { background-color: lemonchiffon; } </style>JS:
addGlobalEventListener( 'click', '#something', debounceSingleClickOnly(sayHello) ); addGlobalEventListener( 'dblclick', '#something', sayWorld ); addGlobalEventListener( 'click', '#good', debounceSingleClickOnly(sayHello) ); addGlobalEventListener( 'dblclick', '#good', sayWorld ); let counter = 0; function sayHello({target: {id}}) { ++counter; console.log(`${counter}. clicked ${id}`); } function sayWorld({target: {id}}) { ++counter; console.log(`${counter}. double-clicked ${id}`); } function addGlobalEventListener(type, selector, callback) { document.addEventListener(type, (e) => { if (e.target.matches(selector)) { callback(e); } }); } function debounce(func, wait, immediate) { let timeout; return function () { const context = this, args = arguments; const later = function () { timeout = null; if (!immediate) func.apply(context, args); }; const callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func.apply(context, args); }; } function debounceSingleClickOnly(func, timeout = 500) { function eventHandler(event) { const { detail } = event; if (detail > 1) { return; } func.apply(this, arguments); } return debounce(eventHandler, timeout); }