blob: e911a66c56c4a67037ab3aed7939437ed62b1236 [file] [log] [blame]
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
Input,
NgZone,
OnChanges,
OnDestroy,
SimpleChanges
} from '@angular/core';
import { NotebookSearchResultItem } from '@zeppelin/interfaces';
import { getKeywordPositions, KeywordPosition } from '@zeppelin/utility/get-keyword-positions';
import { editor, Range } from 'monaco-editor';
import IEditor = editor.IEditor;
import IStandaloneCodeEditor = editor.IStandaloneCodeEditor;
@Component({
selector: 'zeppelin-notebook-search-result-item',
templateUrl: './result-item.component.html',
styleUrls: ['./result-item.component.less'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class NotebookSearchResultItemComponent implements OnChanges, OnDestroy {
@Input() result: NotebookSearchResultItem;
displayName = '';
routerLink = '';
mergedStr: string;
keywords: string[] = [];
highlightPositions: KeywordPosition[] = [];
editor: IStandaloneCodeEditor;
height = 0;
decorations: string[] = [];
editorOption = {
readOnly: true,
fontSize: 12,
renderLineHighlight: 'none',
minimap: { enabled: false },
lineNumbers: 'off',
glyphMargin: false,
scrollBeyondLastLine: false,
contextmenu: false
};
constructor(private ngZone: NgZone, private cdr: ChangeDetectorRef) {}
setDisplayNameAndRouterLink(): void {
const noteId = this.result.id.split('/', 2)[0];
this.displayName = this.result.name ? this.result.name : `Note ${noteId}`;
this.routerLink = `/notebook/${noteId}`;
}
setHighlightKeyword(): void {
let mergedStr = this.result.header ? `${this.result.header}\n\n${this.result.snippet}` : this.result.snippet;
const regexp = /<B>(.+?)<\/B>/g;
const matches = [];
let match = regexp.exec(mergedStr);
while (match !== null) {
if (match[1]) {
matches.push(match[1].toLocaleLowerCase());
}
match = regexp.exec(mergedStr);
}
mergedStr = mergedStr.replace(regexp, '$1');
this.mergedStr = mergedStr;
const keywords = [...new Set(matches)];
this.highlightPositions = getKeywordPositions(keywords, mergedStr);
}
applyHighlight() {
if (this.editor) {
this.decorations = this.editor.deltaDecorations(
this.decorations,
this.highlightPositions.map(highlight => {
const line = highlight.line + 1;
const character = highlight.character + 1;
return {
range: new Range(line, character, line, character + highlight.length),
options: {
className: 'mark',
stickiness: 1
}
};
})
);
this.cdr.markForCheck();
}
}
setLanguage() {
const editorModes = {
scala: /^%(\w*\.)?(spark|flink)/,
python: /^%(\w*\.)?(pyspark|python)/,
html: /^%(\w*\.)?(angular|ng)/,
r: /^%(\w*\.)?(r|sparkr|knitr)/,
sql: /^%(\w*\.)?\wql/,
yaml: /^%(\w*\.)?\wconf/,
markdown: /^%md/,
shell: /^%sh/
};
let mode = 'text';
const model = this.editor.getModel();
const keys = Object.keys(editorModes);
for (let i = 0; i < keys.length; i++) {
if (editorModes[keys[i]].test(this.result.snippet)) {
mode = keys[i];
break;
}
}
editor.setModelLanguage(model, mode);
}
autoAdjustEditorHeight() {
this.ngZone.run(() => {
setTimeout(() => {
if (this.editor) {
this.height =
this.editor.getTopForLineNumber(Number.MAX_SAFE_INTEGER) + this.editor.getConfiguration().lineHeight * 2;
this.editor.layout();
this.cdr.markForCheck();
}
});
});
}
initializedEditor(editorInstance: IEditor) {
this.editor = editorInstance as IStandaloneCodeEditor;
this.editor.setValue(this.mergedStr);
this.setLanguage();
this.autoAdjustEditorHeight();
this.applyHighlight();
}
ngOnChanges(changes: SimpleChanges): void {
if (changes.result) {
this.setDisplayNameAndRouterLink();
this.setHighlightKeyword();
this.autoAdjustEditorHeight();
this.applyHighlight();
}
}
ngOnDestroy(): void {
this.editor.dispose();
}
}