-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(uip-editor):
uip-editor
reworked to use latest version of Code…
…Jar and Prism without producing side-effects
- Loading branch information
Showing
5 changed files
with
75 additions
and
130 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,61 +1,101 @@ | ||
// Prevent Prism from auto-highlighting | ||
window.Prism = window.Prism || {}; | ||
if (typeof Prism.manual === 'undefined') Prism.manual = true; | ||
|
||
import React from 'jsx-dom'; | ||
import Prism from 'prismjs'; | ||
import 'prismjs/plugins/normalize-whitespace/prism-normalize-whitespace'; | ||
|
||
import {CodeJar} from 'codejar'; | ||
|
||
import {debounce} from '@exadel/esl/modules/esl-utils/async/debounce'; | ||
import {bind, decorate, jsonAttr} from '@exadel/esl/modules/esl-utils/decorators'; | ||
import {bind, decorate, memoize, jsonAttr} from '@exadel/esl/modules/esl-utils/decorators'; | ||
|
||
import {UIPPlugin} from '../../core/base/plugin'; | ||
|
||
import {UIPPlugin} from '../../core/registration'; | ||
import {JarEditor} from './jar/jar-editor'; | ||
import {EditorConfig} from './jar/jar-utils'; | ||
export interface UIPEditorConfig { | ||
wrap?: number; | ||
} | ||
|
||
/** | ||
* Editor {@link UIPPlugin} custom element definition | ||
* Uses Codejar code editor to provide an ability to modify UIP state markup | ||
* @extends UIPPlugin | ||
*/ | ||
export class UIPEditor extends UIPPlugin { | ||
public static is = 'uip-editor'; | ||
/** Wrapped {@link https://medv.io/codejar/ Codejar} editor instance */ | ||
protected editor: JarEditor; | ||
/** Editor's {@link EditorConfig} passed through attribute */ | ||
public static override is = 'uip-editor'; | ||
|
||
/** Highlight method declaration */ | ||
public static highlight: (editor: HTMLElement) => void = Prism.highlightElement; | ||
|
||
/** Editor's {@link UIPEditorConfig} passed through attribute */ | ||
@jsonAttr({defaultValue: {wrap: 60}}) | ||
private editorConfig: Partial<EditorConfig>; | ||
private editorConfig: Partial<UIPEditorConfig>; | ||
|
||
/** Wrapped {@link https://medv.io/codejar/ Codejar} editor instance */ | ||
@memoize() | ||
protected get editor(): CodeJar { | ||
return CodeJar(this.$code, UIPEditor.highlight, { tab: '\t' }); | ||
} | ||
|
||
@memoize() | ||
protected get $code(): HTMLElement { | ||
return (<pre class='language-html editor-content'><code/></pre>) as HTMLElement; | ||
} | ||
|
||
protected connectedCallback() { | ||
/** @returns editor's content */ | ||
public get value(): string { | ||
return this.editor.toString(); | ||
} | ||
|
||
/** Preformat and set editor's content */ | ||
public set value(value: string) { | ||
this.editor.updateCode(this.normalizeValue(value)); | ||
} | ||
|
||
protected override connectedCallback() { | ||
super.connectedCallback(); | ||
this.innerHTML = ''; | ||
|
||
// Prefill content | ||
this.appendChild(this.$inner); | ||
this.initEditor(); | ||
this.$inner.classList.add('esl-scrollable-content'); | ||
this.$inner.append(<esl-scrollbar target="::parent"/>); | ||
this.$inner.append(this.$code); | ||
|
||
// Initial update | ||
this._onChange(); | ||
this.editor.onUpdate(this._onChange); | ||
this._onRootStateChange(); | ||
} | ||
|
||
protected disconnectedCallback(): void { | ||
this.editor.removeEventListener(this._onChange); | ||
protected override disconnectedCallback(): void { | ||
this.editor?.destroy(); | ||
memoize.clear(this, 'editor'); | ||
super.disconnectedCallback(); | ||
} | ||
|
||
/** Initialize inner {@link https://medv.io/codejar/ Codejar} editor */ | ||
protected initEditor(): void { | ||
const codeBlock = (<pre class='language-html editor-content'><code/></pre>) as HTMLPreElement; | ||
this.$inner.classList.add('esl-scrollable-content'); | ||
this.$inner.append(<esl-scrollbar target="::parent"></esl-scrollbar> as HTMLElement); | ||
this.$inner.append(codeBlock); | ||
|
||
this.editor = new JarEditor(codeBlock, this.editorConfig); | ||
this.editor.addEventListener('uip:editor-change', this._onChange); | ||
this._onRootStateChange(); | ||
/** Preformat value, calls before setting to editor */ | ||
protected normalizeValue(value: string): string { | ||
const {wrap} = this.editorConfig; | ||
const settings: Record<string, any> = {}; | ||
if (wrap) settings['break-lines'] = wrap; | ||
return Prism.plugins.NormalizeWhitespace.normalize(value, settings); | ||
} | ||
|
||
/** Callback to call on editor's content changes */ | ||
@decorate(debounce, 1000) | ||
protected _onChange() { | ||
this.model!.setHtml(this.editor.getValue(), this); | ||
this.model!.setHtml(this.value, this); | ||
} | ||
|
||
/** Change editor's markup from markup state changes */ | ||
@bind | ||
protected _onRootStateChange(): void { | ||
if (this.model!.lastModifier === this) return; | ||
const markup = this.model!.html; | ||
setTimeout(() => this.editor?.setValue(markup)); | ||
setTimeout(() => { | ||
this.value = markup; | ||
}); | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.