inital commit

This commit is contained in:
2026-01-01 15:25:19 +05:30
commit f0ae49465a
36361 changed files with 4894111 additions and 0 deletions

42
node_modules/jodit/esm/plugins/search/config.d.ts generated vendored Normal file
View File

@@ -0,0 +1,42 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
/**
* @module plugins/search
*/
import type { FuzzySearch } from "../../types/index";
import "./interface";
declare module 'jodit/config' {
interface Config {
/**
* Enable custom search plugin
* ![search](https://user-images.githubusercontent.com/794318/34545433-cd0a9220-f10e-11e7-8d26-7e22f66e266d.gif)
*/
useSearch: boolean;
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.
*
* ```ts
* Jodit.make('#editor', {
* search: {
* fuzzySearch: (needle, haystack, offset) => {
* return [haystack.toLowerCase().indexOf(needle.toLowerCase(), offset), needle.length];
* }
* }
* })
* ```
*/
fuzzySearch?: FuzzySearch;
};
}
}

43
node_modules/jodit/esm/plugins/search/config.js generated vendored Normal file
View File

@@ -0,0 +1,43 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
import { globalWindow } from "../../core/constants.js";
import { Icon } from "../../core/ui/icon.js";
import { Config } from "../../config.js";
import "./interface.js";
import searchIcon from "./search.svg.js";
Config.prototype.useSearch = true;
Config.prototype.search = {
lazyIdleTimeout: 0,
useCustomHighlightAPI: globalWindow && typeof globalWindow.Highlight !== 'undefined'
};
Icon.set('search', searchIcon);
Config.prototype.controls.find = {
tooltip: 'Find',
icon: 'search',
exec(jodit, _, { control }) {
const value = control.args && control.args[0];
switch (value) {
case 'findPrevious':
jodit.e.fire('searchPrevious');
break;
case 'findNext':
jodit.e.fire('searchNext');
break;
case 'replace':
jodit.execCommand('openReplaceDialog');
break;
default:
jodit.execCommand('openSearchDialog');
}
},
list: {
search: 'Find',
findNext: 'Find Next',
findPrevious: 'Find Previous',
replace: 'Replace'
},
childTemplate: (_, k, v) => v
};

View File

@@ -0,0 +1,26 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
/**
* @module plugins/search
*/
import type { ICreate, IJodit, ISelectionRange } from "../../../types/index";
/**
* @private
*/
export declare function highlightTextRanges(jodit: IJodit, rng: ISelectionRange, restRanges: ISelectionRange[], ci: ICreate, root: HTMLElement): void;
/**
* @private
*/
export declare function getSelectionWrappers(root: HTMLElement): HTMLElement[];
/**
* @private
*/
export declare function clearSelectionWrappers(jodit: IJodit): void;
/**
* @private
*/
export declare function clearSelectionWrappersFromHTML(root: string): string;
export declare function clearNativeSelection(jodit: IJodit): void;

View File

