Move SearchHighlightDirective to AutocompleterModule in order to use it in the project autocompleter. The highlightDirective needed to be extended so that it can highlight dynamically and not only once at the first trigger.

pull/10674/head
Henriette Darge 2 years ago
parent 6d3df992f3
commit 4f864d59a6
  1. 4
      frontend/src/app/shared/components/autocompleter/op-autocompleter/op-autocompleter.component.html
  2. 7
      frontend/src/app/shared/components/autocompleter/openproject-autocompleter.module.ts
  3. 10
      frontend/src/app/shared/components/autocompleter/project-autocompleter/project-autocompleter.component.html
  4. 8
      frontend/src/app/shared/components/autocompleter/project-autocompleter/project-autocompleter.component.ts
  5. 17
      frontend/src/app/shared/directives/search-highlight.directive.ts
  6. 5
      frontend/src/app/shared/shared.module.ts

@ -98,7 +98,7 @@
let-search="searchTerm"
>
<ng-container
[ngTemplateOutlet]="optionTemplate ? optionTemplate : defaultOption"
[ngTemplateOutlet]="optionTemplate || defaultOption"
[ngTemplateOutletContext]="{$implicit:item, search:search, index:index }"
></ng-container>
</ng-template>
@ -145,7 +145,7 @@
<div class="op-autocompleter--wp-content">
<span
[ngOptionHighlight]="search"
[textContent]="item.project?.name"
[textContent]="item.project?.name"
class="op-autocompleter--wp-project"
></span>

@ -1,6 +1,9 @@
import { NgModule } from '@angular/core';
import { NgSelectModule } from '@ng-select/ng-select';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import {
FormsModule,
ReactiveFormsModule,
} from '@angular/forms';
import { DynamicModule } from 'ng-dynamic-component';
import { CommonModule } from '@angular/common';
import { DragulaModule } from 'ng2-dragula';
@ -21,6 +24,7 @@ import { OpAutocompleterLabelTemplateDirective } from 'core-app/shared/component
import { OpAutocompleterHeaderTemplateDirective } from 'core-app/shared/components/autocompleter/op-autocompleter/directives/op-autocompleter-header-template.directive';
import { CreateAutocompleterComponent } from 'core-app/shared/components/autocompleter/create-autocompleter/create-autocompleter.component';
import { OpAutocompleterFooterTemplateDirective } from 'core-app/shared/components/autocompleter/autocompleter-footer-template/op-autocompleter-footer-template.directive';
import { OpSearchHighlightDirective } from 'core-app/shared/directives/search-highlight.directive';
export const OPENPROJECT_AUTOCOMPLETE_COMPONENTS = [
CreateAutocompleterComponent,
@ -37,6 +41,7 @@ export const OPENPROJECT_AUTOCOMPLETE_COMPONENTS = [
OpAutocompleterLabelTemplateDirective,
OpAutocompleterHeaderTemplateDirective,
OpAutocompleterFooterTemplateDirective,
OpSearchHighlightDirective,
];
@NgModule({

@ -10,10 +10,10 @@
appendTo="body"
(change)="writeValue($event)"
(change)="writeValue($event)"
>
<ng-template
op-autocompleter-label-tmp
ng-label-tmp
let-item
>
<span class="ng-value-label">{{ item.name }}</span>
@ -22,12 +22,12 @@
<ng-template
op-autocompleter-option-tmp
let-item
let-search="searchTerm"
let-search="search"
>
<div
class="ng-option-label ellipsis"
[ngStyle]="{ 'padding-left.px': item.numberOfAncestors * 20 }"
[ngOptionHighlight]="search"
[opSearchHighlight]="search"
>{{ item.name }}</div>
<div
*ngIf="item.disabledReason"
@ -39,7 +39,7 @@
<input
#hiddenInput
[name]="name"
[name]="name"
type="hidden"
[value]="plainValue"
/>

@ -94,7 +94,7 @@ export class ProjectAutocompleterComponent implements ControlValueAccessor {
@Input() public multiple = false;
@Input() public labelForId:string = '';
@Input() public labelForId = '';
@Input() public apiFilters:ApiV3ListFilter[] = [];
@ -128,7 +128,7 @@ export class ProjectAutocompleterComponent implements ControlValueAccessor {
@Output('valueChange') valueChange = new EventEmitter<IProjectAutocompleterData|IProjectAutocompleterData[]|null>();
@ViewChild('hiddenInput') hiddenInput: ElementRef;
@ViewChild('hiddenInput') hiddenInput:ElementRef;
constructor(
public elementRef:ElementRef,
@ -147,7 +147,7 @@ export class ProjectAutocompleterComponent implements ControlValueAccessor {
return getPaginatedResults<IProject>(
(params) => {
const filters:ApiV3ListFilter[] = [...this.apiFilters];
if (searchTerm.length) {
filters.push(['name_and_identifier', '~', [searchTerm]]);
}
@ -168,7 +168,7 @@ export class ProjectAutocompleterComponent implements ControlValueAccessor {
],
...params,
};
const collectionURL = listParamsString(fullParams) + '&' + url.searchParams.toString();
const collectionURL = `${listParamsString(fullParams)}&${url.searchParams.toString()}`;
url.searchParams.forEach((key) => url.searchParams.delete(key));
return this.http.get<IHALCollection<IProject>>(url.toString() + collectionURL);
},

@ -14,12 +14,13 @@ export class OpSearchHighlightDirective implements AfterViewChecked {
constructor(readonly elementRef:ElementRef) { }
ngAfterViewChecked():void {
let el = this.elementRef.nativeElement as HTMLElement;
el = this.cleanUpOldHighlighting(el);
if (!this.query) {
return;
}
const el = this.elementRef.nativeElement as HTMLElement;
const textNode = Array.from(el.childNodes).find((n:Node) => n.nodeType === n.TEXT_NODE) as Node;
const content = textNode?.textContent || '';
if (!content) {
@ -40,4 +41,16 @@ export class OpSearchHighlightDirective implements AfterViewChecked {
newNode.innerHTML = `${start}<span class="op-search-highlight">${result}</span>${end}`;
el.replaceChild(newNode, textNode);
}
private cleanUpOldHighlighting(el:HTMLElement):HTMLElement {
if (el.children.length > 0) {
const unifiedLabelText = Array.from(el.children, ({ textContent }) => textContent?.trim()).join('');
// eslint-disable-next-line no-param-reassign
el.innerHTML = '';
// eslint-disable-next-line no-param-reassign
el.innerText = unifiedLabelText;
}
return el;
}
}

@ -65,7 +65,6 @@ import {
highlightColSelector,
OpHighlightColDirective,
} from './directives/highlight-col/highlight-col.directive';
import { OpSearchHighlightDirective } from './directives/search-highlight.directive';
import { CopyToClipboardDirective } from './components/copy-to-clipboard/copy-to-clipboard.directive';
import { OpDateTimeComponent } from './components/date/op-date-time.component';
@ -172,8 +171,6 @@ export function bootstrapModule(injector:Injector) {
// Table highlight
OpHighlightColDirective,
OpSearchHighlightDirective,
ResizerComponent,
TablePaginationComponent,
@ -236,8 +233,6 @@ export function bootstrapModule(injector:Injector) {
TablePaginationComponent,
SortHeaderDirective,
OpSearchHighlightDirective,
// Zen mode button
ZenModeButtonComponent,

Loading…
Cancel
Save