diff --git a/scripts/manifests/chromemanifest.json b/scripts/manifests/chromemanifest.json index 9763385..8699897 100644 --- a/scripts/manifests/chromemanifest.json +++ b/scripts/manifests/chromemanifest.json @@ -13,8 +13,7 @@ }, "background": { - "scripts": ["browser-polyfill.js", "background/modules/InstallUpgrade.js", "background/background.js"], - "type": "module" + "page": "background.html" }, "content_scripts": [ { diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index 82825d2..9d2251c 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -139,6 +139,35 @@ "description": "An entry in the context menu. This is an entry for the case." }, + "menuCodeCaseCodeCasing": { + "message": "Change code casing", + "description": "An entry in the context menu. This is an entry for the case." + }, + "menuCodeCaseCamelCase": { + "message": "Camel case", + "description": "An entry in the context menu. This is an entry for the case." + }, + "menuCodeCaseUpperCamelCase": { + "message": "Upper camel case", + "description": "An entry in the context menu. This is an entry for the case." + }, + "menuCodeCaseSnakeCase": { + "message": "Snake case", + "description": "An entry in the context menu. This is an entry for the case." + }, + "menuCodeCaseConstantCase": { + "message": "Constant case", + "description": "An entry in the context menu. This is an entry for the case." + }, + "menuCodeCaseKebabCase": { + "message": "Kebab case", + "description": "An entry in the context menu. This is an entry for the case." + }, + "menuCodeCaseTrainCase": { + "message": "Train case", + "description": "An entry in the context menu. This is an entry for the case." + }, + "menuFontSuperscript": { "message": "Superscript", "description": "An entry in the context menu. This is an entry for the Unicode font." @@ -251,11 +280,40 @@ "message": "Squared (black)", "description": "An entry in the context menu. This is an entry for the Unicode font." }, + "menuFontParenthesized": { + "message": "Parenthesized", + "description": "An entry in the context menu. This is an entry for the Unicode font." + }, "menuFontFullwidth": { "message": "Fullwidth", "description": "An entry in the context menu. This is an entry for the Unicode font." }, + "menuFormatFormatting": { + "message": "Change formatting", + "description": "An entry in the context menu. This is an entry for the Unicode format." + }, + "menuFormatOverlined": { + "message": "Overlined", + "description": "An entry in the context menu. This is an entry for the Unicode format." + }, + "menuFormatDoubleOverlined": { + "message": "Double overlined", + "description": "An entry in the context menu. This is an entry for the Unicode format." + }, + "menuFormatStrikethrough": { + "message": "Strikethrough", + "description": "An entry in the context menu. This is an entry for the Unicode format." + }, + "menuFormatUnderlined": { + "message": "Underlined", + "description": "An entry in the context menu. This is an entry for the Unicode format." + }, + "menuFormatDoubleUnderlined": { + "message": "Double underlined", + "description": "An entry in the context menu. This is an entry for the Unicode format." + }, + // options "someSettingsAreManaged": { "message": "Some settings are managed by your system administrator and cannot be changed.", diff --git a/src/background/modules/ContextMenu.js b/src/background/modules/ContextMenu.js index 8e962ab..64197d3 100644 --- a/src/background/modules/ContextMenu.js +++ b/src/background/modules/ContextMenu.js @@ -126,10 +126,23 @@ async function buildMenu(unicodeFontSettings, exampleText = null) { } if (!unicodeFontSettings.nested && unicodeFontSettings.changeFont && + unicodeFontSettings.changeFormat && + !menuIsShown) { + await menus.create({ + id: "seperator-format-font", + type: "separator", + contexts: ["editable"] + }); + } + if (unicodeFontSettings.changeFormat) { + await addMenuItems(menuStructure[TRANSFORMATION_TYPE.FORMAT], unicodeFontSettings, exampleText); + } + if (!unicodeFontSettings.nested && + (unicodeFontSettings.changeFont || unicodeFontSettings.changeFormat) && unicodeFontSettings.changeCase && !menuIsShown) { await menus.create({ - id: "seperator-case-font", + id: "seperator-case-format", type: "separator", contexts: ["editable"] }); @@ -137,6 +150,19 @@ async function buildMenu(unicodeFontSettings, exampleText = null) { if (unicodeFontSettings.changeCase) { await addMenuItems(menuStructure[TRANSFORMATION_TYPE.CASING], unicodeFontSettings, exampleText); } + if (!unicodeFontSettings.nested && + (unicodeFontSettings.changeFont || unicodeFontSettings.changeFormat || unicodeFontSettings.changeCase) && + unicodeFontSettings.changeCodeCase && + !menuIsShown) { + await menus.create({ + id: "seperator-code-case", + type: "separator", + contexts: ["editable"] + }); + } + if (unicodeFontSettings.changeCodeCase) { + await addMenuItems(menuStructure[TRANSFORMATION_TYPE.CODE_CASING], unicodeFontSettings, exampleText); + } menuIsShown = true; } diff --git a/src/common/modules/UnicodeTransformationHandler.js b/src/common/modules/UnicodeTransformationHandler.js index e93ef9b..ccf8525 100644 --- a/src/common/modules/UnicodeTransformationHandler.js +++ b/src/common/modules/UnicodeTransformationHandler.js @@ -1,4 +1,4 @@ -import { fontLetters, CASE_ID_PREFIX, FONT_ID_PREFIX, TRANSFORMATION_TYPE } from "/common/modules/data/Fonts.js"; +import { fontLetters, formats, CASE_ID_PREFIX, CODE_CASE_ID_PREFIX, FONT_ID_PREFIX, FORMAT_ID_PREFIX, TRANSFORMATION_TYPE } from "/common/modules/data/Fonts.js"; /** * Transforms the given text according to the given transformation. @@ -12,11 +12,20 @@ import { fontLetters, CASE_ID_PREFIX, FONT_ID_PREFIX, TRANSFORMATION_TYPE } from export function transformText(text, transformationId) { let output = null; const transformationType = getTransformationType(transformationId); - if (transformationType === TRANSFORMATION_TYPE.CASING) { - output = changeCase[transformationId](text); - } else if (transformationType === TRANSFORMATION_TYPE.FONT) { + switch (transformationType) { + case TRANSFORMATION_TYPE.CASING: + output = changeCase[transformationId.slice(CASE_ID_PREFIX.length)](text); + break; + case TRANSFORMATION_TYPE.CODE_CASING: + output = changeCodeCase[transformationId.slice(CODE_CASE_ID_PREFIX.length)](text); + break; + case TRANSFORMATION_TYPE.FONT: output = changeFont(text, transformationId); - } else { + break; + case TRANSFORMATION_TYPE.FORMAT: + output = changeFormat(text, transformationId); + break; + default: throw new Error(`Transformation with id=${transformationId} is unknown and could not be processed.`); } @@ -37,8 +46,12 @@ export function transformText(text, transformationId) { export function getTransformationType(transformationId) { if (transformationId.startsWith(CASE_ID_PREFIX)) { return TRANSFORMATION_TYPE.CASING; + } else if (transformationId.startsWith(CODE_CASE_ID_PREFIX)) { + return TRANSFORMATION_TYPE.CODE_CASING; } else if (transformationId.startsWith(FONT_ID_PREFIX)) { return TRANSFORMATION_TYPE.FONT; + } else if (transformationId.startsWith(FORMAT_ID_PREFIX)) { + return TRANSFORMATION_TYPE.FORMAT; } throw new Error(`Error while getting transformation type. Transformation with id=${transformationId} is unknown.`); @@ -55,7 +68,7 @@ function capitalizeEachWord(text) { // see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#bcd:javascript.builtins.RegExp // Intl.Segmenter is not yet supported by Firefox/Thunderbird: https://bugzilla.mozilla.org/show_bug.cgi?id=1423593 // \p{Alphabetic} - return text.replace(/(?<=^|\P{Alpha})\p{Alpha}\S*/gu, ([h, ...t]) => h.toLocaleUpperCase() + t.join("")); + return text.replaceAll(/(?<=^|\P{Alpha})\p{Alpha}\S*/gu, ([h, ...t]) => h.toLocaleUpperCase() + t.join("")); } /** @@ -69,7 +82,7 @@ function capitalizeEachWord(text) { * @throws {Error} */ function changeFont(text, chosenFont) { - const font = fontLetters[chosenFont]; + const font = fontLetters[chosenFont.slice(FONT_ID_PREFIX.length)]; if (!font) { throw new Error(`Font ${chosenFont} could not be processed.`); } @@ -102,6 +115,23 @@ function changeFont(text, chosenFont) { return output; } +/** + * Changes the Unicode format of the given text. + * + * @param {string} text + * @param {string} chosenFormat + * @returns {string} + * @throws {Error} + */ +function changeFormat(text, chosenFormat) { + const format = formats[chosenFormat.slice(FORMAT_ID_PREFIX.length)]; + if (!format) { + throw new Error(`Format ${chosenFormat} could not be processed.`); + } + + return Array.from(text, (letter) => letter + format).join(""); +} + /** * Toggle Case. * @@ -133,8 +163,103 @@ function toggleCase(atext) { * @type {Object.} */ const changeCase = Object.freeze({ - [`${CASE_ID_PREFIX}Lowercase`]: (str) => str.toLocaleLowerCase(), - [`${CASE_ID_PREFIX}Uppercase`]: (str) => str.toLocaleUpperCase(), - [`${CASE_ID_PREFIX}CapitalizeEachWord`]: (str) => capitalizeEachWord(str.toLocaleLowerCase()), - [`${CASE_ID_PREFIX}ToggleCase`]: (str) => toggleCase(str) + Lowercase: (str) => str.toLocaleLowerCase(), + Uppercase: (str) => str.toLocaleUpperCase(), + CapitalizeEachWord: (str) => capitalizeEachWord(str.toLocaleLowerCase()), + ToggleCase: (str) => toggleCase(str) +}); + +/** + * Split string to change coding case. + * + * @param {string} str + * @returns {string[]} + */ +function split(str) { + // \p{Alphabetic} \p{Mark} \p{Decimal_Number} \p{Join_Control} + const re = /[^\p{Alpha}\p{M}\p{digit}\p{Join_C}]+/gu; + let arr = str.split(/\s+/u).map((x) => x.replaceAll(re, "")).filter(Boolean); + if (!arr.length || arr.length > 1) { + return arr; + } + + arr = str.split(re).filter(Boolean); + // \p{Uppercase} + return !arr.length || arr.length > 1 ? arr : arr[0].match(/\p{Upper}*\P{Upper}+|\p{Upper}+/gu); +} + +/** + * Lower camel case. + * + * @param {string} atext + * @returns {string} + */ +function camelCase(atext) { + const [head, ...tail] = split(atext); + return head.toLowerCase() + tail.map(([h, ...t]) => h.toUpperCase() + t.join("").toLowerCase()).join(""); +} + +/** + * Upper camel case. + * + * @param {string} atext + * @returns {string} + */ +function upperCamelCase(atext) { + return split(atext).map(([h, ...t]) => h.toUpperCase() + t.join("").toLowerCase()).join(""); +} + +/** + * Snake case. + * + * @param {string} atext + * @returns {string} + */ +function snakeCase(atext) { + return split(atext).map((x) => x.toLowerCase()).join("_"); +} + +/** + * Constant case. + * + * @param {string} atext + * @returns {string} + */ +function constantCase(atext) { + return split(atext).map((x) => x.toUpperCase()).join("_"); +} + +/** + * Kebab case. + * + * @param {string} atext + * @returns {string} + */ +function kebabCase(atext) { + return split(atext).map((x) => x.toLowerCase()).join("-"); +} + +/** + * Train case. + * + * @param {string} atext + * @returns {string} + */ +function trainCase(atext) { + return split(atext).map((x) => x.toUpperCase()).join("-"); +} + +/** + * Change Coding Case + * + * @const + * @type {Object.} + */ +const changeCodeCase = Object.freeze({ + CamelCase: camelCase, + UpperCamelCase: upperCamelCase, + SnakeCase: snakeCase, + ConstantCase: constantCase, + KebabCase: kebabCase, + TrainCase: trainCase }); diff --git a/src/common/modules/data/DefaultSettings.js b/src/common/modules/data/DefaultSettings.js index 079c336..6032267 100644 --- a/src/common/modules/data/DefaultSettings.js +++ b/src/common/modules/data/DefaultSettings.js @@ -23,7 +23,9 @@ const defaultSettings = { }, unicodeFont: { changeFont: true, + changeFormat: false, changeCase: true, + changeCodeCase: true, showReadableText: true, livePreview: true, nested: true diff --git a/src/common/modules/data/Fonts.js b/src/common/modules/data/Fonts.js index ead0b5d..e59b864 100644 --- a/src/common/modules/data/Fonts.js +++ b/src/common/modules/data/Fonts.js @@ -13,7 +13,9 @@ const smallCaps = "ᴀʙᴄᴅᴇꜰɢʜɪᴊᴋʟᴍɴᴏᴘꞯʀꜱᴛᴜᴠ */ export const TRANSFORMATION_TYPE = Object.freeze({ CASING: Symbol("casing transformation"), - FONT: Symbol("font transformation") + CODE_CASING: Symbol("code casing transformation"), + FONT: Symbol("font transformation"), + FORMAT: Symbol("format transformation") }); /** @@ -34,6 +36,15 @@ export const SEPARATOR_ID_PREFIX = "separator"; */ export const CASE_ID_PREFIX = "menuCase"; +/** + * Unique prefix for all IDs related to code casing. + * + * @public + * @const + * @type {string} + */ +export const CODE_CASE_ID_PREFIX = "menuCodeCase"; + /** * Unique prefix for all IDs related to fonts. * @@ -43,6 +54,15 @@ export const CASE_ID_PREFIX = "menuCase"; */ export const FONT_ID_PREFIX = "menuFont"; +/** + * Unique prefix for all IDs related to fonts. + * + * @public + * @const + * @type {string} + */ +export const FORMAT_ID_PREFIX = "menuFormat"; + /** * The structure of the context menu. * @@ -94,12 +114,22 @@ export const menuStructure = Object.freeze({ `${FONT_ID_PREFIX}Circled`, `${FONT_ID_PREFIX}CircledBlack`, `${FONT_ID_PREFIX}Squared`, - `${FONT_ID_PREFIX}SquaredBlack` + `${FONT_ID_PREFIX}SquaredBlack`, + `${FONT_ID_PREFIX}Parenthesized` ], [`${FONT_ID_PREFIX}Fullwidth`]: [ `${FONT_ID_PREFIX}Fullwidth` ] }, + [TRANSFORMATION_TYPE.FORMAT]: { + [`${FORMAT_ID_PREFIX}Formatting`]: [ + `${FORMAT_ID_PREFIX}Overlined`, + `${FORMAT_ID_PREFIX}DoubleOverlined`, + `${FORMAT_ID_PREFIX}Strikethrough`, + `${FORMAT_ID_PREFIX}Underlined`, + `${FORMAT_ID_PREFIX}DoubleUnderlined` + ] + }, [TRANSFORMATION_TYPE.CASING]: { [`${CASE_ID_PREFIX}Casing`]: [ `${CASE_ID_PREFIX}Lowercase`, @@ -107,6 +137,16 @@ export const menuStructure = Object.freeze({ `${CASE_ID_PREFIX}CapitalizeEachWord`, `${CASE_ID_PREFIX}ToggleCase` ] + }, + [TRANSFORMATION_TYPE.CODE_CASING]: { + [`${CODE_CASE_ID_PREFIX}CodeCasing`]: [ + `${CODE_CASE_ID_PREFIX}CamelCase`, + `${CODE_CASE_ID_PREFIX}UpperCamelCase`, + `${CODE_CASE_ID_PREFIX}SnakeCase`, + `${CODE_CASE_ID_PREFIX}ConstantCase`, + `${CODE_CASE_ID_PREFIX}KebabCase`, + `${CODE_CASE_ID_PREFIX}TrainCase` + ] } }); @@ -122,32 +162,33 @@ export const menuStructure = Object.freeze({ * @type {Object.} */ const fonts = Object.freeze({ - [`${FONT_ID_PREFIX}SerifBold`]: "𝐀𝐁𝐂𝐃𝐄𝐅𝐆𝐇𝐈𝐉𝐊𝐋𝐌𝐍𝐎𝐏𝐐𝐑𝐒𝐓𝐔𝐕𝐖𝐗𝐘𝐙𝐚𝐛𝐜𝐝𝐞𝐟𝐠𝐡𝐢𝐣𝐤𝐥𝐦𝐧𝐨𝐩𝐪𝐫𝐬𝐭𝐮𝐯𝐰𝐱𝐲𝐳𝟎𝟏𝟐𝟑𝟒𝟓𝟔𝟕𝟖𝟗", - [`${FONT_ID_PREFIX}SerifItalic`]: "𝐴𝐵𝐶𝐷𝐸𝐹𝐺𝐻𝐼𝐽𝐾𝐿𝑀𝑁𝑂𝑃𝑄𝑅𝑆𝑇𝑈𝑉𝑊𝑋𝑌𝑍𝑎𝑏𝑐𝑑𝑒𝑓𝑔ℎ𝑖𝑗𝑘𝑙𝑚𝑛𝑜𝑝𝑞𝑟𝑠𝑡𝑢𝑣𝑤𝑥𝑦𝑧", - [`${FONT_ID_PREFIX}SerifBoldItalic`]: "𝑨𝑩𝑪𝑫𝑬𝑭𝑮𝑯𝑰𝑱𝑲𝑳𝑴𝑵𝑶𝑷𝑸𝑹𝑺𝑻𝑼𝑽𝑾𝑿𝒀𝒁𝒂𝒃𝒄𝒅𝒆𝒇𝒈𝒉𝒊𝒋𝒌𝒍𝒎𝒏𝒐𝒑𝒒𝒓𝒔𝒕𝒖𝒗𝒘𝒙𝒚𝒛", - [`${FONT_ID_PREFIX}SansSerif`]: "𝖠𝖡𝖢𝖣𝖤𝖥𝖦𝖧𝖨𝖩𝖪𝖫𝖬𝖭𝖮𝖯𝖰𝖱𝖲𝖳𝖴𝖵𝖶𝖷𝖸𝖹𝖺𝖻𝖼𝖽𝖾𝖿𝗀𝗁𝗂𝗃𝗄𝗅𝗆𝗇𝗈𝗉𝗊𝗋𝗌𝗍𝗎𝗏𝗐𝗑𝗒𝗓𝟢𝟣𝟤𝟥𝟦𝟧𝟨𝟩𝟪𝟫", - [`${FONT_ID_PREFIX}SansSerifBold`]: "𝗔𝗕𝗖𝗗𝗘𝗙𝗚𝗛𝗜𝗝𝗞𝗟𝗠𝗡𝗢𝗣𝗤𝗥𝗦𝗧𝗨𝗩𝗪𝗫𝗬𝗭𝗮𝗯𝗰𝗱𝗲𝗳𝗴𝗵𝗶𝗷𝗸𝗹𝗺𝗻𝗼𝗽𝗾𝗿𝘀𝘁𝘂𝘃𝘄𝘅𝘆𝘇𝟬𝟭𝟮𝟯𝟰𝟱𝟲𝟳𝟴𝟵", - [`${FONT_ID_PREFIX}SansSerifItalic`]: "𝘈𝘉𝘊𝘋𝘌𝘍𝘎𝘏𝘐𝘑𝘒𝘓𝘔𝘕𝘖𝘗𝘘𝘙𝘚𝘛𝘜𝘝𝘞𝘟𝘠𝘡𝘢𝘣𝘤𝘥𝘦𝘧𝘨𝘩𝘪𝘫𝘬𝘭𝘮𝘯𝘰𝘱𝘲𝘳𝘴𝘵𝘶𝘷𝘸𝘹𝘺𝘻", - [`${FONT_ID_PREFIX}SansSerifBoldItalic`]: "𝘼𝘽𝘾𝘿𝙀𝙁𝙂𝙃𝙄𝙅𝙆𝙇𝙈𝙉𝙊𝙋𝙌𝙍𝙎𝙏𝙐𝙑𝙒𝙓𝙔𝙕𝙖𝙗𝙘𝙙𝙚𝙛𝙜𝙝𝙞𝙟𝙠𝙡𝙢𝙣𝙤𝙥𝙦𝙧𝙨𝙩𝙪𝙫𝙬𝙭𝙮𝙯", - [`${FONT_ID_PREFIX}Script`]: "𝒜ℬ𝒞𝒟ℰℱ𝒢ℋℐ𝒥𝒦ℒℳ𝒩𝒪𝒫𝒬ℛ𝒮𝒯𝒰𝒱𝒲𝒳𝒴𝒵𝒶𝒷𝒸𝒹ℯ𝒻ℊ𝒽𝒾𝒿𝓀𝓁𝓂𝓃ℴ𝓅𝓆𝓇𝓈𝓉𝓊𝓋𝓌𝓍𝓎𝓏", - [`${FONT_ID_PREFIX}ScriptBold`]: "𝓐𝓑𝓒𝓓𝓔𝓕𝓖𝓗𝓘𝓙𝓚𝓛𝓜𝓝𝓞𝓟𝓠𝓡𝓢𝓣𝓤𝓥𝓦𝓧𝓨𝓩𝓪𝓫𝓬𝓭𝓮𝓯𝓰𝓱𝓲𝓳𝓴𝓵𝓶𝓷𝓸𝓹𝓺𝓻𝓼𝓽𝓾𝓿𝔀𝔁𝔂𝔃", - [`${FONT_ID_PREFIX}Fraktur`]: "𝔄𝔅ℭ𝔇𝔈𝔉𝔊ℌℑ𝔍𝔎𝔏𝔐𝔑𝔒𝔓𝔔ℜ𝔖𝔗𝔘𝔙𝔚𝔛𝔜ℨ𝔞𝔟𝔠𝔡𝔢𝔣𝔤𝔥𝔦𝔧𝔨𝔩𝔪𝔫𝔬𝔭𝔮𝔯𝔰𝔱𝔲𝔳𝔴𝔵𝔶𝔷", - [`${FONT_ID_PREFIX}FrakturBold`]: "𝕬𝕭𝕮𝕯𝕰𝕱𝕲𝕳𝕴𝕵𝕶𝕷𝕸𝕹𝕺𝕻𝕼𝕽𝕾𝕿𝖀𝖁𝖂𝖃𝖄𝖅𝖆𝖇𝖈𝖉𝖊𝖋𝖌𝖍𝖎𝖏𝖐𝖑𝖒𝖓𝖔𝖕𝖖𝖗𝖘𝖙𝖚𝖛𝖜𝖝𝖞𝖟", - [`${FONT_ID_PREFIX}Monospace`]: "𝙰𝙱𝙲𝙳𝙴𝙵𝙶𝙷𝙸𝙹𝙺𝙻𝙼𝙽𝙾𝙿𝚀𝚁𝚂𝚃𝚄𝚅𝚆𝚇𝚈𝚉𝚊𝚋𝚌𝚍𝚎𝚏𝚐𝚑𝚒𝚓𝚔𝚕𝚖𝚗𝚘𝚙𝚚𝚛𝚜𝚝𝚞𝚟𝚠𝚡𝚢𝚣𝟶𝟷𝟸𝟹𝟺𝟻𝟼𝟽𝟾𝟿", - [`${FONT_ID_PREFIX}DoubleStruck`]: "𝔸𝔹ℂ𝔻𝔼𝔽𝔾ℍ𝕀𝕁𝕂𝕃𝕄ℕ𝕆ℙℚℝ𝕊𝕋𝕌𝕍𝕎𝕏𝕐ℤ𝕒𝕓𝕔𝕕𝕖𝕗𝕘𝕙𝕚𝕛𝕜𝕝𝕞𝕟𝕠𝕡𝕢𝕣𝕤𝕥𝕦𝕧𝕨𝕩𝕪𝕫𝟘𝟙𝟚𝟛𝟜𝟝𝟞𝟟𝟠𝟡", - [`${FONT_ID_PREFIX}Circled`]: " !\"#$%&'()⊛⊕,⊖⊙⊘⓪①②③④⑤⑥⑦⑧⑨:;⧀⊜⧁?@ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏ[⦸]^_`ⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ{⦶}~", - [`${FONT_ID_PREFIX}CircledBlack`]: "🅐🅑🅒🅓🅔🅕🅖🅗🅘🅙🅚🅛🅜🅝🅞🅟🅠🅡🅢🅣🅤🅥🅦🅧🅨🅩⓿❶❷❸❹❺❻❼❽❾", - [`${FONT_ID_PREFIX}Squared`]: " !\"#$%&'()⧆⊞,⊟⊡⧄0123456789:;<=>?@🄰🄱🄲🄳🄴🄵🄶🄷🄸🄹🄺🄻🄼🄽🄾🄿🅀🅁🅂🅃🅄🅅🅆🅇🅈🅉[⧅]^_`🄰🄱🄲🄳🄴🄵🄶🄷🄸🄹🄺🄻🄼🄽🄾🄿🅀🅁🅂🅃🅄🅅🅆🅇🅈🅉{|}~", - [`${FONT_ID_PREFIX}SquaredBlack`]: "🅰🅱🅲🅳🅴🅵🅶🅷🅸🅹🅺🅻🅼🅽🅾🅿🆀🆁🆂🆃🆄🆅🆆🆇🆈🆉", + SerifBold: "𝐀𝐁𝐂𝐃𝐄𝐅𝐆𝐇𝐈𝐉𝐊𝐋𝐌𝐍𝐎𝐏𝐐𝐑𝐒𝐓𝐔𝐕𝐖𝐗𝐘𝐙𝐚𝐛𝐜𝐝𝐞𝐟𝐠𝐡𝐢𝐣𝐤𝐥𝐦𝐧𝐨𝐩𝐪𝐫𝐬𝐭𝐮𝐯𝐰𝐱𝐲𝐳𝟎𝟏𝟐𝟑𝟒𝟓𝟔𝟕𝟖𝟗", + SerifItalic: "𝐴𝐵𝐶𝐷𝐸𝐹𝐺𝐻𝐼𝐽𝐾𝐿𝑀𝑁𝑂𝑃𝑄𝑅𝑆𝑇𝑈𝑉𝑊𝑋𝑌𝑍𝑎𝑏𝑐𝑑𝑒𝑓𝑔ℎ𝑖𝑗𝑘𝑙𝑚𝑛𝑜𝑝𝑞𝑟𝑠𝑡𝑢𝑣𝑤𝑥𝑦𝑧", + SerifBoldItalic: "𝑨𝑩𝑪𝑫𝑬𝑭𝑮𝑯𝑰𝑱𝑲𝑳𝑴𝑵𝑶𝑷𝑸𝑹𝑺𝑻𝑼𝑽𝑾𝑿𝒀𝒁𝒂𝒃𝒄𝒅𝒆𝒇𝒈𝒉𝒊𝒋𝒌𝒍𝒎𝒏𝒐𝒑𝒒𝒓𝒔𝒕𝒖𝒗𝒘𝒙𝒚𝒛", + SansSerif: "𝖠𝖡𝖢𝖣𝖤𝖥𝖦𝖧𝖨𝖩𝖪𝖫𝖬𝖭𝖮𝖯𝖰𝖱𝖲𝖳𝖴𝖵𝖶𝖷𝖸𝖹𝖺𝖻𝖼𝖽𝖾𝖿𝗀𝗁𝗂𝗃𝗄𝗅𝗆𝗇𝗈𝗉𝗊𝗋𝗌𝗍𝗎𝗏𝗐𝗑𝗒𝗓𝟢𝟣𝟤𝟥𝟦𝟧𝟨𝟩𝟪𝟫", + SansSerifBold: "𝗔𝗕𝗖𝗗𝗘𝗙𝗚𝗛𝗜𝗝𝗞𝗟𝗠𝗡𝗢𝗣𝗤𝗥𝗦𝗧𝗨𝗩𝗪𝗫𝗬𝗭𝗮𝗯𝗰𝗱𝗲𝗳𝗴𝗵𝗶𝗷𝗸𝗹𝗺𝗻𝗼𝗽𝗾𝗿𝘀𝘁𝘂𝘃𝘄𝘅𝘆𝘇𝟬𝟭𝟮𝟯𝟰𝟱𝟲𝟳𝟴𝟵", + SansSerifItalic: "𝘈𝘉𝘊𝘋𝘌𝘍𝘎𝘏𝘐𝘑𝘒𝘓𝘔𝘕𝘖𝘗𝘘𝘙𝘚𝘛𝘜𝘝𝘞𝘟𝘠𝘡𝘢𝘣𝘤𝘥𝘦𝘧𝘨𝘩𝘪𝘫𝘬𝘭𝘮𝘯𝘰𝘱𝘲𝘳𝘴𝘵𝘶𝘷𝘸𝘹𝘺𝘻", + SansSerifBoldItalic: "𝘼𝘽𝘾𝘿𝙀𝙁𝙂𝙃𝙄𝙅𝙆𝙇𝙈𝙉𝙊𝙋𝙌𝙍𝙎𝙏𝙐𝙑𝙒𝙓𝙔𝙕𝙖𝙗𝙘𝙙𝙚𝙛𝙜𝙝𝙞𝙟𝙠𝙡𝙢𝙣𝙤𝙥𝙦𝙧𝙨𝙩𝙪𝙫𝙬𝙭𝙮𝙯", + Script: "𝒜ℬ𝒞𝒟ℰℱ𝒢ℋℐ𝒥𝒦ℒℳ𝒩𝒪𝒫𝒬ℛ𝒮𝒯𝒰𝒱𝒲𝒳𝒴𝒵𝒶𝒷𝒸𝒹ℯ𝒻ℊ𝒽𝒾𝒿𝓀𝓁𝓂𝓃ℴ𝓅𝓆𝓇𝓈𝓉𝓊𝓋𝓌𝓍𝓎𝓏", + ScriptBold: "𝓐𝓑𝓒𝓓𝓔𝓕𝓖𝓗𝓘𝓙𝓚𝓛𝓜𝓝𝓞𝓟𝓠𝓡𝓢𝓣𝓤𝓥𝓦𝓧𝓨𝓩𝓪𝓫𝓬𝓭𝓮𝓯𝓰𝓱𝓲𝓳𝓴𝓵𝓶𝓷𝓸𝓹𝓺𝓻𝓼𝓽𝓾𝓿𝔀𝔁𝔂𝔃", + Fraktur: "𝔄𝔅ℭ𝔇𝔈𝔉𝔊ℌℑ𝔍𝔎𝔏𝔐𝔑𝔒𝔓𝔔ℜ𝔖𝔗𝔘𝔙𝔚𝔛𝔜ℨ𝔞𝔟𝔠𝔡𝔢𝔣𝔤𝔥𝔦𝔧𝔨𝔩𝔪𝔫𝔬𝔭𝔮𝔯𝔰𝔱𝔲𝔳𝔴𝔵𝔶𝔷", + FrakturBold: "𝕬𝕭𝕮𝕯𝕰𝕱𝕲𝕳𝕴𝕵𝕶𝕷𝕸𝕹𝕺𝕻𝕼𝕽𝕾𝕿𝖀𝖁𝖂𝖃𝖄𝖅𝖆𝖇𝖈𝖉𝖊𝖋𝖌𝖍𝖎𝖏𝖐𝖑𝖒𝖓𝖔𝖕𝖖𝖗𝖘𝖙𝖚𝖛𝖜𝖝𝖞𝖟", + Monospace: "𝙰𝙱𝙲𝙳𝙴𝙵𝙶𝙷𝙸𝙹𝙺𝙻𝙼𝙽𝙾𝙿𝚀𝚁𝚂𝚃𝚄𝚅𝚆𝚇𝚈𝚉𝚊𝚋𝚌𝚍𝚎𝚏𝚐𝚑𝚒𝚓𝚔𝚕𝚖𝚗𝚘𝚙𝚚𝚛𝚜𝚝𝚞𝚟𝚠𝚡𝚢𝚣𝟶𝟷𝟸𝟹𝟺𝟻𝟼𝟽𝟾𝟿", + DoubleStruck: "𝔸𝔹ℂ𝔻𝔼𝔽𝔾ℍ𝕀𝕁𝕂𝕃𝕄ℕ𝕆ℙℚℝ𝕊𝕋𝕌𝕍𝕎𝕏𝕐ℤ𝕒𝕓𝕔𝕕𝕖𝕗𝕘𝕙𝕚𝕛𝕜𝕝𝕞𝕟𝕠𝕡𝕢𝕣𝕤𝕥𝕦𝕧𝕨𝕩𝕪𝕫𝟘𝟙𝟚𝟛𝟜𝟝𝟞𝟟𝟠𝟡", + Circled: " !\"#$%&'()⊛⊕,⊖⊙⊘⓪①②③④⑤⑥⑦⑧⑨:;⧀⊜⧁?@ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏ[⦸]^_`ⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ{⦶}~", + CircledBlack: "🅐🅑🅒🅓🅔🅕🅖🅗🅘🅙🅚🅛🅜🅝🅞🅟🅠🅡🅢🅣🅤🅥🅦🅧🅨🅩⓿❶❷❸❹❺❻❼❽❾", + Squared: " !\"#$%&'()⧆⊞,⊟⊡⧄0123456789:;<=>?@🄰🄱🄲🄳🄴🄵🄶🄷🄸🄹🄺🄻🄼🄽🄾🄿🅀🅁🅂🅃🅄🅅🅆🅇🅈🅉[⧅]^_`🄰🄱🄲🄳🄴🄵🄶🄷🄸🄹🄺🄻🄼🄽🄾🄿🅀🅁🅂🅃🅄🅅🅆🅇🅈🅉{|}~", + SquaredBlack: "🅰🅱🅲🅳🅴🅵🅶🅷🅸🅹🅺🅻🅼🅽🅾🅿🆀🆁🆂🆃🆄🆅🆆🆇🆈🆉", + Parenthesized: "🄐🄑🄒🄓🄔🄕🄖🄗🄘🄙🄚🄛🄜🄝🄞🄟🄠🄡🄢🄣🄤🄥🄦🄧🄨🄩⒜⒝⒞⒟⒠⒡⒢⒣⒤⒥⒦⒧⒨⒩⒪⒫⒬⒭⒮⒯⒰⒱⒲⒳⒴⒵0⑴⑵⑶⑷⑸⑹⑺⑻⑼", // https://en.wikipedia.org/wiki/Halfwidth_and_Fullwidth_Forms_(Unicode_block) - [`${FONT_ID_PREFIX}Fullwidth`]: " !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~", + Fullwidth: " !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~", // Adapted from: https://rupertshepherd.info/resource_pages/superscript-letters-in-unicode // https://en.wikipedia.org/wiki/Unicode_subscripts_and_superscripts - [`${FONT_ID_PREFIX}Superscript`]: " !\"#$%&'⁽⁾*⁺,⁻./⁰¹²³⁴⁵⁶⁷⁸⁹:;<⁼>?@ᴬᴮꟲᴰᴱꟳᴳᴴᴵᴶᴷᴸᴹᴺᴼᴾꟴᴿˢᵀᵁⱽᵂˣʸᶻ[\\]^_`ᵃᵇᶜᵈᵉᶠᵍʰⁱʲᵏˡᵐⁿᵒᵖ𐞥ʳˢᵗᵘᵛʷˣʸᶻ{|}~", - [`${FONT_ID_PREFIX}Subscript`]: " !\"#$%&'₍₎*₊,₋./₀₁₂₃₄₅₆₇₈₉:;<₌>?@ₐBCDₑFGₕᵢⱼₖₗₘₙₒₚQᵣₛₜᵤᵥWₓYZ[\\]^_`ₐbcdₑfgₕᵢⱼₖₗₘₙₒₚqᵣₛₜᵤᵥwₓyz{|}~", - [`${FONT_ID_PREFIX}SmallCaps`]: `ABCDEFGHIJKLMNOPQRSTUVWXYZ${smallCaps}`, - [`${FONT_ID_PREFIX}AllSmallCaps`]: smallCaps, - [`${FONT_ID_PREFIX}Unicase`]: `${smallCaps}abcdefghijklmnopqrstuvwxyz` + Superscript: " !\"#$%&'⁽⁾*⁺,⁻./⁰¹²³⁴⁵⁶⁷⁸⁹:;<⁼>?@ᴬᴮꟲᴰᴱꟳᴳᴴᴵᴶᴷᴸᴹᴺᴼᴾꟴᴿˢᵀᵁⱽᵂˣʸᶻ[\\]^_`ᵃᵇᶜᵈᵉᶠᵍʰⁱʲᵏˡᵐⁿᵒᵖ𐞥ʳˢᵗᵘᵛʷˣʸᶻ{|}~", + Subscript: " !\"#$%&'₍₎*₊,₋./₀₁₂₃₄₅₆₇₈₉:;<₌>?@ₐBCDₑFGₕᵢⱼₖₗₘₙₒₚQᵣₛₜᵤᵥWₓYZ[\\]^_`ₐbcdₑfgₕᵢⱼₖₗₘₙₒₚqᵣₛₜᵤᵥwₓyz{|}~", + SmallCaps: `ABCDEFGHIJKLMNOPQRSTUVWXYZ${smallCaps}`, + AllSmallCaps: smallCaps, + Unicase: `${smallCaps}abcdefghijklmnopqrstuvwxyz` }); /** @@ -163,6 +204,24 @@ const fonts = Object.freeze({ export const fontLetters = Object.freeze( Object.fromEntries(Object.entries(fonts).map(([font, charString]) => { // split-up the letter string an array with each character - return [font, Array.from(charString)]; + const letters = Array.from(charString); + console.assert([26, 26 + 10, 26 + 26, 26 + 26 + 10, 95].includes(letters.length), "Error:", font, charString, letters); + return [font, letters]; })) ); + +/** + * Unicode formats + * https://en.wikipedia.org/wiki/Combining_Diacritical_Marks + * + * @public + * @const + * @type {Object.} + */ +export const formats = Object.freeze({ + Overlined: "\u0305", + DoubleOverlined: "\u033F", + Strikethrough: "\u0336", + Underlined: "\u0332", + DoubleUnderlined: "\u0333" +}); diff --git a/src/content_scripts/autocorrect.js b/src/content_scripts/autocorrect.js index d1ffa1b..7577ef5 100644 --- a/src/content_scripts/autocorrect.js +++ b/src/content_scripts/autocorrect.js @@ -142,7 +142,7 @@ function insertIntoPage(atext) { */ function countChars(str) { // removing the joiners - const split = str.split("\u{200D}"); + const split = str.split("\u200D"); let count = 0; for (const s of split) { diff --git a/src/options/options.html b/src/options/options.html index c643584..e8379ad 100644 --- a/src/options/options.html +++ b/src/options/options.html @@ -127,6 +127,14 @@

Context menu

For example, ˢᵘᵖᵉʳˢᶜʳⁱᵖᵗ, ꜱᴍᴀʟʟ ᴄᴀᴘꜱ, 𝒮𝒸𝓇𝒾𝓅𝓉, 𝔉𝔯𝔞𝔨𝔱𝔲𝔯, 🅒🅘🅡🅒🅛🅔🅓 and 🆂🆀🆄🅰🆁🅴🅳. +
  • +
    + + +
    + For example, O̅v̅e̅r̅l̅i̅n̅e̅d̅, S̶t̶r̶i̶k̶e̶t̶h̶r̶o̶u̶g̶h̶ and U̲n̲d̲e̲r̲l̲i̲n̲e̲d̲. +
  • +
  • @@ -135,6 +143,14 @@

    Context menu

    For example, “UPPER CASE”, “lower case”, “Capitalize Each Word” or “tOGGLE cASE”.
  • +
  • +
    + + +
    + For example, “camelCase”, “UpperCamelCase”, “snake_case” or “kebab-case”. +
  • +

    Entry design