Skip to content

Commit

Permalink
Docs and refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
DawidKossowski committed Sep 22, 2023
1 parent 0cb1dc1 commit 2fca617
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 43 deletions.
36 changes: 17 additions & 19 deletions packages/ckeditor5-ui/src/autocomplete/autocompleteview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ export default class AutocompleteView<
*/
protected override _config: AutocompleteViewConfig<TQueryFieldView>;

declare public resultsView: AutocompleteResultsView;

/**
* @inheritDoc
*/
Expand All @@ -44,21 +46,20 @@ export default class AutocompleteView<
}
} );

const resultsView = this.resultsView as AutocompleteResultsView;
const bindResultsView = resultsView.bindTemplate;
const bindResultsView = this.resultsView.bindTemplate;

resultsView.set( 'isVisible', false );
resultsView.set( '_position', 's' );
resultsView.set( '_width', 0 );
this.resultsView.set( 'isVisible', false );
this.resultsView.set( '_position', 's' );
this.resultsView.set( '_width', 0 );

resultsView.extendTemplate( {
this.resultsView.extendTemplate( {
attributes: {
class: [
bindResultsView.if( 'isVisible', 'ck-hidden', value => !value ),
bindResultsView.to( '_position', value => `ck-search__results_${ value }` )
],
style: {
width: bindResultsView.to( '_width', value => toPx( value ) )
width: bindResultsView.to( '_width', toPx )
}
}
} );
Expand All @@ -70,7 +71,7 @@ export default class AutocompleteView<

if ( isFocused ) {
// Reset the scroll position of the results view whenever the autocomplete reopens.
resultsView.element!.scrollTop = 0;
this.resultsView.element!.scrollTop = 0;
} else if ( config.resetOnBlur ) {
this.queryView.reset();
}
Expand All @@ -86,7 +87,7 @@ export default class AutocompleteView<

// Hide the results view when the user presses the ESC key.
this.keystrokes.set( 'esc', ( evt, cancel ) => {
resultsView.isVisible = false;
this.resultsView.isVisible = false;
cancel();
} );

Expand Down Expand Up @@ -116,11 +117,11 @@ export default class AutocompleteView<
this.queryView.fieldView.value = this.queryView.fieldView.element!.value = value;

// Finally, hide the results view. The focus has been moved earlier so this is safe.
resultsView.isVisible = false;
this.resultsView.isVisible = false;
} );

