diff --git a/ngcomponents/lib/angular_components.dart b/ngcomponents/lib/angular_components.dart index 793df26c..69153912 100644 --- a/ngcomponents/lib/angular_components.dart +++ b/ngcomponents/lib/angular_components.dart @@ -18,8 +18,6 @@ import 'focus/focus_list.dart'; import 'focus/focus_trap.dart'; import 'focus/keyboard_only_focus_indicator.dart'; import 'glyph/glyph.dart'; -import 'highlighted_text/highlighted_text.dart'; -import 'highlighted_text/highlighted_value.dart'; import 'laminate/components/modal/modal.dart'; import 'material_button/material_button.dart'; import 'material_button/material_fab.dart'; @@ -104,8 +102,6 @@ export 'focus/focus_trap.dart'; export 'focus/keyboard_only_focus_indicator.dart'; export 'forms/error_renderer.dart'; export 'glyph/glyph.dart'; -export 'highlighted_text/highlighted_text.dart'; -export 'highlighted_text/highlighted_value.dart'; export 'laminate/components/modal/modal.dart'; export 'laminate/enums/alignment.dart'; export 'laminate/overlay/module.dart'; @@ -194,7 +190,6 @@ export 'material_yes_no_buttons/material_yes_no_buttons.dart'; export 'mixins/button_wrapper.dart'; export 'mixins/focusable_mixin.dart'; export 'mixins/has_tab_index.dart'; -export 'mixins/highlight_assistant_mixin.dart'; export 'mixins/material_dropdown_base.dart'; export 'mixins/track_layout_changes.dart'; export 'model/date/date.dart'; @@ -240,8 +235,6 @@ const List materialDirectives = [ FocusableDirective, FocusTrapComponent, GlyphComponent, - HighlightedTextComponent, - HighlightedValueComponent, KeyboardOnlyFocusIndicatorDirective, LowerBoundValidator, MaterialAutoSuggestInputComponent, diff --git a/ngcomponents/lib/highlighted_text/highlighted_text.dart b/ngcomponents/lib/highlighted_text/highlighted_text.dart deleted file mode 100644 index 574fa96b..00000000 --- a/ngcomponents/lib/highlighted_text/highlighted_text.dart +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:ngdart/angular.dart'; -import 'package:ngcomponents/model/ui/highlighted_text_model.dart'; - -/// A component that presents a list of [HighlightedTextSegment]s. -/// -/// Example parent component: -/// -/// var highlighter = new TextHighlighter(); -/// var segments = highlighter.highlight(text, ['search', 'tokens']); -/// -/// And template: -/// -/// -/// -/// Use [HighlightedValueComponent] for highlighting a value instead of -/// providing segments as required by this component. -@Component( - selector: 'highlighted-text', - templateUrl: 'highlighted_text.html', - styleUrls: ['highlighted_text.scss.css'], - directives: [NgFor], - changeDetection: ChangeDetectionStrategy.onPush, -) -class HighlightedTextComponent { - /// List of [HighlightedTextSegment]s to present. - @Input() - List? segments; -} diff --git a/ngcomponents/lib/highlighted_text/highlighted_text.html b/ngcomponents/lib/highlighted_text/highlighted_text.html deleted file mode 100644 index 8cfa1759..00000000 --- a/ngcomponents/lib/highlighted_text/highlighted_text.html +++ /dev/null @@ -1,8 +0,0 @@ - -{{segment.text}} diff --git a/ngcomponents/lib/highlighted_text/highlighted_text.scss b/ngcomponents/lib/highlighted_text/highlighted_text.scss deleted file mode 100644 index 519d80e9..00000000 --- a/ngcomponents/lib/highlighted_text/highlighted_text.scss +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@import 'package:ngcomponents/css/material/material'; - -.segment-highlight { - font-weight: $mat-font-weight-bold; -} diff --git a/ngcomponents/lib/highlighted_text/highlighted_value.dart b/ngcomponents/lib/highlighted_text/highlighted_value.dart deleted file mode 100644 index d22cf017..00000000 --- a/ngcomponents/lib/highlighted_text/highlighted_value.dart +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:ngdart/angular.dart'; -import 'package:ngcomponents/highlighted_text/highlighted_text.dart'; -import 'package:ngcomponents/model/ui/has_renderer.dart'; -import 'package:ngcomponents/model/ui/highlight_provider.dart'; -import 'package:ngcomponents/model/ui/highlighted_text_model.dart'; - -/// An alternate api to [HighlightedTextComponent] that uses a highlighter -/// and accepts a value that it converts to text segments using a -/// [HighlightProvider]. -@Component( - selector: 'highlight-value', - templateUrl: 'highlighted_text.html', - styleUrls: ['highlighted_text.scss.css'], - directives: [NgFor], -) -class HighlightedValueComponent implements RendersValue { - final HighlightProvider _highLighter; - - /// Value to pass to the highlighter to calculate text segments. - @override - @Input() - Object? value; - - HighlightedValueComponent(this._highLighter); - - /// List of [HighlightedTextSegment]s to present. - List get segments { - /// Highlighter is caching the data so this is fine otherwise this object - /// would need to know when it needs to requery if the highlighting changed. - return _highLighter.highlightOption(value); - } -} diff --git a/ngcomponents/lib/material_input/base_material_input.dart b/ngcomponents/lib/material_input/base_material_input.dart index dfa4020f..a453f964 100644 --- a/ngcomponents/lib/material_input/base_material_input.dart +++ b/ngcomponents/lib/material_input/base_material_input.dart @@ -156,7 +156,7 @@ class BaseMaterialInput extends FocusableMixin /// /// Character count always is displayed when the value is non-null. @Input() - int maxCount = 0; + int? maxCount; ValidityCheck _checkValid = (v) => ''; ValidityCheck get checkValid => _checkValid; @@ -268,7 +268,7 @@ class BaseMaterialInput extends FocusableMixin _localValidationMessage = requiredErrorMsg; return {materialInputErrorKey: _localValidationMessage}; } - if (inputTextLength > maxCount) { + if (maxCount != null && inputTextLength > maxCount!) { _localValidationMessage = _errorMsg; return {materialInputErrorKey: _localValidationMessage}; } diff --git a/ngcomponents/lib/material_input/material_auto_suggest_input.dart b/ngcomponents/lib/material_input/material_auto_suggest_input.dart index e20b819f..1c527e2a 100644 --- a/ngcomponents/lib/material_input/material_auto_suggest_input.dart +++ b/ngcomponents/lib/material_input/material_auto_suggest_input.dart @@ -24,7 +24,6 @@ import 'package:ngcomponents/material_select/material_select_base.dart'; import 'package:ngcomponents/material_select/material_select_dropdown_item.dart'; import 'package:ngcomponents/material_spinner/material_spinner.dart'; import 'package:ngcomponents/material_tooltip/material_tooltip.dart'; -import 'package:ngcomponents/mixins/highlight_assistant_mixin.dart'; import 'package:ngcomponents/mixins/material_dropdown_base.dart'; import 'package:ngcomponents/mixins/selection_input_adapter.dart'; import 'package:ngcomponents/model/a11y/active_item.dart'; @@ -36,7 +35,6 @@ import 'package:ngcomponents/model/selection/selection_model.dart'; import 'package:ngcomponents/model/selection/selection_options.dart'; import 'package:ngcomponents/model/selection/string_selection_options.dart'; import 'package:ngcomponents/model/ui/has_factory.dart'; -import 'package:ngcomponents/model/ui/highlight_provider.dart'; import 'package:ngcomponents/model/ui/template_support.dart'; import 'package:ngcomponents/stop_propagation/stop_propagation.dart'; import 'package:ngcomponents/utils/angular/properties/properties.dart'; @@ -58,7 +56,6 @@ typedef InputChangeCallback = dynamic Function(Object inputText, ExistingProvider(HasDisabled, MaterialAutoSuggestInputComponent), ExistingProvider(HasRenderer, MaterialAutoSuggestInputComponent), ExistingProvider(SelectionContainer, MaterialAutoSuggestInputComponent), - ExistingProvider(HighlightProvider, MaterialAutoSuggestInputComponent), ExistingProvider(DropdownHandle, MaterialAutoSuggestInputComponent), //ExistingProvider(HasComponentRenderer, MaterialAutoSuggestInputComponent), ExistingProvider(HasFactoryRenderer, MaterialAutoSuggestInputComponent), @@ -100,8 +97,7 @@ class MaterialAutoSuggestInputComponent extends MaterialSelectBase with SelectionInputAdapter, MaterialInputWrapper, - KeyboardHandlerMixin, - HighlightAssistantMixin + KeyboardHandlerMixin implements AfterChanges, ControlValueAccessor, @@ -109,7 +105,6 @@ class MaterialAutoSuggestInputComponent extends MaterialSelectBase OnInit, OnDestroy, HasRenderer, - //HasComponentRenderer, HasFactoryRenderer, DropdownHandle, PopupSizeProvider { @@ -508,25 +503,6 @@ class MaterialAutoSuggestInputComponent extends MaterialSelectBase /// Whether an option is hidden. bool isOptionHidden(T item) => Selectable.isHiddenIn(options, item, false); - /// Whether to highlight options. - /// Default value is `true`. - @Input() - bool highlightOptions = true; - - //@override - //ComponentRenderer? get componentRenderer => highlightOptions && - // super.componentRenderer == null && - // super.factoryRenderer == null - // ? highlightComponentRenderer - // : super.componentRenderer; - - @override - FactoryRenderer? get factoryRenderer => - highlightOptions && super.factoryRenderer == null - // && super.componentRenderer == null - ? highlightFactoryRenderer - : super.factoryRenderer; - final _showPopupController = StreamController.broadcast(sync: true); /// Publishes event when the showPopup changes. diff --git a/ngcomponents/lib/material_menu/menu_item_groups.dart b/ngcomponents/lib/material_menu/menu_item_groups.dart index c0978de3..e99598b0 100644 --- a/ngcomponents/lib/material_menu/menu_item_groups.dart +++ b/ngcomponents/lib/material_menu/menu_item_groups.dart @@ -11,7 +11,6 @@ import 'package:ngcomponents/content/deferred_content.dart'; import 'package:ngcomponents/focus/focus.dart'; import 'package:ngcomponents/focus/focus_activable_item.dart'; import 'package:ngcomponents/focus/focus_trap.dart'; -import 'package:ngcomponents/highlighted_text/highlighted_text.dart'; import 'package:ngcomponents/laminate/enums/alignment.dart'; import 'package:ngcomponents/material_icon/material_icon.dart'; import 'package:ngcomponents/material_list/material_list.dart'; @@ -29,7 +28,6 @@ import 'package:ngcomponents/model/menu/menu.dart'; import 'package:ngcomponents/model/menu/selectable_menu.dart'; import 'package:ngcomponents/model/selection/select.dart'; import 'package:ngcomponents/model/selection/selection_model.dart'; -import 'package:ngcomponents/model/ui/highlighted_text_model.dart'; import 'package:ngcomponents/utils/disposer/disposer.dart'; import 'package:ngcomponents/utils/id_generator/id_generator.dart'; import 'package:quiver/core.dart' as qc show Optional; @@ -45,7 +43,6 @@ import 'package:quiver/core.dart' as qc show Optional; FocusActivableItemDirective, FocusableDirective, FocusTrapComponent, - HighlightedTextComponent, MaterialIconComponent, MaterialListComponent, MaterialMenuComponent, @@ -54,7 +51,6 @@ import 'package:quiver/core.dart' as qc show Optional; MenuItemGroupsComponent, MaterialTooltipDirective, MaterialSelectItemComponent, - HighlightedTextComponent, NgClass, NgFor, NgIf, @@ -190,19 +186,6 @@ class MenuItemGroupsComponent Stream get selected => _selected.stream; final _selected = StreamController.broadcast(); - /// Highlighter to use, need to be to be provided if [highlight] is used. - @Input() - TextHighlighter? highlighter; - - /// Part of the string to highlight. - @Input() - set highlight(String value) { - _highlight = value; - _highlightCache = {}; - } - - String _highlight = ''; - /// CSS classes to append onto the sub-menu popups. /// /// These CSS classes will be copied into the sub-menu popup overlays. @@ -212,10 +195,6 @@ class MenuItemGroupsComponent @Input() String popupClass = ''; - bool get hasHighlight => _highlight.isNotEmpty; - - var _highlightCache = >{}; - factory MenuItemGroupsComponent( MenuRoot menuRoot, ChangeDetectorRef changeDetector, @@ -230,16 +209,6 @@ class MenuItemGroupsComponent this._subMenuOpener = DelayedAction(_menuDelay, _openSubMenuOnHover); } - /// Returns list of highlighted segments for a given input, using provided - /// highlighter. - List highlighted(String input) { - if (_highlightCache.containsKey(input)) { - return _highlightCache[input] ?? []; - } - return _highlightCache[input] = - highlighter?.highlight(input, [_highlight]) ?? []; - } - @HostListener('mouseover') void onMouseOver(MouseEvent event) { // If not triggered by mouse movement, don't handle it. This can happen when diff --git a/ngcomponents/lib/material_menu/menu_item_groups.html b/ngcomponents/lib/material_menu/menu_item_groups.html index 10853934..7fbcf257 100644 --- a/ngcomponents/lib/material_menu/menu_item_groups.html +++ b/ngcomponents/lib/material_menu/menu_item_groups.html @@ -68,15 +68,7 @@ [icon]="item.icon"> - - - - - {{item.labelAnnotation}} - - - + {{item.uiDisplayName}} diff --git a/ngcomponents/lib/mixins/highlight_assistant_mixin.dart b/ngcomponents/lib/mixins/highlight_assistant_mixin.dart deleted file mode 100644 index c8508558..00000000 --- a/ngcomponents/lib/mixins/highlight_assistant_mixin.dart +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:ngdart/angular.dart'; -import 'package:ngcomponents/highlighted_text/highlighted_value.dart'; -import 'package:ngcomponents/highlighted_text/highlighted_value.template.dart' - as highlight; -import 'package:ngcomponents/model/selection/select.dart'; -import 'package:ngcomponents/model/selection/selection_container.dart'; -import 'package:ngcomponents/model/ui/has_factory.dart'; -import 'package:ngcomponents/model/ui/highlight_assistant.dart'; -import 'package:ngcomponents/model/ui/highlight_provider.dart'; -import 'package:ngcomponents/model/ui/highlighted_text_model.dart'; - -/// Assistant to support highlighting in a SelectionContainer. -abstract class HighlightAssistantMixin - implements SelectionContainer, HighlightProvider { - @Deprecated('Use highlightFactoryRenderer instead as it allows tree-shaking.') - final ComponentRenderer highlightComponentRenderer = - (_) => HighlightedValueComponent; - final FactoryRenderer highlightFactoryRenderer = - (_) => null; //highlight.HighlightedValueComponentNgFactory; - - HighlightAssistant? _highlightAssistant; - - Highlighter? _optionHighlighter; - Highlighter? get optionHighlighter => _optionHighlighter; - - /// Function which returns a list of [HighlightedTextSegment] for the given - /// query and value. - /// - /// If no `optionHighlighter` is provided, a `TextHighlighter` is used in - /// conjunction with the `itemRenderer` to produce the list of text segments. - @Input() - set optionHighlighter(Highlighter? value) { - _optionHighlighter = value; - _highlightAssistant = null; - } - - bool _highlightMatchFromStartOfWord = false; - - /// Whether matches should only highlight at the start of words. - @Input() - set highlightMatchFromStartOfWord(bool value) { - _highlightMatchFromStartOfWord = value; - _highlightAssistant = null; - } - - /// The query to highlight. - String get highlightQuery => options is Filterable - ? (options as Filterable).currentQuery as String? ?? '' - : ''; - - ItemRenderer? get highlightRenderer { - //if ((componentRenderer == null || - // componentRenderer == highlightComponentRenderer) && - if (factoryRenderer == null || - factoryRenderer == highlightFactoryRenderer) { - if (factoryRenderer == null || - factoryRenderer == highlightFactoryRenderer) { - return itemRenderer ?? defaultItemRenderer; - } - return defaultItemRenderer; - } - return null; - } - - @override - List highlightOption(Object? item) { - _highlightAssistant ??= HighlightAssistant( - optionHighlighter: optionHighlighter, - matchFromStartOfWord: _highlightMatchFromStartOfWord); - - return _highlightAssistant?.highlightOption( - highlightQuery, item, highlightRenderer) ?? - []; - } -} diff --git a/ngcomponents/lib/model/selection/selection_container.dart b/ngcomponents/lib/model/selection/selection_container.dart index 70788c87..4be44099 100644 --- a/ngcomponents/lib/model/selection/selection_container.dart +++ b/ngcomponents/lib/model/selection/selection_container.dart @@ -11,7 +11,6 @@ import 'package:ngcomponents/model/ui/has_factory.dart'; abstract class SelectionContainer implements HasRenderer, - //HasComponentRenderer, HasFactoryRenderer { /// The selection model this container represents. SelectionModel selection = SelectionModel.empty(); @@ -24,13 +23,6 @@ abstract class SelectionContainer @override ItemRenderer? itemRenderer; - /// Specifies the componentRenderer to use to determine the component for - /// rendering an item. - //@override - //@Deprecated( - // 'Use factoryRenderer instead it provides more tree-shakeable code') - //ComponentRenderer? componentRenderer; - /// Specifies the factoryRenderer to use to determine the factory for /// rendering an item. @override diff --git a/ngcomponents/lib/model/selection/string_selection_options.dart b/ngcomponents/lib/model/selection/string_selection_options.dart index 649885ec..a82abfb4 100644 --- a/ngcomponents/lib/model/selection/string_selection_options.dart +++ b/ngcomponents/lib/model/selection/string_selection_options.dart @@ -41,7 +41,7 @@ class StringSelectionOptions extends SelectionOptions static const int UNLIMITED = 9007199254740992; /// The last query passed to [filter]. - String _currentQuery = ''; + String? _currentQuery; /// The current limit for the filter being applied. int _currentLimit = -1; @@ -126,7 +126,7 @@ class StringSelectionOptions extends SelectionOptions void refilter() { List> filtered = []; int count = 0; - String? filterQuery = _sanitizeString(_currentQuery); + String? filterQuery = _sanitizeString(_currentQuery ?? ''); for (var group in _optionGroups) { if (count >= currentLimit!) break; var filteredGroup = diff --git a/ngcomponents/lib/model/ui/has_renderer.dart b/ngcomponents/lib/model/ui/has_renderer.dart index da376bb6..c8b49986 100644 --- a/ngcomponents/lib/model/ui/has_renderer.dart +++ b/ngcomponents/lib/model/ui/has_renderer.dart @@ -44,18 +44,6 @@ abstract class RendersValue { set value(T newValue); } -/// Defines a method that returns a component to render the Item. The -/// component must implement RendersValue. -@Deprecated('Use FactoryRenderer instead as it allows for treeshaking') -typedef ComponentRenderer = Type Function(I? item); - -/// HasComponentRenderer defines a method that takes in an item and returns the -/// type to use to render the item. -@Deprecated('Use HasFactoryRenderer instead as it allows for treeshaking') -abstract class HasComponentRenderer { - ComponentRenderer? componentRenderer; -} - String defaultItemRenderer(dynamic value) => '$value'; /// An [ItemRenderer] that indicates that components should not render items. diff --git a/ngcomponents/lib/model/ui/highlight_assistant.dart b/ngcomponents/lib/model/ui/highlight_assistant.dart deleted file mode 100644 index ba0c5641..00000000 --- a/ngcomponents/lib/model/ui/highlight_assistant.dart +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:ngcomponents/model/ui/has_renderer.dart'; -import 'package:ngcomponents/model/ui/highlighted_text_model.dart'; - -/// Maintains a reference to the highlighter and a cache of highlighted data. -class HighlightAssistant { - static final RegExp _separatorRegex = RegExp(r'[,\s]+'); - - // Cache highlight segments. - final _highlightCache = - >>{}; - - final Highlighter? _optionHighlighter; - - // Lazy private highlighter getter. - TextHighlighter? __textHighlighter; - - /// Gets the default text highlighter, creating a cached instance if needed. - TextHighlighter get _textHighlighter => __textHighlighter ??= - TextHighlighter(matchFromStartOfWord: _matchFromStartOfWord); - - /// Whether matches should only highlight at the start of words. - bool _matchFromStartOfWord; - - /// Creates new HighlightAssistant, using provided [optionHighlighter] or - /// TextHighlighter if no value is provided. - HighlightAssistant( - {Highlighter? optionHighlighter, bool matchFromStartOfWord = false}) - : _optionHighlighter = optionHighlighter, - _matchFromStartOfWord = matchFromStartOfWord; - - List highlightOption( - String lastQuery, dynamic item, ItemRenderer? itemRenderer) { - var queryHighlightCache = _highlightCache[lastQuery] ??= {}; - var value = queryHighlightCache[item]; - - if (value == null) { - String render = ''; - if (itemRenderer != null) { - render = itemRenderer(item) ?? ''; - } - value = (_optionHighlighter != null - ? _optionHighlighter!(lastQuery, item) - : _textHighlighter.highlight( - render, lastQuery.split(_separatorRegex))); - queryHighlightCache[item] = value; - } - return value; - } -} diff --git a/ngcomponents/lib/model/ui/highlight_provider.dart b/ngcomponents/lib/model/ui/highlight_provider.dart deleted file mode 100644 index 213de172..00000000 --- a/ngcomponents/lib/model/ui/highlight_provider.dart +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:ngcomponents/model/ui/highlighted_text_model.dart'; - -abstract class HighlightProvider { - List highlightOption(Object? value); -} diff --git a/ngcomponents/lib/model/ui/highlighted_text_model.dart b/ngcomponents/lib/model/ui/highlighted_text_model.dart deleted file mode 100644 index 67453df3..00000000 --- a/ngcomponents/lib/model/ui/highlighted_text_model.dart +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:math' show max; - -import 'package:meta/meta.dart'; -import 'package:quiver/core.dart' show hash2; - -/// Produces a list of [HighlightedTextSegment] instances for the given [query] -/// and [value]. -typedef Highlighter = List Function( - String query, T? value); - -/// Represents a sub-sequence of a search suggestion, highlighted based on -/// whether it matches the query string. -class HighlightedTextSegment { - final bool isHighlighted; - final String text; - - HighlightedTextSegment(this.text, this.isHighlighted); - - @override - bool operator ==(other) => - other is HighlightedTextSegment && - isHighlighted == other.isHighlighted && - text == other.text; - - @override - int get hashCode => hash2(isHighlighted, text); - - @override - String toString() => isHighlighted ? "*$text*" : text; -} - -/// A class to highlight the occurrences of a list of tokens within a string. -/// By default, matches are only highlighted at the start of words, -/// and matching is case-insensitive. -class TextHighlighter { - final bool caseSensitive; - final bool matchFromStartOfWord; - - const TextHighlighter( - {this.caseSensitive = false, this.matchFromStartOfWord = true}); - - List highlight(String text, List tokens) => - _applyMarkers(text, getMarkers(text, tokens)); - - /// Mark the start of each occurrence of each token with a number equal to - /// the length of the token. - /// - /// This can be thought of as the amount of "ink" that the highlighter should - /// have when starting from this point. - /// - /// e.g. For the text `"abc def"` with [tokens] `["ab", "de"]` - /// the marker array will be `[2,0,0,0,2,0,0]`, and the highlighted - /// segments of the string will be computed as `[*ab*,c ,*de*,f]` - /// - /// Subclasses of [TextHighlighter] can override this method to provide custom - /// text highlighting behavior. - @protected - List getMarkers(String text, List tokens) { - var matchText = caseSensitive ? text : text.toLowerCase(); - List markers = List.filled(matchText.length, 0); - - for (String? token in tokens) { - // Prevents an infinite loop, since there are "infinite" occurrences of - // the empty string. - if (token!.isEmpty) continue; - if (!caseSensitive) { - token = token.toLowerCase(); - } - int index = 0; - while (true) { - index = matchText.indexOf(token, index); - if (index == -1) { - break; - } else { - String? wrapperToken = index != 0 ? matchText[index - 1] : null; - if (!matchFromStartOfWord || - (index == 0 || - // Some suggestions will have an alternate label appended to - // the end of the suggestion and enclosed in parenthesis or - // square brackets. We want to highlight matches to words that - // are wrapped in square brackets and parenthesis so we add - // this check here. - wrapperToken == "(" || - wrapperToken == " " || - wrapperToken == "[")) { - markers[index] = max(markers[index], token.length); - } - index += token.length; - } - } - } - return markers; - } - - /// Returns the highlighted list of segments based on the "ink" markers - /// computed previously. - List _applyMarkers(String text, List markers) { - var segments = []; - var currentSegment = StringBuffer(); - - void commitSegment({required bool highlight}) { - if (currentSegment.isEmpty) return; - segments - .add(HighlightedTextSegment(currentSegment.toString(), highlight)); - currentSegment.clear(); - } - - var ink = 0, inkPrevious = 0, i = 0, caseOffset = 0; - - while (i < text.length) { - // "Apply" the ink to the current letter. - ink = max(0, inkPrevious - 1); - if (ink == 0 && inkPrevious > 0) { - // Ran out of ink, commit the previous segment. - commitSegment(highlight: true); - } - - // Gather more ink. - if (ink < markers[i + caseOffset]) { - ink = markers[i + caseOffset]; - if (i > 0) { - // Commit the previous segment. - commitSegment(highlight: inkPrevious > 0); - } - } - - currentSegment.writeCharCode(text.codeUnitAt(i)); - - // Handle the special case of some capital letters being mapped to - // lowercase letters consisting of multiple code units, e.g. 'İ' maps to - // "\u{69}\u{307}" - var lowercaseChar = text[i].toLowerCase(); - if (!caseSensitive && - text[i] != lowercaseChar && - lowercaseChar.length > text[i].length) { - var lengthDiff = lowercaseChar.length - text[i].length; - // Offset the marker index so that on the next iteration, it points to - // the correct index in the original string. e.g. for the string - // "İabc" (length 4), the lowercase version is "i.abc" (length 5). On - // the next iteration the original text index `i` of "a" is 1, but the - // marker index `i + caseOffset` is now 2. - caseOffset += lengthDiff; - // Reduce the amount of ink, since the marker computation applied - // too much ink to the capital letter at this index, as it was - // accounting for the lowercase letter which has greater length. - ink -= lengthDiff; - } - - inkPrevious = ink; - i++; - } - commitSegment(highlight: inkPrevious > 0); - - return segments; - } -}