@@ -0,0 +1,138 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
import { globalWindow } from "../../../core/constants.js";
import { Dom } from "../../../core/dom/dom.js";
import { $$ } from "../../../core/helpers/utils/selector.js";
/**
* @private
*/
const TMP_ATTR = 'jd-tmp-selection';
/**
* @private
*/
export function highlightTextRanges(jodit, rng, restRanges, ci, root) {
if (rng.startContainer.nodeValue == null ||
rng.endContainer.nodeValue == null) {
return;
}
if (checkNativeSelectionMethod(jodit, rng, restRanges)) {
return;
}
const span = ci.element('span', {
[TMP_ATTR]: true
});
Dom.markTemporary(span);
normalizeRanges(rng, restRanges, ci);
let next = rng.startContainer;
do {
if (!next) {
break;
}
if (Dom.isText(next) && !isSelectionWrapper(next.parentNode)) {
Dom.wrap(next, span.cloneNode(), ci);
}
if (next === rng.endContainer) {
break;
}
let step = next.firstChild || next.nextSibling;
if (!step) {
while (next && !next.nextSibling && next !== root) {
next = next.parentNode;
}
step = next === null || next === void 0 ? void 0 : next.nextSibling;
}
next = step;
} while (next && next !== root);
}
/**
* @private
*/
export function getSelectionWrappers(root) {
return $$(`[${TMP_ATTR}]`, root);
}
/**
* @private
*/
export function clearSelectionWrappers(jodit) {
getSelectionWrappers(jodit.editor).forEach(span => Dom.unwrap(span));
clearNativeSelection(jodit);
}
/**
* @private
*/
export function clearSelectionWrappersFromHTML(root) {
return root.replace(RegExp(`<span[^>]+${TMP_ATTR}[^>]+>(.*?)</span>`, 'g'), '$1');
}
/**
* @private
*/
function isSelectionWrapper(node) {
return Dom.isElement(node) && node.hasAttribute(TMP_ATTR);
}
function checkNativeSelectionMethod(jodit, rng, restRanges) {
if (jodit.o.search.useCustomHighlightAPI &&
// @ts-ignore Because Highlight is not defined in the types TS 5.3.3
globalWindow &&
typeof globalWindow.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 true;
}
return false;
}
export function clearNativeSelection(jodit) {
if (jodit.o.search.useCustomHighlightAPI &&
// @ts-ignore Because Highlight is not defined in the types TS 5.3.3
globalWindow &&
typeof globalWindow.Highlight !== 'undefined') {
// @ts-ignore
CSS.highlights.clear();
}
}
function normalizeRanges(rng, restRanges, ci) {
const startText = rng.startContainer.nodeValue;
let diff = 0;
if (rng.startOffset !== 0) {
const text = ci.text(startText.substring(0, rng.startOffset));
rng.startContainer.nodeValue = startText.substring(rng.startOffset);
Dom.before(rng.startContainer, text);
if (rng.startContainer === rng.endContainer) {
diff = rng.startOffset;
rng.endOffset -= diff;
}
rng.startOffset = 0;
}
const endText = rng.endContainer.nodeValue;
if (rng.endOffset !== endText.length) {
const text = ci.text(endText.substring(rng.endOffset));
rng.endContainer.nodeValue = endText.substring(0, rng.endOffset);
Dom.after(rng.endContainer, text);
for (const range of restRanges) {
if (range.startContainer === rng.endContainer) {
range.startContainer = text;
range.startOffset = range.startOffset - rng.endOffset - diff;
if (range.endContainer === rng.endContainer) {
range.endContainer = text;
range.endOffset = range.endOffset - rng.endOffset - diff;
}
}
else {
break;
}
}
rng.endOffset = rng.endContainer.nodeValue.length;
}
}

View File

@@ -0,0 +1,10 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
/**
* @module plugins/search
*/
export * from "./highlight-text-ranges";
export * from "./sentence-finder";

10
node_modules/jodit/esm/plugins/search/helpers/index.js generated vendored Normal file
View File

@@ -0,0 +1,10 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
/**
* @module plugins/search
*/
export * from "./highlight-text-ranges.js";
export * from "./sentence-finder.js";

View File

@@ -0,0 +1,21 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
/**
* @module plugins/search
*/
import type { FuzzySearch, ISelectionRange, Nullable } from "../../../types/index";
export interface State {
query: string;
sentence: SentenceFinder;
}
export declare class SentenceFinder {
private readonly searchIndex;
private queue;
private value;
constructor(searchIndex?: FuzzySearch);
add(node: Text): void;
ranges(needle: string, position?: number): Nullable<ISelectionRange[]>;
}

View File

