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
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); }
<div id='_form'> Form Inputs </div> <div id='_preview' style='display: none'> Preview </div> <button id='_toggle'> Toggle </button> <script> window._toggle.onclick = () => previewFormInputs(); // can also do the following instead of the above /* window._toggle.onclick = previewFormInputs; */ function setElementVisibility(element, visible) { element.style.display = visible ? 'inherit' : 'none'; } let _previewVisible = false; function previewFormInputs() { _previewVisible = !_previewVisible; setElementVisibility(window._form, !_previewVisible); setElementVisibility(window._preview, _previewVisible); } </script>Live: https://jsfiddle.net/sewa4jh1/1/
<div id='_form'> Form Inputs </div> <div id='_preview' style='display: none'> Preview </div> <button id='_toggle'> Toggle </button> <script> window._toggle.onclick = () => previewFormInputs(); // can also do the following instead of the above // _stats.onclick = previewFormInputs; function setElementVisibility(element, visible) { element.style.display = visible ? 'inherit' : 'none'; } const previewFormInputs = (function () { let previewVisible = false; return function () { previewVisible = !previewVisible; setElementVisibility(window._form, !previewVisible); setElementVisibility(window._preview, previewVisible); } })(); </script>Live: https://jsfiddle.net/sewa4jh1/3/
Multiple nots. Complex firstname != 'Juan' || lastname != 'Cruz' English-speak: If your firstname is not Juan or your lastname is not Cruz, therefore you are not Juan Cruz Don't use the above, it has multiple nots. Use this: Single not, simple. Translates well to English: !(firstname == 'Juan' && lastname == 'Cruz') English-speak (reading from inside out): If you are Juan Cruz, then don't. English-speak (reading from left to right): If you are not Juan Cruz, then do. Postgres tuple test: (firstname, lastname) != ('Juan', 'Cruz') Languages without tuple: firstname + ' ' + lastname != 'Juan Cruz' **Schema (PostgreSQL v13)** create table person(firstname text, lastname text); insert into person(firstname, lastname) values ('Juan', 'Cruz'), ('Juan', 'Buen'), ('Michael', 'Cruz'), ('Michael', 'Buen'); --- **Query #1** select firstname, lastname, firstname != 'Juan' or lastname != 'Cruz' as test1, not (firstname = 'Juan' and lastname = 'Cruz') as test2, (firstname, lastname) != ('Juan', 'Cruz') as test3, (firstname || ' ' || lastname) != 'Juan Cruz' as test4 from person; | firstname | lastname | test1 | test2 | test3 | test4 | | --------- | -------- | ----- | ----- | ----- | ----- | | Juan | Cruz | false | false | false | false | | Juan | Buen | true | true | true | true | | Michael | Cruz | true | true | true | true | | Michael | Buen | true | true | true | true | --- [View on DB Fiddle](https://www.db-fiddle.com/f/nxbuszjT4zgmdj4pGaZeuQ/0) ------------- Multiple nots. Complex firstname != 'Juan' && lastname != 'Cruz' Single not, simple. Translates well to English: !(firstname == 'Juan' || lastname == 'Cruz') English-speak: If your firstname is Juan or lastname is Cruz, then don't. **Schema (PostgreSQL v13)** create table person(firstname text, lastname text); insert into person(firstname, lastname) values ('Juan', 'Cruz'), ('Juan', 'Buen'), ('Michael', 'Cruz'), ('Michael', 'Buen'); --- **Query #1** select firstname, lastname, firstname != 'Juan' and lastname != 'Cruz' as test1, not (firstname = 'Juan' or lastname = 'Cruz') as test2 from person; | firstname | lastname | test1 | test2 | | --------- | -------- | ----- | ----- | | Juan | Cruz | false | false | | Juan | Buen | false | false | | Michael | Cruz | false | false | | Michael | Buen | true | true | --- [View on DB Fiddle](https://www.db-fiddle.com/f/nxbuszjT4zgmdj4pGaZeuQ/1)
function tokenizeZH(text) { const segmenter = new Intl.Segmenter('zh', { granularity: 'word' }); const segments = segmenter.segment(text); const words = []; for (const { segment /* , index, isWordLike */ } of segments) { words.push(segment); } return words; } console.log(tokenizeZH('我不是太清楚'));
["我不是", "太", "清楚"]
chrome.runtime.onMessage.addListener(async (message /* , sender, sendResponse */) => { if (message.action === UPDATE_PAGE) { await applyStyleFromSettings(); } // https://stackoverflow.com/questions/53024819/chrome-extension-sendresponse-not-waiting-for-async-function return true; });Returning true is not enough, to fully fix the problem, we must place the async code on the code body itself, not on the callback's declaration. Remove the async declaration from the listener, move it to the code's body instead
chrome.runtime.onMessage.addListener((message /*, sender, sendResponse */) => { (async () => { if (message.action === UPDATE_PAGE) { await applyStyleFromSettings(); } })(); // https://stackoverflow.com/questions/53024819/chrome-extension-sendresponse-not-waiting-for-async-function return true; });
interface IHskLevel { hanzi: string; hsk: number; }This code does not produce compile error (it should):
function* generateHskLevel(): Iterable<IHskLevel> { yield* json.map( ({ hanzi, pinyin, HSK: hsk }) => ({ hanzi, pinyin, hsk }) ); }This produces compile error (it should):
function* generateHskLevel(): Iterable<IHskLevel> { for (const { hanzi, pinyin, HSK: hsk } of json) { yield { hanzi, pinyin, hsk }; } }Error:
error: TS2322 [ERROR]: Type '{ hanzi: string; pinyin: string; hsk: number; }' is not assignable to type 'IHskLevel'. Object literal may only specify known properties, and 'pinyin' does not exist in type 'IHskLevel'. pinyin,
// eslint-disable-next-line no-undef chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { if (request.dataNeeded === HANZI) { (async () => { const hzl = await loadHanziListFile(); sendResponse({data: hzl}); })(); // Need to return true if we are using async code in addListener. // Without this line.. return true; // ..we will receive the error: // Uncaught (in promise) The message port closed before a response was received } });
// eslint-disable-next-line no-undef chrome.action.onClicked.addListener((tab) => { console.log("working"); // eslint-disable-next-line no-undef chrome.tabs.sendMessage( // tabs[0].id, tab.id, { action: "CHANGE_COLOR" }, // eslint-disable-next-line no-unused-vars function (response) {} ); });I'm using manifest version 3:
{ "name": "Chinese word separator", "description": "Put spaces between words", "version": "1.0", "manifest_version": 3, "background" : { "service_worker": "background.js" }, "content_scripts": [ { "matches": ["<all_urls>"], "css": [], "js": ["contentScript.js"] } ] }
To fix the error, add the action property even if it is empty:
{ "name": "Chinese word separator", "description": "Put spaces between words", "version": "1.0", "manifest_version": 3, "action": {}, "background" : { "service_worker": "background.js" }, "content_scripts": [ { "matches": ["<all_urls>"], "css": [], "js": ["contentScript.js"] } ] }It is advisable to wrap the background.js via a wrapper so you'll get better error message, so if there's no action property in manifest.json..
{ "name": "Chinese word separator", "description": "Put spaces between words", "version": "1.0", "manifest_version": 3, "background" : { "service_worker": "background-wrapper.js" }, "content_scripts": [ { "matches": ["<all_urls>"], "css": [], "js": ["contentScript.js"] } ] }..and you wrap the background via wrapper (e.g., background-wrapper.js)..
try { // eslint-disable-next-line no-undef importScripts("./background.js"); } catch (e) { console.error(e); }..you will receive a more descriptive error instead:
background-wrapper.js:5 TypeError: Cannot read property 'onClicked' of undefined at background.js:1 at background-wrapper.js:3 (anonymous) @ background-wrapper.js:5To fix the error, add action on manifest.json
<div id="parent"> <div id="child">hello world</div> </div>Centering with margin, it has to be done at child level:
#parent { width: 50vw; height: 50vh; background-color: gray; display: flex; } #child { margin: auto; }Try it at: https://jsfiddle.net/xd7uwgn8/
#parent { width: 50vw; height: 50vh; background-color: gray; display: flex; justify-content: center; align-items: center; } #child { }Try it at: https://jsfiddle.net/xd7uwgn8/2/
<div id="parent"> hello world </div>Try it at: https://jsfiddle.net/xd7uwgn8/3/
{ "description": "Dvorak navigations - no place like home keys", "manipulators": [ { "from": { "key_code": "v", "modifiers": { "mandatory": [ "left_control", "left_option" ] } }, "to": [ { "key_code": "end", "modifiers" : [ "left_shift" ] }, { "key_code": "delete_or_backspace" } ], "type": "basic" }, { "from": { "key_code": "f", "modifiers": { "mandatory": [ "left_control", "left_option" ] } }, "to": [ { "key_code": "home" }, { "key_code": "end", "modifiers" : [ "left_shift" ] }, { "key_code": "delete_or_backspace" } ], "type": "basic" }, { "from": { "key_code": "j", "modifiers": { "mandatory": [ "left_control" ] } }, "to": [ { "key_code": "delete_or_backspace" } ], "type": "basic" }, { "from": { "key_code": "j", "modifiers": { "mandatory": [ "left_control", "left_option" ] } }, "to": [ { "key_code": "delete_or_backspace", "modifiers": [ "left_option" ] } ], "type": "basic" }, { "from": { "key_code": "h", "modifiers": { "mandatory": [ "left_control" ] } }, "to": [ { "key_code": "delete_forward" } ], "type": "basic" }, { "from": { "key_code": "h", "modifiers": { "mandatory": [ "left_control", "left_option" ] } }, "to": [ { "key_code": "delete_forward", "modifiers": [ "left_option" ] } ], "type": "basic" }, { "from": { "key_code": "l", "modifiers": { "mandatory": [ "left_control" ] } }, "to": [ { "key_code": "down_arrow" } ], "type": "basic" }, { "from": { "key_code": "l", "modifiers": { "mandatory": [ "left_control", "left_shift" ] } }, "to": [ { "key_code": "down_arrow", "modifiers": [ "left_shift" ] } ], "type": "basic" }, { "from": { "key_code": "r", "modifiers": { "mandatory": [ "left_control" ] } }, "to": [ { "key_code": "up_arrow" } ], "type": "basic" }, { "from": { "key_code": "r", "modifiers": { "mandatory": [ "left_control", "left_shift" ] } }, "to": [ { "key_code": "up_arrow", "modifiers": [ "left_shift" ] } ], "type": "basic" }, { "from": { "key_code": "y", "modifiers": { "mandatory": [ "left_control", "left_option" ] } }, "to": [ { "key_code": "right_arrow", "modifiers": [ "left_option" ] } ], "type": "basic" }, { "from": { "key_code": "y", "modifiers": { "mandatory": [ "left_control", "left_option", "left_shift" ] } }, "to": [ { "key_code": "right_arrow", "modifiers": [ "left_option", "left_shift" ] } ], "type": "basic" }, { "from": { "key_code": "n", "modifiers": { "mandatory": [ "left_control", "left_option" ] } }, "to": [ { "key_code": "left_arrow", "modifiers": [ "left_option" ] } ], "type": "basic" }, { "from": { "key_code": "n", "modifiers": { "mandatory": [ "left_control", "left_option", "left_shift" ] } }, "to": [ { "key_code": "left_arrow", "modifiers": [ "left_option", "left_shift" ] } ], "type": "basic" } ] },
% ssh-addSolution source: https://superuser.com/questions/360686/what-exactly-does-ssh-add-do
% cat ~/.scripts/cra.sh #!/bin/zsh if [ $# -eq 0 ] ; then echo "Pass the name of project" exit 1 fi NAME="$1" yarn dlx create-react-app $NAME --template typescript cd $NAME yarn dlx @yarnpkg/pnpify --sdk vscode yarn add react-refresh eslint-config-react-app TO_DECLARE="declare module '@testing-library/react';" printf $TO_DECLARE >> src/react-app-env.d.ts code-insiders .
$ yarn add react-refresh eslint-config-react-app