@ckeditor/ckeditor5-find-and-replace
Version:
Find and replace feature for CKEditor 5.
310 lines (309 loc) • 9.06 kB
TypeScript
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
/**
* @module find-and-replace/ui/findandreplaceformview
*/
import { View, LabeledFieldView, FocusCycler, ViewCollection, type InputView } from 'ckeditor5/src/ui.js';
import { type Locale } from 'ckeditor5/src/utils.js';
import '@ckeditor/ckeditor5-ui/theme/components/responsive-form/responsiveform.css';
import '../../theme/findandreplaceform.css';
/**
* The find and replace form view class.
*
* See {@link module:find-and-replace/ui/findandreplaceformview~FindAndReplaceFormView}.
*/
export default class FindAndReplaceFormView extends View {
/**
* A collection of child views.
*/
children: ViewCollection;
/**
* Stores the number of matched search results.
*
* @readonly
* @observable
*/
matchCount: number;
/**
* The offset of currently highlighted search result in {@link #matchCount matched results}.
*
* @observable
*/
readonly highlightOffset: number;
/**
* `true` when the search params (find text, options) has been changed by the user since
* the last time find was executed. `false` otherwise.
*
* @readonly
* @observable
*/
isDirty: boolean;
/**
* A live object with the aggregated `isEnabled` states of editor commands related to find and
* replace. For instance, it may look as follows:
*
* ```json
* {
* findNext: true,
* findPrevious: true,
* replace: false,
* replaceAll: false
* }
* ```
*
* @internal
* @observable
*/
readonly _areCommandsEnabled: Record<string, boolean>;
/**
* The content of the counter label displaying the index of the current highlighted match
* on top of the find input, for instance "3 of 50".
*
* @internal
* @readonly
* @observable
*/
_resultsCounterText: string;
/**
* The flag reflecting the state of the "Match case" switch button in the search options
* dropdown.
*
* @internal
* @readonly
* @observable
*/
_matchCase: boolean;
/**
* The flag reflecting the state of the "Whole words only" switch button in the search options
* dropdown.
*
* @internal
* @readonly
* @observable
*/
_wholeWordsOnly: boolean;
/**
* This flag is set `true` when some matches were found and the user didn't change the search
* params (text to find, options) yet. This is only possible immediately after hitting the "Find" button.
* `false` when there were no matches (see {@link #matchCount}) or the user changed the params (see {@link #isDirty}).
*
* It is used to control the enabled state of the replace UI (input and buttons); replacing text is only possible
* if this flag is `true`.
*
* @internal
* @observable
*/
readonly _searchResultsFound: boolean;
/**
* The find in text input view that stores the searched string.
*
* @internal
*/
readonly _findInputView: LabeledFieldView<InputView>;
/**
* The replace input view.
*/
private readonly _replaceInputView;
/**
* The find button view that initializes the search process.
*/
private readonly _findButtonView;
/**
* The find previous button view.
*/
private readonly _findPrevButtonView;
/**
* The find next button view.
*/
private readonly _findNextButtonView;
/**
* A collapsible view aggregating the advanced search options.
*/
private readonly _advancedOptionsCollapsibleView;
/**
* A switch button view controlling the "Match case" option.
*/
private readonly _matchCaseSwitchView;
/**
* A switch button view controlling the "Whole words only" option.
*/
private readonly _wholeWordsOnlySwitchView;
/**
* The replace button view.
*/
private readonly _replaceButtonView;
/**
* The replace all button view.
*/
private readonly _replaceAllButtonView;
/**
* The `div` aggregating the inputs.
*/
private readonly _inputsDivView;
/**
* The `div` aggregating the action buttons.
*/
private readonly _actionButtonsDivView;
/**
* Tracks information about the DOM focus in the form.
*/
private readonly _focusTracker;
/**
* An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.
*/
private readonly _keystrokes;
/**
* A collection of views that can be focused in the form.
*/
private readonly _focusables;
/**
* Helps cycling over {@link #_focusables} in the form.
*/
readonly focusCycler: FocusCycler;
locale: Locale;
/**
* Creates a view of find and replace form.
*
* @param locale The localization services instance.
*/
constructor(locale: Locale);
/**
* @inheritDoc
*/
render(): void;
/**
* @inheritDoc
*/
destroy(): void;
/**
* @inheritDoc
*/
focus(direction?: 1 | -1): void;
/**
* Resets the form before re-appearing.
*
* It clears error messages, hides the match counter and disables the replace feature
* until the next hit of the "Find" button.
*
* **Note**: It does not reset inputs and options, though. This way the form works better in editors with
* disappearing toolbar (e.g. BalloonEditor): hiding the toolbar by accident (together with the find and replace UI)
* does not require filling the entire form again.
*/
reset(): void;
/**
* Returns the value of the find input.
*/
private get _textToFind();
/**
* Returns the value of the replace input.
*/
private get _textToReplace();
/**
* Configures and returns the `<div>` aggregating all form inputs.
*/
private _createInputsDiv;
/**
* The action performed when the {@link #_findButtonView} is pressed.
*/
private _onFindButtonExecute;
/**
* Configures an injects the find results counter displaying a "N of M" label of the {@link #_findInputView}.
*/
private _injectFindResultsCounter;
/**
* Creates the collapsible view aggregating the advanced search options.
*/
private _createAdvancedOptionsCollapsible;
/**
* Configures and returns the `<div>` element aggregating all form action buttons.
*/
private _createActionButtonsDiv;
/**
* Creates, configures and returns and instance of a dropdown allowing users to narrow
* the search criteria down. The dropdown has a list with switch buttons for each option.
*/
private _createMatchCaseSwitch;
/**
* Creates, configures and returns and instance of a dropdown allowing users to narrow
* the search criteria down. The dropdown has a list with switch buttons for each option.
*/
private _createWholeWordsOnlySwitch;
/**
* Initializes the {@link #_focusables} and {@link #_focusTracker} to allow navigation
* using <kbd>Tab</kbd> and <kbd>Shift</kbd>+<kbd>Tab</kbd> keystrokes in the right order.
*/
private _initFocusCycling;
/**
* Initializes the keystroke handling in the form.
*/
private _initKeystrokeHandling;
/**
* Creates a button view.
*
* @param options The properties of the `ButtonView`.
* @returns The button view instance.
*/
private _createButton;
/**
* Creates a labeled input view.
*
* @param label The input label.
* @returns The labeled input view instance.
*/
private _createInputField;
}
/**
* Fired when the find next button is triggered.
*
* @eventName ~FindAndReplaceFormView#findNext
* @param data The event data.
*/
export type FindNextEvent = {
name: 'findNext';
args: [data?: FindNextEventData];
};
export type FindNextEventData = FindEventBaseData & {
matchCase: boolean;
wholeWords: boolean;
};
/**
* Fired when the find previous button is triggered.
*
* @eventName ~FindAndReplaceFormView#findPrevious
* @param data The event data.
*/
export type FindPreviousEvent = {
name: 'findPrevious';
args: [data?: FindEventBaseData];
};
/**
* Base type for all find/replace events.
*/
export type FindEventBaseData = {
searchText: string;
};
/**
* Fired when the replace button is triggered.
*
* @eventName ~FindAndReplaceFormView#replace
* @param data The event data.
*/
export type ReplaceEvent = {
name: 'replace';
args: [data: ReplaceEventData];
};
export type ReplaceEventData = FindEventBaseData & {
replaceText: string;
};
/**
* Fired when the replaceAll button is triggered.
*
* @eventName ~FindAndReplaceFormView#replaceAll
* @param data The event data.
*/
export type ReplaceAllEvent = {
name: 'replaceAll';
args: [data: ReplaceEventData];
};