@@ -0,0 +1,61 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
import { fuzzySearchIndex } from "../../../core/helpers/string/fuzzy-search-index.js";
export class SentenceFinder {
constructor(searchIndex = fuzzySearchIndex) {
this.searchIndex = searchIndex;
this.queue = [];
this.value = '';
}
add(node) {
var _a;
const value = ((_a = node.nodeValue) !== null && _a !== void 0 ? _a : '').toLowerCase();
if (!value.length) {
return;
}
const index = this.value.length;
this.queue.push({
startIndex: index,
endIndex: index + value.length,
node
});
this.value += value;
}
ranges(needle, position = 0) {
const results = [];
let index = position, len = 0, startQueueIndex = 0;
// Find all ranges in substring
do {
[index, len] = this.searchIndex(needle, this.value, index);
if (index !== -1) {
let startContainer, startOffset = 0, endContainer, endOffset = 0;
for (let i = startQueueIndex; i < this.queue.length; i += 1) {
if (!startContainer && this.queue[i].endIndex > index) {
startContainer = this.queue[i].node;
startOffset = index - this.queue[i].startIndex;
}
if (startContainer &&
this.queue[i].endIndex >= index + len) {
endContainer = this.queue[i].node;
endOffset = index + len - this.queue[i].startIndex;
startQueueIndex = i;
break;
}
}
if (startContainer && endContainer) {
results.push({
startContainer,
startOffset,
endContainer,
endOffset
});
}
index += len;
}
} while (index !== -1);
return results.length === 0 ? null : results;
}
}

49
node_modules/jodit/esm/plugins/search/interface.d.ts generated vendored Normal file
View File

@@ -0,0 +1,49 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
/**
* @module plugins/search
*/
declare module 'jodit/types/events' {
interface IEventEmitter {
/**
* Search plugin: Emitted when the user presses the button - find the next element ins search form
* @event
*/
on(event: 'searchNext', callback: () => void): this;
/**
* Search plugin: Emitted when the user presses the button - find the previous element in search form
* @event
*/
on(event: 'searchPrevious', callback: () => void): this;
/**
* Search plugin: Emitted search and select process is finished
*/
on(event: 'afterFindAndSelect', callback: () => void): this;
/**
* Search plugin: Emitted search and replace process is finished
*/
on(event: 'afterFindAndReplace', callback: () => void): this;
}
}
declare module 'jodit/types/jodit' {
interface IJodit {
/**
* Search plugin: Runs a text search and highlights found results
*/
execCommand(command: 'search', query?: string, next?: boolean): void;
/**
* Search plugin: Open search form
*/
execCommand(command: 'openSearchDialog', query?: string): void;
/**
* Search plugin: Open replace form
*/
execCommand(command: 'openReplaceDialog', query?: string, replace?: string): void;
registerCommand(command: 'search', callback: (command: 'search', openReplaceDialogquery?: string, next?: boolean) => void): void;
registerCommand(command: 'openSearchDialog', callback: (command: 'openSearchDialog', query?: string) => void): void;
registerCommand(command: 'openReplaceDialog', callback: (command: 'openReplaceDialog', query?: string, replace?: string) => void): void;
}
}

1
node_modules/jodit/esm/plugins/search/interface.js generated vendored Normal file
View File

@@ -0,0 +1 @@
"use strict";

57
node_modules/jodit/esm/plugins/search/search.d.ts generated vendored Normal file
View File