// Update the position and width of the results view when it becomes visible.
resultsView.on( 'change:isVisible', () => {
this.resultsView.on( 'change:isVisible', () => {
this._updateResultsViewWidthAndPosition();
} );
}
Expand All @@ -129,13 +130,11 @@ export default class AutocompleteView<
* Updates the position of the results view on demand.
*/
private _updateResultsViewWidthAndPosition() {
const resultsView = ( this.resultsView as AutocompleteResultsView );

if ( !resultsView.isVisible ) {
if ( !this.resultsView.isVisible ) {
return;
}

resultsView._width = new Rect( this.queryView.fieldView.element! ).width;
this.resultsView._width = new Rect( this.queryView.fieldView.element! ).width;

const optimalResultsPosition = AutocompleteView._getOptimalPosition( {
element: this.resultsView.element!,
Expand All @@ -145,18 +144,17 @@ export default class AutocompleteView<
} );

// _getOptimalPosition will return null if there is no optimal position found (e.g. target is off the viewport).
resultsView._position = optimalResultsPosition ? optimalResultsPosition.name as string : 's';
this.resultsView._position = optimalResultsPosition ? optimalResultsPosition.name : 's';
}

/**
* Updates the visibility of the results view on demand.
*/
private _updateResultsVisibility() {
const resultsView = ( this.resultsView as AutocompleteResultsView );
const queryMinChars = typeof this._config.queryMinChars === 'undefined' ? 0 : this._config.queryMinChars;
const queryLength = this.queryView.fieldView.element!.value.length;

resultsView.isVisible = this.focusTracker.isFocused && this.isEnabled && queryLength >= queryMinChars;
this.resultsView.isVisible = this.focusTracker.isFocused && this.isEnabled && queryLength >= queryMinChars;
}

/**
Expand Down Expand Up @@ -204,7 +202,7 @@ export interface AutocompleteResultsView extends SearchResultsView {
*
* @internal
*/
_position: string;
_position?: string;

/**
* The observable property determining the CSS width of the results view.
Expand Down
23 changes: 13 additions & 10 deletions packages/ckeditor5-ui/src/highlightedtext/highlightedtextview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export default class HighlightedTextView extends View {
* The text that can be highlighted using the {@link #highlightText} method.
*
* **Note:** When this property changes, the previous highlighting is removed.
*
* @observable
*/
declare public text: string | undefined;

Expand Down Expand Up @@ -62,31 +64,31 @@ export default class HighlightedTextView extends View {

/**
* Updates element's innerHTML with the passed content.
*
* @param newText
*/
private _updateInnerHTML( newInnerHTML: string | undefined ) {
this.element!.innerHTML = newInnerHTML || '';
}
}

// Replaces RegExp occurrences with <mark> tags in a text.
//
// @param text A text to get marked.
// @param [regExp] An optional RegExp. If not passed, this is a pass-through function.
// @returns A text with RegExp occurrences marked by <mark>.
function markText( text: string, regExp: RegExp | null ) {
/**
* Replaces RegExp occurrences with <mark> tags in a text.
*
* @param text A text to get marked.
* @param regExp An optional RegExp. If not passed, this is a pass-through function.
* @returns A text with RegExp occurrences marked by <mark>.
*/
function markText( text: string, regExp?: RegExp | null ) {
if ( !regExp ) {
return escape( text );
}

const textParts: Array<{ text: string; isMatch: boolean }> = [];
let lastMatchEnd = 0;
let matchInfo;
let matchInfo = regExp.exec( text );

// Iterate over all matches and create an array of text parts. The idea is to mark which parts are query matches
// so that later on they can be highlighted.
while ( ( matchInfo = regExp.exec( text ) ) !== null ) {
while ( matchInfo !== null ) {
const curMatchStart = matchInfo.index;
// Detect if there was something between last match and this one.
if ( curMatchStart !== lastMatchEnd ) {
Expand All @@ -102,6 +104,7 @@ function markText( text: string, regExp: RegExp | null ) {
} );

lastMatchEnd = regExp.lastIndex;
matchInfo = regExp.exec( text );
}

// Your match might not be the last part of a string. Be sure to add any plain text following the last match.
Expand Down
2 changes: 1 addition & 1 deletion packages/ckeditor5-ui/src/search/searchinfoview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import View from '../view';
/**
* A view displaying an information text related to different states of {@link module:ui/search/text/searchtextview~SearchTextView}.
*
* @private
* @internal
*/
export default class SearchInfoView extends View {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { icons } from '@ckeditor/ckeditor5-core';
/**
* A search input field for the {@link module:ui/search/text/searchtextview~SearchTextView} component.
*
* @private
* @internal
* @extends module:ui/labeledfield/labeledfieldview~LabeledFieldView
*/
export default class SearchTextQueryView<
Expand Down
40 changes: 28 additions & 12 deletions packages/ckeditor5-ui/src/search/text/searchtextview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,20 +81,23 @@ export default class SearchTextView<
* Controls whether the component is in read-only mode.
*
* @default true
* @observable
*/
declare public isEnabled: boolean;

/**
* The number of results found for the current search query. Updated upon the {@link #search} event.
*
* @default 0
* @observable
*/
declare public resultsCount: number;

/**
* The number of the items that can be searched in the {@link #filteredView}. Updated upon the {@link #search} event.
*
* @default 0
* @observable
*/
declare public totalItemsCount: number;

Expand All @@ -112,6 +115,8 @@ export default class SearchTextView<
*/
declare public readonly focusableChildren: ViewCollection;

public declare locale: Locale;

/**
* Provides the focus management (keyboard navigation) between {@link #queryView} and {@link #filteredView}.
*
Expand Down Expand Up @@ -177,7 +182,7 @@ export default class SearchTextView<
}
} );

this.on( 'search', ( evt, { resultsCount, totalItemsCount } ) => {
this.on<SearchTextViewSearchEvent>( 'search', ( evt, { resultsCount, totalItemsCount } ) => {
this.resultsCount = resultsCount;
this.totalItemsCount = totalItemsCount;
} );
Expand Down Expand Up @@ -256,12 +261,9 @@ export default class SearchTextView<

/**
* Creates a search field view based on configured creator..
*
* @param locale The localization services instance.
* @param label The label of the search field.
*/
private _createSearchTextQueryView(): SearchTextQueryView<TQueryFieldView> {
const queryView = new SearchTextQueryView<TQueryFieldView>( this.locale!, this._config.queryView );
const queryView = new SearchTextQueryView<TQueryFieldView>( this.locale, this._config.queryView );

this.listenTo( queryView.fieldView, 'input', () => {
this.search( queryView.fieldView.element!.value );
Expand All @@ -278,12 +280,12 @@ export default class SearchTextView<
* was specified in the view config.
*/
private _enableDefaultInfoViewBehavior(): void {
const t = this.locale!.t;
const t = this.locale.t;
const infoView = this.infoView as SearchInfoView;

this.on<SearchTextViewSearchEvent>( 'search', ( evt, data ) => {
if ( !data.resultsCount ) {
const defaultTextConfig = this._config.infoView?.text;
const defaultTextConfig = this._config.infoView && this._config.infoView.text;
let primaryText, secondaryText;

if ( data.totalItemsCount ) {
Expand Down Expand Up @@ -380,9 +382,23 @@ export type SearchTextViewDefaultInfoText = string | ( ( query: string, resultsC
*/
export type SearchTextViewSearchEvent = {
name: 'search';
args: [ {
query: string;
resultsCount: number;
totalItemsCount: number;
} ];
args: [ SearchTextViewSearchEventData ];
};

export type SearchTextViewSearchEventData = {

/**
* The search query string.
*/
query: string;

/**
* The number of results found for the current search query.
*/
resultsCount: number;

/**
* The number of the items that can be searched.
*/
totalItemsCount: number;
};

0 comments on commit 2fca617

Please sign in to comment.