From 8745504d2cbbeed31dcd0f50daf6e29dc96b8be5 Mon Sep 17 00:00:00 2001 From: xdan Date: Sun, 25 Feb 2024 17:11:54 +0300 Subject: [PATCH] New version 4.0.7 Read more https://github.com/xdan/jodit/blob/main/CHANGELOG.md --- .stylelintrc | 12 +- CHANGELOG.md | 5 + package-lock.json | 184 +++++++++++++----- package.json | 4 +- src/langs/fi.js | 10 +- src/plugins/search/config.ts | 9 +- ...n-tmp-span.ts => highlight-text-ranges.ts} | 31 ++- src/plugins/search/helpers/index.ts | 2 +- src/plugins/search/search.test.js | 6 + src/plugins/search/search.ts | 8 +- src/plugins/search/ui/search.less | 5 +- src/styles/variables.less | 1 + tsconfig.json | 2 +- 13 files changed, 216 insertions(+), 63 deletions(-) rename src/plugins/search/helpers/{wrap-ranges-texts-in-tmp-span.ts => highlight-text-ranges.ts} (81%) diff --git a/.stylelintrc b/.stylelintrc index af8cb4226..cb35dbee2 100644 --- a/.stylelintrc +++ b/.stylelintrc @@ -1,5 +1,9 @@ { - "extends": ["stylelint-config-standard","stylelint-config-idiomatic-order", "stylelint-prettier/recommended"], + "extends": [ + "stylelint-config-standard", + "stylelint-config-idiomatic-order", + "stylelint-prettier/recommended" + ], "customSyntax": "postcss-less", "rules": { "prettier/prettier": true, @@ -8,6 +12,12 @@ "selector-not-notation": null, "selector-class-pattern": null, "no-descending-specificity": null, + "selector-pseudo-element-no-unknown": [ + true, + { + "ignorePseudoElements": ["highlight"] + } + ], "property-no-unknown": [ true, { diff --git a/CHANGELOG.md b/CHANGELOG.md index a21d83aa9..abb030b3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,11 @@ > - :house: [Internal] > - :nail_care: [Polish] +## 4.0.7 + +- Added `search.useCustomHighlightAPI` option to the "Search" plugin to use the built-in text highlighting API https://developer.mozilla.org/en-US/docs/Web/API/CSS_Custom_Highlight_API + If the browser does not support this API, then standard text highlighting will be used by wrapping it in the `` tag. + ## 4.0.2 - [BUG: FileBrowser Context Menu Grows Infinitely](https://github.com/xdan/jodit/issues/1059) diff --git a/package-lock.json b/package-lock.json index 5e60fd0ee..0a2a91347 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "jodit", - "version": "4.0.6", + "version": "4.0.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "jodit", - "version": "4.0.6", + "version": "4.0.7", "license": "MIT", "dependencies": { "autobind-decorator": "^2.4.0" @@ -70,7 +70,7 @@ "ts-loader": "^9.5.1", "ts-node": "^10.9.2", "tslib": "^2.6.2", - "typescript": "^5.3.3", + "typescript": "^5.4.1-rc", "webpack": "5.89.0", "webpack-cli": "^5.1.4", "webpack-dev-middleware": "^7.0.0", @@ -1181,6 +1181,32 @@ } } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ts-api-utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz", + "integrity": "sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/@typescript-eslint/parser": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.18.0.tgz", @@ -1253,6 +1279,32 @@ } } }, + "node_modules/@typescript-eslint/type-utils/node_modules/ts-api-utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz", + "integrity": "sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/@typescript-eslint/types": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.18.0.tgz", @@ -1294,6 +1346,32 @@ } } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/ts-api-utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz", + "integrity": "sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/@typescript-eslint/utils": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.18.0.tgz", @@ -2781,32 +2859,6 @@ "node": ">= 0.10" } }, - "node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dev": true, - "dependencies": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -8277,6 +8329,47 @@ "webpack": "^5.0.0" } }, + "node_modules/postcss-loader/node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/postcss-loader/node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "optional": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/postcss-merge-idents": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-6.0.1.tgz", @@ -10742,6 +10835,21 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, + "node_modules/stylelint/node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "optional": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -11146,18 +11254,6 @@ "node": ">=0.8.0" } }, - "node_modules/ts-api-utils": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", - "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", - "dev": true, - "engines": { - "node": ">=16.13.0" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, "node_modules/ts-loader": { "version": "9.5.1", "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", @@ -11393,9 +11489,9 @@ } }, "node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.4.1-rc", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.1-rc.tgz", + "integrity": "sha512-gInURzaO0bbfzfQAc3mfcHxh8qev+No4QOFUZHajo9vBgOLaljELJ3wuzyoGo/zHIzMSezdhtrsRdqL6E9SvNA==", "dev": true, "bin": { "tsc": "bin/tsc", diff --git a/package.json b/package.json index 502dbd77b..5315a6eef 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jodit", - "version": "4.0.6", + "version": "4.0.7", "description": "Jodit is awesome and usefully wysiwyg editor with filebrowser", "main": "build/jodit.min.js", "types": "./types/index.d.ts", @@ -108,7 +108,7 @@ "ts-loader": "^9.5.1", "ts-node": "^10.9.2", "tslib": "^2.6.2", - "typescript": "^5.3.3", + "typescript": "^5.4.1-rc", "webpack": "5.89.0", "webpack-cli": "^5.1.4", "webpack-dev-middleware": "^7.0.0", diff --git a/src/langs/fi.js b/src/langs/fi.js index 06b4bdf91..cd63e1710 100644 --- a/src/langs/fi.js +++ b/src/langs/fi.js @@ -10,7 +10,8 @@ module.exports = { 'About Jodit': 'Tietoja Jodit:ista', 'Jodit Editor': 'Jodit Editor', "Jodit User's Guide": 'Jodit käyttäjän ohje', - 'contains detailed help for using': 'sisältää tarkempaa tietoa käyttämiseen', + 'contains detailed help for using': + 'sisältää tarkempaa tietoa käyttämiseen', 'For information about the license, please go to our website:': 'Tietoa lisensoinnista, vieraile verkkosivuillamme:', 'Buy full version': 'Osta täysi versio', @@ -81,7 +82,7 @@ module.exports = { 'Koodi on HTML:n tapaista. Säilytetäänkö HTML?', 'Paste as HTML': 'Liitä HTML:nä?', Keep: 'Säilytä', - Clean: 'Tyhjennä', + Clean: 'Tyhjennä', 'Insert as Text': 'Lisää tekstinä', 'Word Paste Detected': 'Word liittäminen havaittu', 'The pasted content is coming from a Microsoft Word/Excel document. Do you want to keep the format or clean it up?': @@ -225,7 +226,6 @@ module.exports = { 'Find Previous': 'Hae edellinen', 'Find Next': 'Hae seuraava', 'Insert className': 'Lisää luokkanimi', - 'Press Alt for custom resizing': - 'Paina Alt muokattuun koon muuttamiseen', - 'Class name': 'Luokan nimi', + 'Press Alt for custom resizing': 'Paina Alt muokattuun koon muuttamiseen', + 'Class name': 'Luokan nimi' }; diff --git a/src/plugins/search/config.ts b/src/plugins/search/config.ts index 0115fa597..818457873 100644 --- a/src/plugins/search/config.ts +++ b/src/plugins/search/config.ts @@ -27,6 +27,12 @@ declare module 'jodit/config' { search: { lazyIdleTimeout: number; + /** + * Use custom highlight API https://developer.mozilla.org/en-US/docs/Web/API/CSS_Custom_Highlight_API + * or use default implementation (wrap text in span and attribute jd-tmp-selection) + */ + useCustomHighlightAPI: boolean; + /** * Function to search for a string within a substring. The default implementation is [[fuzzySearchIndex]] * But you can write your own. It must implement the [[FuzzySearch]] interface. @@ -48,7 +54,8 @@ declare module 'jodit/config' { Config.prototype.useSearch = true; Config.prototype.search = { - lazyIdleTimeout: 0 + lazyIdleTimeout: 0, + useCustomHighlightAPI: typeof Highlight !== 'undefined' }; Icon.set('search', searchIcon); diff --git a/src/plugins/search/helpers/wrap-ranges-texts-in-tmp-span.ts b/src/plugins/search/helpers/highlight-text-ranges.ts similarity index 81% rename from src/plugins/search/helpers/wrap-ranges-texts-in-tmp-span.ts rename to src/plugins/search/helpers/highlight-text-ranges.ts index c2740e71c..2860df36e 100644 --- a/src/plugins/search/helpers/wrap-ranges-texts-in-tmp-span.ts +++ b/src/plugins/search/helpers/highlight-text-ranges.ts @@ -8,7 +8,13 @@ * @module plugins/search */ -import type { CanUndef, ICreate, ISelectionRange, Nullable } from 'jodit/types'; +import type { + CanUndef, + ICreate, + IJodit, + ISelectionRange, + Nullable +} from 'jodit/types'; import { Dom } from 'jodit/core/dom/dom'; import { $$ } from 'jodit/core/helpers/utils/selector'; @@ -20,7 +26,8 @@ const TMP_ATTR = 'jd-tmp-selection'; /** * @private */ -export function wrapRangesTextsInTmpSpan( +export function highlightTextRanges( + jodit: IJodit, rng: ISelectionRange, restRanges: ISelectionRange[], ci: ICreate, @@ -33,6 +40,26 @@ export function wrapRangesTextsInTmpSpan( return; } + if ( + jodit.o.search.useCustomHighlightAPI && + typeof Highlight !== 'undefined' + ) { + const ranges = [rng, ...restRanges].map(rng => { + const range = jodit.selection.createRange(); + range.setStart(rng.startContainer, rng.startOffset); + range.setEnd(rng.endContainer, rng.endOffset); + return range; + }); + + const searchHighlight = new Highlight(...ranges); + // @ts-ignore + CSS.highlights.clear(); + // @ts-ignore + CSS.highlights.set('jodit-search-result', searchHighlight); + restRanges.length = 0; + return; + } + const span = ci.element('span', { [TMP_ATTR]: true }); diff --git a/src/plugins/search/helpers/index.ts b/src/plugins/search/helpers/index.ts index 4a7b6814c..0415499bf 100644 --- a/src/plugins/search/helpers/index.ts +++ b/src/plugins/search/helpers/index.ts @@ -9,4 +9,4 @@ */ export * from './sentence-finder'; -export * from './wrap-ranges-texts-in-tmp-span'; +export * from './highlight-text-ranges'; diff --git a/src/plugins/search/search.test.js b/src/plugins/search/search.test.js index 3b64c6c1d..e3051754c 100644 --- a/src/plugins/search/search.test.js +++ b/src/plugins/search/search.test.js @@ -9,6 +9,12 @@ describe('Search plugin', function () { beforeEach(() => { unmockPromise(); + Jodit.defaultOptions.search.useCustomHighlightAPI = false; + }); + + afterEach(() => { + Jodit.defaultOptions.search.useCustomHighlightAPI = + typeof Highlight !== 'undefined'; }); function getSearchInputs(editor) { diff --git a/src/plugins/search/search.ts b/src/plugins/search/search.ts index 8412c434d..c72248d92 100644 --- a/src/plugins/search/search.ts +++ b/src/plugins/search/search.ts @@ -31,7 +31,7 @@ import { clearSelectionWrappersFromHTML, getSelectionWrappers, SentenceFinder, - wrapRangesTextsInTmpSpan + highlightTextRanges } from './helpers'; import './config'; @@ -197,7 +197,7 @@ export class search extends Plugin { this.drawPromise?.rejectCallback(); this.j.async.cancelAnimationFrame(this.wrapFrameRequest); clearSelectionWrappers(this.j.editor); - this.drawPromise = this.drawSelectionRanges(bounds); + this.drawPromise = this.__drawSelectionRanges(bounds); } this.previousQuery = query; @@ -311,7 +311,7 @@ export class search extends Plugin { private wrapFrameRequest: number = 0; - private drawSelectionRanges( + private __drawSelectionRanges( ranges: ISelectionRange[] ): RejectablePromise { const { async, createInside: ci, editor } = this.j; @@ -329,7 +329,7 @@ export class search extends Plugin { sRange = parts.shift(); if (sRange) { - wrapRangesTextsInTmpSpan(sRange, parts, ci, editor); + highlightTextRanges(this.j, sRange, parts, ci, editor); } total += 1; diff --git a/src/plugins/search/ui/search.less b/src/plugins/search/ui/search.less index 4808caf7f..368d9c76a 100644 --- a/src/plugins/search/ui/search.less +++ b/src/plugins/search/ui/search.less @@ -151,6 +151,7 @@ } } -[jd-tmp-selection] { - background-color: aquamarine; + ::highlight(jodit-search-result), [jd-tmp-selection] { + background-color: var(--color-background-selection); + color: var(--color-text-selection); } diff --git a/src/styles/variables.less b/src/styles/variables.less index 8f9fe0f31..d405244f5 100644 --- a/src/styles/variables.less +++ b/src/styles/variables.less @@ -56,6 +56,7 @@ --color-background-progress: #b91f1f; --color-background-active: #2196f3; --color-background-selection: @color-blue; + --color-text-selection: var(--color-white); // stylelint-disable-next-line function-no-unknown --color-background-selection-opacity50: fadeout(@color-blue, 0.5); --color-source-area: #323232; diff --git a/tsconfig.json b/tsconfig.json index f88fccf3a..fce6efc84 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -35,7 +35,7 @@ "importHelpers": true, - "lib": ["es5", "esnext", "dom", "scripthost", "es2015.iterable"], + "lib": ["es5", "esnext", "DOM", "scripthost", "es2015.iterable"], "baseUrl": ".", "paths": {