@@ -0,0 +1,57 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
/**
* [[include:plugins/search/README.md]]
* @packageDocumentation
* @module plugins/search
*/
import type { IJodit, IPlugin, ISelectionRange, Nullable } from "../../types/index";
import { LazyWalker } from "../../core/dom/index";
import { Plugin } from "../../core/plugin/index";
import "./config";
/**
* Search plugin. it is used for custom search in text
* ![search](https://user-images.githubusercontent.com/794318/34545433-cd0a9220-f10e-11e7-8d26-7e22f66e266d.gif)
*
* @example
* ```typescript
* const jodit = Jodit.make('#editor', {
* useSearch: false
* });
* // or
* const jodit = Jodit.make('#editor', {
* disablePlugins: 'search'
* });
* ```
*/
export declare class search extends Plugin {
buttons: IPlugin['buttons'];
private get ui();
private updateCounters;
protected onPressReplaceButton(): void;
private tryScrollToElement;
protected calcCounts(query: string): Promise<number>;
findQueryBounds(query: string, walkerKey: 'walker' | 'walkerCount'): Promise<ISelectionRange[]>;
findAndReplace(query: string): Promise<boolean>;
private previousQuery;
private drawPromise;
findAndSelect(query: string, next: boolean): Promise<boolean>;
private findCurrentIndexInRanges;
walker: Nullable<LazyWalker>;
walkerCount: Nullable<LazyWalker>;
private cache;
private isValidCache;
private find;
private wrapFrameRequest;
private __drawSelectionRanges;
protected onAfterGetValueFromEditor(data: {
value: string;
}): void;
/** @override */
afterInit(editor: IJodit): void;
/** @override */
beforeDestruct(jodit: IJodit): void;
}

356
node_modules/jodit/esm/plugins/search/search.js generated vendored Normal file
View File

@@ -0,0 +1,356 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
r = Reflect.decorate(decorators, target, key, desc);
else
for (var i = decorators.length - 1; i >= 0; i--)
if (d = decorators[i])
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { IS_PROD } from "../../core/constants.js";
import { autobind, cache, cached, watch } from "../../core/decorators/index.js";
import { Dom, LazyWalker } from "../../core/dom/index.js";
import { pluginSystem } from "../../core/global.js";
import { scrollIntoViewIfNeeded } from "../../core/helpers/index.js";
import { Plugin } from "../../core/plugin/index.js";
import "./config.js";
import { clearSelectionWrappers, clearSelectionWrappersFromHTML, getSelectionWrappers, highlightTextRanges, SentenceFinder } from "./helpers/index.js";
import { UISearch } from "./ui/search.js";
/**
* Search plugin. it is used for custom search in text
* ![search](https://user-images.githubusercontent.com/794318/34545433-cd0a9220-f10e-11e7-8d26-7e22f66e266d.gif)
*
* @example
* ```typescript
* const jodit = Jodit.make('#editor', {
* useSearch: false
* });
* // or
* const jodit = Jodit.make('#editor', {
* disablePlugins: 'search'
* });
* ```
*/
export class search extends Plugin {
constructor() {
super(...arguments);
this.buttons = [
{
name: 'find',
group: 'search'
}
];
this.previousQuery = '';
this.drawPromise = null;
this.walker = null;
this.walkerCount = null;
this.cache = {};
this.wrapFrameRequest = 0;
}
get ui() {
return new UISearch(this.j);
}
async updateCounters() {
if (!this.ui.isOpened) {
return;
}
this.ui.count = await this.calcCounts(this.ui.query);
}
onPressReplaceButton() {
this.findAndReplace(this.ui.query);
this.updateCounters();
}
tryScrollToElement(startContainer) {
// find scrollable element
let parentBox = Dom.closest(startContainer, Dom.isElement, this.j.editor);
if (!parentBox) {
parentBox = Dom.prev(startContainer, Dom.isElement, this.j.editor);
}
parentBox &&
parentBox !== this.j.editor &&
scrollIntoViewIfNeeded(parentBox, this.j.editor, this.j.ed);
}
async calcCounts(query) {
return (await this.findQueryBounds(query, 'walkerCount')).length;
}
async findQueryBounds(query, walkerKey) {
let walker = this[walkerKey];
if (walker) {
walker.break();
}
walker = new LazyWalker(this.j.async, {
timeout: this.j.o.search.lazyIdleTimeout
});
this[walkerKey] = walker;
return this.find(walker, query).catch(e => {
!IS_PROD && console.error(e);
return [];
});
}
async findAndReplace(query) {
const bounds = await this.findQueryBounds(query, 'walker');
if (!bounds.length) {
return false;
}
let currentIndex = this.findCurrentIndexInRanges(bounds, this.j.s.range);
if (currentIndex === -1) {
currentIndex = 0;
}
const bound = bounds[currentIndex];
if (bound) {
try {
const rng = this.j.ed.createRange();
rng.setStart(bound.startContainer, bound.startOffset);
rng.setEnd(bound.endContainer, bound.endOffset);
rng.deleteContents();
const textNode = this.j.createInside.text(this.ui.replace);
Dom.safeInsertNode(rng, textNode);
clearSelectionWrappers(this.j);
this.j.s.setCursorAfter(textNode);
this.tryScrollToElement(textNode);
this.cache = {};
this.ui.currentIndex = currentIndex;
await this.findAndSelect(query, true).catch(e => {
!IS_PROD && console.error(e);
return null;
});
}
finally {
this.j.synchronizeValues();
}
this.j.e.fire('afterFindAndReplace');
return true;
}
return false;
}
async findAndSelect(query, next) {
var _a;
const bounds = await this.findQueryBounds(query, 'walker');
if (!bounds.length) {
return false;
}
if (this.previousQuery !== query ||
!getSelectionWrappers(this.j.editor).length) {
(_a = this.drawPromise) === null || _a === void 0 ? void 0 : _a.rejectCallback();
this.j.async.cancelAnimationFrame(this.wrapFrameRequest);
clearSelectionWrappers(this.j);
this.drawPromise = this.__drawSelectionRanges(bounds);
}
this.previousQuery = query;
let currentIndex = this.ui.currentIndex - 1;
if (currentIndex === -1) {
currentIndex = 0;
}
else if (next) {
currentIndex =
currentIndex === bounds.length - 1 ? 0 : currentIndex + 1;
}
else {
currentIndex =
currentIndex === 0 ? bounds.length - 1 : currentIndex - 1;
}
this.ui.currentIndex = currentIndex + 1;
const bound = bounds[currentIndex];
if (bound) {
const rng = this.j.ed.createRange();
try {
rng.setStart(bound.startContainer, bound.startOffset);
rng.setEnd(bound.endContainer, bound.endOffset);
this.j.s.selectRange(rng);
}
catch (e) {
!IS_PROD && console.error(e);
}
this.tryScrollToElement(bound.startContainer);
await this.updateCounters();
await this.drawPromise;
this.j.e.fire('afterFindAndSelect');
return true;
}
return false;
}
findCurrentIndexInRanges(bounds, range) {
return bounds.findIndex(bound => bound.startContainer === range.startContainer &&
bound.startOffset === range.startOffset &&
bound.endContainer === range.startContainer &&
bound.endOffset === range.endOffset);
}
async isValidCache(promise) {
const res = await promise;
return res.every(r => {
var _a, _b, _c, _d;
return r.startContainer.isConnected &&
r.startOffset <= ((_b = (_a = r.startContainer.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) &&
r.endContainer.isConnected &&
r.endOffset <= ((_d = (_c = r.endContainer.nodeValue) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0);
});
}
async find(walker, query) {
if (!query.length) {
return [];
}
const cache = this.cache[query];
if (cache && (await this.isValidCache(cache))) {
return cache;
}
this.cache[query] = this.j.async.promise(resolve => {
const sentence = new SentenceFinder(this.j.o.search.fuzzySearch);
walker
.on('break', () => {
resolve([]);
})
.on('visit', (elm) => {
if (Dom.isText(elm)) {
sentence.add(elm);
}
return false;
})
.on('end', () => {
var _a;
resolve((_a = sentence.ranges(query)) !== null && _a !== void 0 ? _a : []);
})
.setWork(this.j.editor);
});
return this.cache[query];
}
__drawSelectionRanges(ranges) {
const { async, createInside: ci, editor } = this.j;
async.cancelAnimationFrame(this.wrapFrameRequest);
const parts = [...ranges];
let sRange, total = 0;
return async.promise(resolve => {
const drawParts = () => {
do {
sRange = parts.shift();
if (sRange) {
highlightTextRanges(this.j, sRange, parts, ci, editor);
}
total += 1;
} while (sRange && total <= 5);
if (parts.length) {
this.wrapFrameRequest =
async.requestAnimationFrame(drawParts);
}
else {
resolve();
}
};
drawParts();
});
}
onAfterGetValueFromEditor(data) {
data.value = clearSelectionWrappersFromHTML(data.value);
}
/** @override */
afterInit(editor) {
if (editor.o.useSearch) {
const self = this;
editor.e
.on('beforeSetMode.search', () => {
this.ui.close();
})
.on(this.ui, 'afterClose', () => {
clearSelectionWrappers(editor);
this.ui.currentIndex = 0;
this.ui.count = 0;
this.cache = {};
editor.focus();
})
.on('click', () => {
this.ui.currentIndex = 0;
clearSelectionWrappers(editor);
})
.on('change.search', () => {
this.cache = {};
})
.on('keydown.search mousedown.search', editor.async.debounce(() => {
if (this.ui.selInfo) {
editor.s.removeMarkers();
this.ui.selInfo = null;
}
if (this.ui.isOpened) {
void this.updateCounters();
}
}, editor.defaultTimeout))
.on('searchNext.search searchPrevious.search', () => {
if (!this.ui.isOpened) {
this.ui.open();
}
return self
.findAndSelect(self.ui.query, editor.e.current === 'searchNext')
.catch(e => {
!IS_PROD && console.error('Search error', e);
});
})
.on('search.search', (value, next = true) => {
this.ui.currentIndex = 0;
return self.findAndSelect(value || '', next).catch(e => {
!IS_PROD && console.error('Search error', e);
});
});
editor
.registerCommand('search', {
exec: (command, value, next = true) => {
value &&
self.findAndSelect(value, next).catch(e => {
!IS_PROD && console.error('Search error', e);
});
return false;
}
})
.registerCommand('openSearchDialog', {
exec: (command, value) => {
self.ui.open(value);
return false;
},
hotkeys: ['ctrl+f', 'cmd+f']
})
.registerCommand('openReplaceDialog', {
exec: (command, query, replace) => {
if (!editor.o.readonly) {
self.ui.open(query, replace, true);
}
return false;
},
hotkeys: ['ctrl+h', 'cmd+h']
});
}
}
/** @override */
beforeDestruct(jodit) {
var _a;
(_a = cached(this, 'ui')) === null || _a === void 0 ? void 0 : _a.destruct();
jodit.e.off('.search');
}
}
__decorate([
cache
], search.prototype, "ui", null);
__decorate([
watch('ui:needUpdateCounters')
], search.prototype, "updateCounters", null);
__decorate([
watch('ui:pressReplaceButton')
], search.prototype, "onPressReplaceButton", null);
__decorate([
autobind
], search.prototype, "findQueryBounds", null);
__decorate([
autobind
], search.prototype, "findAndReplace", null);
__decorate([
autobind
], search.prototype, "findAndSelect", null);
__decorate([
autobind
], search.prototype, "find", null);
__decorate([
watch(':afterGetValueFromEditor')
], search.prototype, "onAfterGetValueFromEditor", null);
pluginSystem.add('search', search);

1
node_modules/jodit/esm/plugins/search/search.svg.js generated vendored Normal file
View File

@@ -0,0 +1 @@
export default "<svg viewBox=\"0 0 500 500\" xmlns=\"http://www.w3.org/2000/svg\"> <path clip-rule=\"evenodd\" d=\"M306.39,154.09c19.628,4.543,35.244,21.259,39.787,39.523 c1.551,8.54,8.998,14.989,17.904,14.989c9.991,0,18.168-8.175,18.168-18.17c0-13.083-10.991-32.98-25.985-47.881 c-14.719-14.537-32.252-24.802-46.695-24.802c-9.991,0-18.172,8.45-18.172,18.446C291.396,145.094,297.847,152.546,306.39,154.09z M56.629,392.312c-14.09,14.08-14.09,36.979,0,51.059c14.08,14.092,36.981,14.092,50.965,0l104.392-104.303 c24.347,15.181,53.062,23.991,83.953,23.991c87.857,0,158.995-71.142,158.995-158.999c0-87.854-71.138-158.995-158.995-158.995 c-87.856,0-158.995,71.141-158.995,158.995c0,30.802,8.819,59.606,23.992,83.953L56.629,392.312z M182.371,204.06 c0-62.687,50.875-113.568,113.568-113.568s113.569,50.881,113.569,113.568c0,62.694-50.876,113.569-113.569,113.569 S182.371,266.754,182.371,204.06z\" fill-rule=\"evenodd\"/> </svg> ";

36
node_modules/jodit/esm/plugins/search/ui/search.d.ts generated vendored Normal file
View File

@@ -0,0 +1,36 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
/**
* @module plugins/search
*/
import type { IJodit, MarkerInfo, Nullable } from "../../../types/index";
import { UIElement } from "../../../core/ui/index";
export declare class UISearch extends UIElement<IJodit> {
className(): string;
private queryInput;
private replaceInput;
selInfo: Nullable<MarkerInfo[]>;
private closeButton;
private replaceButton;
private currentBox;
private countBox;
render(): string;
private _currentIndex;
get currentIndex(): number;
set currentIndex(value: number);
set count(value: number);
get query(): string;
get replace(): string;
constructor(jodit: IJodit);
protected onEditorKeyDown(e: KeyboardEvent): void;
isOpened: boolean;
open(query?: string, replace?: string, searchAndReplace?: boolean): void;
close(): void;
/**
* Calculate position if sticky is enabled
*/
private calcSticky;
}

210
node_modules/jodit/esm/plugins/search/ui/search.js generated vendored Normal file
View File

@@ -0,0 +1,210 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
r = Reflect.decorate(decorators, target, key, desc);
else
for (var i = decorators.length - 1; i >= 0; i--)
if (d = decorators[i])
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { MODE_WYSIWYG } from "../../../core/constants.js";
import * as consts from "../../../core/constants.js";
import { autobind, component, watch } from "../../../core/decorators/index.js";
import { Dom } from "../../../core/dom/index.js";
import { css, position, refs, trim } from "../../../core/helpers/index.js";
import { Icon, UIElement } from "../../../core/ui/index.js";
let UISearch = class UISearch extends UIElement {
className() {
return 'UISearch';
}
render() {
return `<div>
<div class="&__box">
<div class="&__inputs">
<input data-ref="query" tabindex="0" placeholder="~Search for~" type="text"/>
<input data-ref="replace" tabindex="0" placeholder="~Replace with~" type="text"/>
</div>
<div class="&__counts">
<span data-ref="counter-box">
<span data-ref="current">0</span><span>/</span><span data-ref="count">0</span>
</span>
</div>
<div class="&__buttons">
<button data-ref="next" tabindex="0" type="button">${Icon.get('angle-down')}</button>
<button data-ref="prev" tabindex="0" type="button">${Icon.get('angle-up')}</button>
<button data-ref="cancel" tabindex="0" type="button">${Icon.get('cancel')}</button>
<button data-ref="replace-btn" tabindex="0" type="button" class="jodit-ui-button">~Replace~</button>
</div>
</div>
</div>`;
}
get currentIndex() {
return this._currentIndex;
}
set currentIndex(value) {
this._currentIndex = value;
this.currentBox.innerText = value.toString();
}
set count(value) {
this.countBox.innerText = value.toString();
}
get query() {
return this.queryInput.value;
}
get replace() {
return this.replaceInput.value;
}
constructor(jodit) {
super(jodit);
this.selInfo = null;
this._currentIndex = 0;
this.isOpened = false;
const { query, replace, cancel, next, prev, replaceBtn, current, count } = refs(this.container);
this.queryInput = query;
this.replaceInput = replace;
this.closeButton = cancel;
this.replaceButton = replaceBtn;
this.currentBox = current;
this.countBox = count;
jodit.e
.on(this.closeButton, 'pointerdown', () => {
this.close();
return false;
})
.on(this.queryInput, 'input', () => {
this.currentIndex = 0;
})
.on(this.queryInput, 'pointerdown', () => {
if (jodit.s.isFocused()) {
jodit.s.removeMarkers();
this.selInfo = jodit.s.save();
}
})
.on(this.replaceButton, 'pointerdown', () => {
jodit.e.fire(this, 'pressReplaceButton');
return false;
})
.on(next, 'pointerdown', () => {
void jodit.e.fire('searchNext');
return false;
})
.on(prev, 'pointerdown', () => {
jodit.e.fire('searchPrevious');
return false;
})
.on(this.queryInput, 'input', () => {
this.setMod('empty-query', !trim(this.queryInput.value).length);
})
.on(this.queryInput, 'keydown', this.j.async.debounce(async (e) => {
switch (e.key) {
case consts.KEY_ENTER:
e.preventDefault();
e.stopImmediatePropagation();
if (await jodit.e.fire('searchNext')) {
this.close();
}
break;
default:
jodit.e.fire(this, 'needUpdateCounters');
break;
}
}, this.j.defaultTimeout));
}
onEditorKeyDown(e) {
if (!this.isOpened) {
return;
}
const { j } = this;
if (j.getRealMode() !== MODE_WYSIWYG) {
return;
}
switch (e.key) {
case consts.KEY_ESC:
this.close();
break;
case consts.KEY_F3:
if (this.queryInput.value) {
j.e.fire(!e.shiftKey ? 'searchNext' : 'searchPrevious');
e.preventDefault();
}
break;
}
}
open(query, replace, searchAndReplace = false) {
if (!this.isOpened) {
this.j.workplace.appendChild(this.container);
this.isOpened = true;
}
this.calcSticky(this.j.e.fire('getStickyState.sticky') || false);
this.j.e.fire('hidePopup');
this.setMod('replace', searchAndReplace);
// this.current = this.j.s.current();
const selStr = query !== null && query !== void 0 ? query : (this.j.s.sel || '').toString();
if (selStr) {
this.queryInput.value = selStr;
}
if (replace) {
this.replaceInput.value = replace;
}
this.setMod('empty-query', !selStr.length);
this.j.e.fire(this, 'needUpdateCounters');
if (selStr) {
this.queryInput.select();
}
else {
this.queryInput.focus();
}
}
close() {
if (!this.isOpened) {
return;
}
this.j.s.restore();
Dom.safeRemove(this.container);
this.isOpened = false;
this.j.e.fire(this, 'afterClose');
}
/**
* Calculate position if sticky is enabled
*/
calcSticky(enabled) {
if (this.isOpened) {
this.setMod('sticky', enabled);
if (enabled) {
const pos = position(this.j.toolbarContainer);
css(this.container, {
top: pos.top + pos.height,
left: pos.left + pos.width
});
}
else {
css(this.container, {
top: null,
left: null
});
}
}
}
};
__decorate([
watch([':keydown', 'queryInput:keydown'])
], UISearch.prototype, "onEditorKeyDown", null);
__decorate([
autobind
], UISearch.prototype, "open", null);
__decorate([
autobind
], UISearch.prototype, "close", null);
__decorate([
watch(':toggleSticky')
], UISearch.prototype, "calcSticky", null);
UISearch = __decorate([
component
], UISearch);
export { UISearch };