@aeriz/wysiwyg 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +610 -96
- package/angular/README.md +112 -0
- package/angular/aeriz-editor.directive.ts +243 -0
- package/angular/aeriz-wysiwyg.module.ts +14 -0
- package/angular/index.ts +5 -0
- package/dist/adapters/jquery.cjs +1 -0
- package/dist/adapters/jquery.js +91 -0
- package/dist/adapters/react.cjs +1 -0
- package/dist/adapters/react.js +66 -0
- package/dist/adapters/shared.cjs +1 -0
- package/dist/adapters/shared.js +87 -0
- package/dist/adapters/svelte.cjs +1 -0
- package/dist/adapters/svelte.js +29 -0
- package/dist/adapters/vue.cjs +1 -0
- package/dist/adapters/vue.js +110 -0
- package/dist/adapters/vue2.cjs +1 -0
- package/dist/adapters/vue2.js +117 -0
- package/dist/adapters/wc.cjs +1 -0
- package/dist/adapters/wc.js +207 -0
- package/dist/aeriz-wysiwyg-adapter.js +169 -0
- package/dist/aeriz-wysiwyg-adapter.min.js +1 -0
- package/dist/aeriz-wysiwyg-jquery.js +275 -0
- package/dist/aeriz-wysiwyg-jquery.min.js +1 -0
- package/dist/aeriz-wysiwyg-wc.js +401 -0
- package/dist/aeriz-wysiwyg-wc.min.js +1 -0
- package/dist/aeriz-wysiwyg.cjs +6912 -0
- package/dist/aeriz-wysiwyg.css +37 -129
- package/dist/aeriz-wysiwyg.esm.js +1194 -153
- package/dist/aeriz-wysiwyg.esm.min.js +2067 -1204
- package/dist/aeriz-wysiwyg.js +1193 -152
- package/dist/aeriz-wysiwyg.min.cjs +54 -0
- package/dist/aeriz-wysiwyg.min.css +1 -1
- package/dist/aeriz-wysiwyg.min.js +44 -13
- package/dist/server.cjs +32 -0
- package/dist/server.js +666 -0
- package/dist-types/adapters/jquery.d.ts +34 -0
- package/dist-types/adapters/jquery.d.ts.map +1 -0
- package/dist-types/adapters/react.d.ts +28 -0
- package/dist-types/adapters/react.d.ts.map +1 -0
- package/dist-types/adapters/shared.d.ts +83 -0
- package/dist-types/adapters/shared.d.ts.map +1 -0
- package/dist-types/adapters/svelte.d.ts +38 -0
- package/dist-types/adapters/svelte.d.ts.map +1 -0
- package/dist-types/adapters/vue.d.ts +189 -0
- package/dist-types/adapters/vue.d.ts.map +1 -0
- package/dist-types/adapters/vue2.d.ts +175 -0
- package/dist-types/adapters/vue2.d.ts.map +1 -0
- package/dist-types/adapters/wc.d.ts +96 -0
- package/dist-types/adapters/wc.d.ts.map +1 -0
- package/dist-types/cjs/adapters/jquery.d.cts +34 -0
- package/dist-types/cjs/adapters/react.d.cts +28 -0
- package/dist-types/cjs/adapters/shared.d.cts +83 -0
- package/dist-types/cjs/adapters/svelte.d.cts +38 -0
- package/dist-types/cjs/adapters/vue.d.cts +189 -0
- package/dist-types/cjs/adapters/vue2.d.cts +175 -0
- package/dist-types/cjs/adapters/wc.d.cts +96 -0
- package/dist-types/cjs/core/AerizEditor.d.cts +357 -0
- package/dist-types/cjs/core/AerizViewer.d.cts +61 -0
- package/dist-types/cjs/core/block-meta.d.cts +32 -0
- package/dist-types/cjs/core/blocks.d.cts +368 -0
- package/dist-types/cjs/core/fonts.d.cts +60 -0
- package/dist-types/cjs/core/highlight.d.cts +44 -0
- package/dist-types/cjs/core/html-mini.d.cts +65 -0
- package/dist-types/cjs/core/i18n.d.cts +209 -0
- package/dist-types/cjs/core/import-html.d.cts +39 -0
- package/dist-types/cjs/core/import-markdown.d.cts +37 -0
- package/dist-types/cjs/core/markdown-export.d.cts +30 -0
- package/dist-types/cjs/core/plain-text.d.cts +17 -0
- package/dist-types/cjs/core/render-string.d.cts +68 -0
- package/dist-types/cjs/core/snapshot.d.cts +51 -0
- package/dist-types/cjs/index.d.cts +20 -0
- package/dist-types/cjs/server/index.d.cts +37 -0
- package/dist-types/cjs/types/index.d.cts +61 -0
- package/dist-types/cjs/ui/Toolbar.d.cts +21 -0
- package/dist-types/cjs/ui/dialogs.d.cts +74 -0
- package/dist-types/cjs/ui/icons.d.cts +2 -0
- package/dist-types/cjs/ui/popovers.d.cts +70 -0
- package/dist-types/core/AerizEditor.d.ts +30 -10
- package/dist-types/core/AerizEditor.d.ts.map +1 -1
- package/dist-types/core/AerizViewer.d.ts +16 -4
- package/dist-types/core/AerizViewer.d.ts.map +1 -1
- package/dist-types/core/block-meta.d.ts +32 -0
- package/dist-types/core/block-meta.d.ts.map +1 -0
- package/dist-types/core/blocks.d.ts +62 -7
- package/dist-types/core/blocks.d.ts.map +1 -1
- package/dist-types/core/fonts.d.ts +11 -0
- package/dist-types/core/fonts.d.ts.map +1 -1
- package/dist-types/core/html-mini.d.ts +65 -0
- package/dist-types/core/html-mini.d.ts.map +1 -0
- package/dist-types/core/import-html.d.ts.map +1 -1
- package/dist-types/core/markdown-export.d.ts +30 -0
- package/dist-types/core/markdown-export.d.ts.map +1 -0
- package/dist-types/core/plain-text.d.ts +17 -0
- package/dist-types/core/plain-text.d.ts.map +1 -0
- package/dist-types/core/render-string.d.ts +68 -0
- package/dist-types/core/render-string.d.ts.map +1 -0
- package/dist-types/core/snapshot.d.ts +51 -0
- package/dist-types/core/snapshot.d.ts.map +1 -0
- package/dist-types/index.d.ts +19 -10
- package/dist-types/index.d.ts.map +1 -1
- package/dist-types/server/index.d.ts +37 -0
- package/dist-types/server/index.d.ts.map +1 -0
- package/dist-types/types/index.d.ts +21 -0
- package/dist-types/types/index.d.ts.map +1 -1
- package/dist-types/ui/Toolbar.d.ts +1 -1
- package/dist-types/ui/popovers.d.ts +1 -1
- package/dist-types/ui/popovers.d.ts.map +1 -1
- package/package.json +213 -58
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Angular 연동
|
|
2
|
+
|
|
3
|
+
이 디렉터리는 **TypeScript 소스로 배포**됩니다. 미리 컴파일한 Angular
|
|
4
|
+
라이브러리는 빌드에 쓰인 Angular 버전과 소비자 버전이 맞아야 하는데, 소스로
|
|
5
|
+
두면 소비자의 Angular 컴파일러가 직접 컴파일하므로 Angular 14 이상 어느
|
|
6
|
+
버전에서도 같은 파일이 동작합니다.
|
|
7
|
+
|
|
8
|
+
## 설정 (택 1)
|
|
9
|
+
|
|
10
|
+
### 방법 A — tsconfig 에 경로 추가 (권장)
|
|
11
|
+
|
|
12
|
+
`tsconfig.app.json` 의 `include` 에 한 줄 추가하면 Angular CLI 가 이 소스를
|
|
13
|
+
앱과 함께 컴파일합니다.
|
|
14
|
+
|
|
15
|
+
```jsonc
|
|
16
|
+
{
|
|
17
|
+
"include": [
|
|
18
|
+
"src/**/*.ts",
|
|
19
|
+
"node_modules/@aeriz/wysiwyg/angular/*.ts" // ← 추가
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### 방법 B — 파일 복사
|
|
25
|
+
|
|
26
|
+
`aeriz-editor.directive.ts` 를 앱 소스 안으로 복사합니다. 의존성은
|
|
27
|
+
`@angular/core`, `@angular/forms`, `@aeriz/wysiwyg` 뿐입니다.
|
|
28
|
+
|
|
29
|
+
## 스타일시트
|
|
30
|
+
|
|
31
|
+
`angular.json` 의 `styles` 배열에 추가합니다.
|
|
32
|
+
|
|
33
|
+
```jsonc
|
|
34
|
+
"styles": [
|
|
35
|
+
"node_modules/@aeriz/wysiwyg/dist/aeriz-wysiwyg.min.css",
|
|
36
|
+
"src/styles.css"
|
|
37
|
+
]
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## 사용
|
|
41
|
+
|
|
42
|
+
### standalone 컴포넌트
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import { Component } from '@angular/core';
|
|
46
|
+
import { FormsModule } from '@angular/forms';
|
|
47
|
+
import { AerizEditorDirective } from '@aeriz/wysiwyg/angular';
|
|
48
|
+
|
|
49
|
+
@Component({
|
|
50
|
+
standalone: true,
|
|
51
|
+
imports: [FormsModule, AerizEditorDirective],
|
|
52
|
+
template: `
|
|
53
|
+
<div aerizEditor [(ngModel)]="html" theme="dark" placeholder="내용을 입력하세요"></div>
|
|
54
|
+
<pre>{{ html }}</pre>
|
|
55
|
+
`,
|
|
56
|
+
})
|
|
57
|
+
export class ComposeComponent {
|
|
58
|
+
html = '<p>안녕하세요</p>';
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### NgModule 앱
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { AerizWysiwygModule } from '@aeriz/wysiwyg/angular';
|
|
66
|
+
|
|
67
|
+
@NgModule({
|
|
68
|
+
imports: [BrowserModule, FormsModule, AerizWysiwygModule],
|
|
69
|
+
})
|
|
70
|
+
export class AppModule {}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## 바인딩 방식
|
|
74
|
+
|
|
75
|
+
| 방식 | 템플릿 |
|
|
76
|
+
| --- | --- |
|
|
77
|
+
| 단방향 | `<div aerizEditor [value]="html" (valueChange)="html = $event"></div>` |
|
|
78
|
+
| 양방향 | `<div aerizEditor [(value)]="html"></div>` |
|
|
79
|
+
| ngModel | `<div aerizEditor [(ngModel)]="html"></div>` |
|
|
80
|
+
| Reactive Forms | `<div aerizEditor formControlName="body"></div>` |
|
|
81
|
+
|
|
82
|
+
## 입력 / 출력
|
|
83
|
+
|
|
84
|
+
| 이름 | 타입 | 설명 |
|
|
85
|
+
| --- | --- | --- |
|
|
86
|
+
| `value` | `string` | 본문 HTML |
|
|
87
|
+
| `placeholder` | `string` | 빈 본문 안내 문구 |
|
|
88
|
+
| `toolbar` | `ToolbarConfig \| false` | 툴바 구성. `false` 면 숨김 |
|
|
89
|
+
| `theme` | `'light' \| 'dark'` | 테마 |
|
|
90
|
+
| `locale` | `'en' \| 'ko' \| 'ja' \| 'zh'` | UI 언어 |
|
|
91
|
+
| `imageUploadUrl` | `string` | 이미지 업로드 API URL |
|
|
92
|
+
| `fileUploadUrl` | `string` | 파일 업로드 API URL |
|
|
93
|
+
| `imageUpload` | `(file: File) => Promise<string>` | 직접 업로드 핸들러 |
|
|
94
|
+
| `fileUpload` | `(file: File) => Promise<string>` | 직접 업로드 핸들러 |
|
|
95
|
+
| `(valueChange)` | `string` | 본문 변경 |
|
|
96
|
+
| `(stateChange)` | `EditorState` | 블록/선택 상태 변경 |
|
|
97
|
+
| `(ready)` | `AerizEditor` | 인스턴스 생성 완료 |
|
|
98
|
+
|
|
99
|
+
## 성능 메모
|
|
100
|
+
|
|
101
|
+
디렉티브는 에디터 인스턴스를 `NgZone` **밖에서** 생성합니다. 에디터는
|
|
102
|
+
`selectionchange` 등 고빈도 이벤트를 구독하므로, zone 안에서 만들면 캐럿을
|
|
103
|
+
움직일 때마다 변경 감지가 돌게 됩니다. 값이 실제로 바뀔 때만 zone 으로
|
|
104
|
+
복귀해 한 번 감지를 돌립니다.
|
|
105
|
+
|
|
106
|
+
## 뷰어
|
|
107
|
+
|
|
108
|
+
```html
|
|
109
|
+
<div aerizViewer [blocks]="blocks" theme="light"></div>
|
|
110
|
+
<!-- 블록 대신 HTML 문자열도 가능 -->
|
|
111
|
+
<div aerizViewer [html]="savedHtml"></div>
|
|
112
|
+
```
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Angular 디렉티브 — `[aerizEditor]` / `[aerizViewer]`.
|
|
3
|
+
*
|
|
4
|
+
* 이 파일은 **소스 배포**다. Angular 라이브러리는 소비자의 Angular 버전에 맞춰
|
|
5
|
+
* Ivy 로 컴파일돼야 하고, 미리 빌드한 산출물은 버전 창이 좁아진다. 소스로
|
|
6
|
+
* 두면 소비자의 Angular 컴파일러가 직접 컴파일하므로 Angular 14 ~ 최신까지
|
|
7
|
+
* 같은 파일 하나로 동작한다. 설정 방법은 `angular/README.md` 참고.
|
|
8
|
+
*
|
|
9
|
+
* `@angular/core` / `@angular/forms` 는 소비자 앱의 것을 그대로 쓴다.
|
|
10
|
+
*/
|
|
11
|
+
import {
|
|
12
|
+
Directive,
|
|
13
|
+
ElementRef,
|
|
14
|
+
EventEmitter,
|
|
15
|
+
Input,
|
|
16
|
+
NgZone,
|
|
17
|
+
OnChanges,
|
|
18
|
+
OnDestroy,
|
|
19
|
+
OnInit,
|
|
20
|
+
Output,
|
|
21
|
+
forwardRef,
|
|
22
|
+
} from '@angular/core';
|
|
23
|
+
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
24
|
+
import type { ControlValueAccessor } from '@angular/forms';
|
|
25
|
+
import { createEditorController, createViewerController } from '@aeriz/wysiwyg/adapter';
|
|
26
|
+
import type {
|
|
27
|
+
AerizEditorController,
|
|
28
|
+
AerizEditorProps,
|
|
29
|
+
AerizViewerController,
|
|
30
|
+
AerizViewerProps,
|
|
31
|
+
} from '@aeriz/wysiwyg/adapter';
|
|
32
|
+
import type {
|
|
33
|
+
AerizEditor,
|
|
34
|
+
AerizViewer,
|
|
35
|
+
BlockSnapshot,
|
|
36
|
+
EditorState,
|
|
37
|
+
ToolbarConfig,
|
|
38
|
+
} from '@aeriz/wysiwyg';
|
|
39
|
+
|
|
40
|
+
type Theme = 'light' | 'dark';
|
|
41
|
+
type Locale = 'en' | 'ko' | 'ja' | 'zh';
|
|
42
|
+
type HtmlStyles = 'inline' | 'class';
|
|
43
|
+
type UploadFn = (file: File) => Promise<string>;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 에디터 디렉티브.
|
|
47
|
+
*
|
|
48
|
+
* 세 가지 바인딩 방식을 모두 지원한다.
|
|
49
|
+
* - 단방향: `<div aerizEditor [value]="html" (valueChange)="html = $event">`
|
|
50
|
+
* - 양방향: `<div aerizEditor [(value)]="html">`
|
|
51
|
+
* - 폼: `<div aerizEditor [(ngModel)]="html">` / `formControlName="body"`
|
|
52
|
+
*
|
|
53
|
+
* 에디터 내부 리스너(selectionchange 등) 는 매우 자주 발화하므로 인스턴스를
|
|
54
|
+
* Angular zone **밖에서** 만든다. 값이 실제로 바뀔 때만 zone 안으로 돌아와
|
|
55
|
+
* 변경 감지를 한 번 돌린다.
|
|
56
|
+
*/
|
|
57
|
+
@Directive({
|
|
58
|
+
selector: '[aerizEditor]',
|
|
59
|
+
standalone: true,
|
|
60
|
+
providers: [
|
|
61
|
+
{
|
|
62
|
+
provide: NG_VALUE_ACCESSOR,
|
|
63
|
+
useExisting: forwardRef(() => AerizEditorDirective),
|
|
64
|
+
multi: true,
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
})
|
|
68
|
+
export class AerizEditorDirective
|
|
69
|
+
implements OnInit, OnChanges, OnDestroy, ControlValueAccessor
|
|
70
|
+
{
|
|
71
|
+
/** 본문 HTML. `[(value)]` 로 양방향 바인딩할 수 있다. */
|
|
72
|
+
@Input() value?: string;
|
|
73
|
+
@Input() placeholder?: string;
|
|
74
|
+
@Input() toolbar?: ToolbarConfig | false;
|
|
75
|
+
@Input() theme?: Theme;
|
|
76
|
+
@Input() locale?: Locale;
|
|
77
|
+
/** `getHTML()` · `(valueChange)` 출력 전략. 기본 `'inline'`. */
|
|
78
|
+
@Input() htmlStyles?: HtmlStyles;
|
|
79
|
+
@Input() imageUploadUrl?: string;
|
|
80
|
+
@Input() fileUploadUrl?: string;
|
|
81
|
+
/** 직접 업로드 핸들러. 설정 시 `imageUploadUrl` 보다 우선한다. */
|
|
82
|
+
@Input() imageUpload?: UploadFn;
|
|
83
|
+
@Input() fileUpload?: UploadFn;
|
|
84
|
+
|
|
85
|
+
@Output() valueChange = new EventEmitter<string>();
|
|
86
|
+
@Output() stateChange = new EventEmitter<EditorState>();
|
|
87
|
+
@Output() ready = new EventEmitter<AerizEditor>();
|
|
88
|
+
|
|
89
|
+
private controller: AerizEditorController | null = null;
|
|
90
|
+
/** 에디터가 들고 있는 값. ngModel / [value] 양쪽의 단일 출처. */
|
|
91
|
+
private current = '';
|
|
92
|
+
private onChangeFn: (value: string) => void = () => undefined;
|
|
93
|
+
private onTouchedFn: () => void = () => undefined;
|
|
94
|
+
|
|
95
|
+
constructor(
|
|
96
|
+
private readonly host: ElementRef<HTMLElement>,
|
|
97
|
+
private readonly zone: NgZone,
|
|
98
|
+
) {}
|
|
99
|
+
|
|
100
|
+
/** 코어 인스턴스. 명령형 API 접근 경로. */
|
|
101
|
+
get editor(): AerizEditor | null {
|
|
102
|
+
return this.controller?.editor ?? null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
ngOnInit(): void {
|
|
106
|
+
if (this.value !== undefined) this.current = this.value;
|
|
107
|
+
this.zone.runOutsideAngular(() => {
|
|
108
|
+
this.controller = createEditorController(
|
|
109
|
+
this.host.nativeElement,
|
|
110
|
+
this.buildProps(),
|
|
111
|
+
);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
ngOnChanges(): void {
|
|
116
|
+
if (!this.controller) return;
|
|
117
|
+
if (this.value !== undefined) this.current = this.value;
|
|
118
|
+
this.zone.runOutsideAngular(() => {
|
|
119
|
+
this.controller?.update(this.buildProps());
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
ngOnDestroy(): void {
|
|
124
|
+
this.controller?.destroy();
|
|
125
|
+
this.controller = null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ─── ControlValueAccessor ────────────────────────────────────────────
|
|
129
|
+
|
|
130
|
+
writeValue(value: string | null): void {
|
|
131
|
+
this.current = value ?? '';
|
|
132
|
+
this.zone.runOutsideAngular(() => {
|
|
133
|
+
this.controller?.update(this.buildProps());
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
registerOnChange(fn: (value: string) => void): void {
|
|
138
|
+
this.onChangeFn = fn;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
registerOnTouched(fn: () => void): void {
|
|
142
|
+
this.onTouchedFn = fn;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
setDisabledState(isDisabled: boolean): void {
|
|
146
|
+
// 코어에 읽기 전용 모드가 없어 본문 편집 가능 여부만 직접 토글한다.
|
|
147
|
+
const content = this.controller?.editor.content;
|
|
148
|
+
if (content) content.contentEditable = isDisabled ? 'false' : 'true';
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ─── 내부 ────────────────────────────────────────────────────────────
|
|
152
|
+
|
|
153
|
+
private buildProps(): AerizEditorProps {
|
|
154
|
+
const props: AerizEditorProps = {
|
|
155
|
+
value: this.current,
|
|
156
|
+
onChange: (html: string) => {
|
|
157
|
+
this.current = html;
|
|
158
|
+
// 편집이 실제로 값을 바꿨을 때만 zone 으로 복귀한다.
|
|
159
|
+
this.zone.run(() => {
|
|
160
|
+
this.onChangeFn(html);
|
|
161
|
+
this.onTouchedFn();
|
|
162
|
+
this.valueChange.emit(html);
|
|
163
|
+
});
|
|
164
|
+
},
|
|
165
|
+
onStateChange: (state: EditorState) => {
|
|
166
|
+
this.zone.run(() => this.stateChange.emit(state));
|
|
167
|
+
},
|
|
168
|
+
onReady: (editor: AerizEditor) => {
|
|
169
|
+
this.zone.run(() => this.ready.emit(editor));
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
if (this.placeholder !== undefined) props.placeholder = this.placeholder;
|
|
173
|
+
if (this.toolbar !== undefined) props.toolbar = this.toolbar;
|
|
174
|
+
if (this.theme !== undefined) props.theme = this.theme;
|
|
175
|
+
if (this.locale !== undefined) props.locale = this.locale;
|
|
176
|
+
if (this.htmlStyles !== undefined) props.htmlStyles = this.htmlStyles;
|
|
177
|
+
if (this.imageUploadUrl !== undefined) props.imageUploadUrl = this.imageUploadUrl;
|
|
178
|
+
if (this.fileUploadUrl !== undefined) props.fileUploadUrl = this.fileUploadUrl;
|
|
179
|
+
if (this.imageUpload !== undefined) props.onImageUpload = this.imageUpload;
|
|
180
|
+
if (this.fileUpload !== undefined) props.onFileUpload = this.fileUpload;
|
|
181
|
+
return props;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** 읽기 전용 뷰어 디렉티브. `blocks` 가 있으면 `html` 보다 우선한다. */
|
|
186
|
+
@Directive({
|
|
187
|
+
selector: '[aerizViewer]',
|
|
188
|
+
standalone: true,
|
|
189
|
+
})
|
|
190
|
+
export class AerizViewerDirective implements OnInit, OnChanges, OnDestroy {
|
|
191
|
+
@Input() blocks?: BlockSnapshot[];
|
|
192
|
+
@Input() html?: string;
|
|
193
|
+
@Input() theme?: Theme;
|
|
194
|
+
/** `getHTML()` 출력 전략. 기본 `'inline'`. */
|
|
195
|
+
@Input() htmlStyles?: HtmlStyles;
|
|
196
|
+
|
|
197
|
+
@Output() ready = new EventEmitter<AerizViewer>();
|
|
198
|
+
|
|
199
|
+
private controller: AerizViewerController | null = null;
|
|
200
|
+
|
|
201
|
+
constructor(
|
|
202
|
+
private readonly host: ElementRef<HTMLElement>,
|
|
203
|
+
private readonly zone: NgZone,
|
|
204
|
+
) {}
|
|
205
|
+
|
|
206
|
+
get viewer(): AerizViewer | null {
|
|
207
|
+
return this.controller?.viewer ?? null;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
ngOnInit(): void {
|
|
211
|
+
this.zone.runOutsideAngular(() => {
|
|
212
|
+
this.controller = createViewerController(
|
|
213
|
+
this.host.nativeElement,
|
|
214
|
+
this.buildProps(),
|
|
215
|
+
);
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
ngOnChanges(): void {
|
|
220
|
+
if (!this.controller) return;
|
|
221
|
+
this.zone.runOutsideAngular(() => {
|
|
222
|
+
this.controller?.update(this.buildProps());
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
ngOnDestroy(): void {
|
|
227
|
+
this.controller?.destroy();
|
|
228
|
+
this.controller = null;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
private buildProps(): AerizViewerProps {
|
|
232
|
+
const props: AerizViewerProps = {
|
|
233
|
+
onReady: (viewer: AerizViewer) => {
|
|
234
|
+
this.zone.run(() => this.ready.emit(viewer));
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
if (this.blocks !== undefined) props.blocks = this.blocks;
|
|
238
|
+
if (this.html !== undefined) props.html = this.html;
|
|
239
|
+
if (this.theme !== undefined) props.theme = this.theme;
|
|
240
|
+
if (this.htmlStyles !== undefined) props.htmlStyles = this.htmlStyles;
|
|
241
|
+
return props;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import { AerizEditorDirective, AerizViewerDirective } from './aeriz-editor.directive';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* NgModule 방식 앱을 위한 편의 모듈.
|
|
6
|
+
*
|
|
7
|
+
* standalone 컴포넌트를 쓰는 앱은 이 모듈 없이 디렉티브를 `imports` 에 직접
|
|
8
|
+
* 넣으면 된다.
|
|
9
|
+
*/
|
|
10
|
+
@NgModule({
|
|
11
|
+
imports: [AerizEditorDirective, AerizViewerDirective],
|
|
12
|
+
exports: [AerizEditorDirective, AerizViewerDirective],
|
|
13
|
+
})
|
|
14
|
+
export class AerizWysiwygModule {}
|
package/angular/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("./shared.cjs"),f=new WeakMap,d=new WeakMap;function c(t,a,s){const n=t[0],e=n?f.get(n):void 0;switch(a){case"getHTML":return(e==null?void 0:e.editor.getHTML())??"";case"getBlocks":return(e==null?void 0:e.editor.serialize())??[];case"setHTML":return t.each((u,i)=>{var r;(r=f.get(i))==null||r.editor.setHTML(String(s[0]??""))}),t;case"update":return t.each((u,i)=>{var r;(r=f.get(i))==null||r.update(s[0]??{})}),t;case"focus":return e==null||e.editor.focus(),t;case"instance":return(e==null?void 0:e.editor)??null;case"destroy":return t.each((u,i)=>{const r=f.get(i);r&&(r.destroy(),f.delete(i))}),t;default:throw new Error(`aerizEditor: 알 수 없는 명령 "${a}"`)}}function y(t,a,s){const n=t[0],e=n?d.get(n):void 0;switch(a){case"getHTML":return(e==null?void 0:e.viewer.getHTML())??"";case"getBlocks":return(e==null?void 0:e.viewer.getBlocks())??[];case"update":return t.each((u,i)=>{var r;(r=d.get(i))==null||r.update(s[0]??{})}),t;case"instance":return(e==null?void 0:e.viewer)??null;case"destroy":return t.each((u,i)=>{const r=d.get(i);r&&(r.destroy(),d.delete(i))}),t;default:throw new Error(`aerizViewer: 알 수 없는 명령 "${a}"`)}}function p(t,...a){if(typeof t=="string")return c(this,t,a);const s=t??{};return this.each((n,e)=>{const u=f.get(e);if(u){u.update(s);return}f.set(e,h.createEditorController(e,s))}),this}function o(t,...a){if(typeof t=="string")return y(this,t,a);const s=t??{};return this.each((n,e)=>{const u=d.get(e);if(u){u.update(s);return}d.set(e,h.createViewerController(e,s))}),this}function w(t){if(!t||typeof t.fn!="object")throw new TypeError("registerAerizJQuery: jQuery 객체가 필요합니다.");t.fn.aerizEditor||(t.fn.aerizEditor=p),t.fn.aerizViewer||(t.fn.aerizViewer=o)}const g=globalThis.jQuery;g&&w(g);exports.registerAerizJQuery=w;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { createEditorController as w, createViewerController as h } from "./shared.js";
|
|
2
|
+
const f = /* @__PURE__ */ new WeakMap(), d = /* @__PURE__ */ new WeakMap();
|
|
3
|
+
function c(t, n, s) {
|
|
4
|
+
const a = t[0], e = a ? f.get(a) : void 0;
|
|
5
|
+
switch (n) {
|
|
6
|
+
case "getHTML":
|
|
7
|
+
return (e == null ? void 0 : e.editor.getHTML()) ?? "";
|
|
8
|
+
case "getBlocks":
|
|
9
|
+
return (e == null ? void 0 : e.editor.serialize()) ?? [];
|
|
10
|
+
case "setHTML":
|
|
11
|
+
return t.each((u, i) => {
|
|
12
|
+
var r;
|
|
13
|
+
(r = f.get(i)) == null || r.editor.setHTML(String(s[0] ?? ""));
|
|
14
|
+
}), t;
|
|
15
|
+
case "update":
|
|
16
|
+
return t.each((u, i) => {
|
|
17
|
+
var r;
|
|
18
|
+
(r = f.get(i)) == null || r.update(s[0] ?? {});
|
|
19
|
+
}), t;
|
|
20
|
+
case "focus":
|
|
21
|
+
return e == null || e.editor.focus(), t;
|
|
22
|
+
case "instance":
|
|
23
|
+
return (e == null ? void 0 : e.editor) ?? null;
|
|
24
|
+
case "destroy":
|
|
25
|
+
return t.each((u, i) => {
|
|
26
|
+
const r = f.get(i);
|
|
27
|
+
r && (r.destroy(), f.delete(i));
|
|
28
|
+
}), t;
|
|
29
|
+
default:
|
|
30
|
+
throw new Error(`aerizEditor: 알 수 없는 명령 "${n}"`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function y(t, n, s) {
|
|
34
|
+
const a = t[0], e = a ? d.get(a) : void 0;
|
|
35
|
+
switch (n) {
|
|
36
|
+
case "getHTML":
|
|
37
|
+
return (e == null ? void 0 : e.viewer.getHTML()) ?? "";
|
|
38
|
+
case "getBlocks":
|
|
39
|
+
return (e == null ? void 0 : e.viewer.getBlocks()) ?? [];
|
|
40
|
+
case "update":
|
|
41
|
+
return t.each((u, i) => {
|
|
42
|
+
var r;
|
|
43
|
+
(r = d.get(i)) == null || r.update(s[0] ?? {});
|
|
44
|
+
}), t;
|
|
45
|
+
case "instance":
|
|
46
|
+
return (e == null ? void 0 : e.viewer) ?? null;
|
|
47
|
+
case "destroy":
|
|
48
|
+
return t.each((u, i) => {
|
|
49
|
+
const r = d.get(i);
|
|
50
|
+
r && (r.destroy(), d.delete(i));
|
|
51
|
+
}), t;
|
|
52
|
+
default:
|
|
53
|
+
throw new Error(`aerizViewer: 알 수 없는 명령 "${n}"`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function p(t, ...n) {
|
|
57
|
+
if (typeof t == "string")
|
|
58
|
+
return c(this, t, n);
|
|
59
|
+
const s = t ?? {};
|
|
60
|
+
return this.each((a, e) => {
|
|
61
|
+
const u = f.get(e);
|
|
62
|
+
if (u) {
|
|
63
|
+
u.update(s);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
f.set(e, w(e, s));
|
|
67
|
+
}), this;
|
|
68
|
+
}
|
|
69
|
+
function z(t, ...n) {
|
|
70
|
+
if (typeof t == "string")
|
|
71
|
+
return y(this, t, n);
|
|
72
|
+
const s = t ?? {};
|
|
73
|
+
return this.each((a, e) => {
|
|
74
|
+
const u = d.get(e);
|
|
75
|
+
if (u) {
|
|
76
|
+
u.update(s);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
d.set(e, h(e, s));
|
|
80
|
+
}), this;
|
|
81
|
+
}
|
|
82
|
+
function o(t) {
|
|
83
|
+
if (!t || typeof t.fn != "object")
|
|
84
|
+
throw new TypeError("registerAerizJQuery: jQuery 객체가 필요합니다.");
|
|
85
|
+
t.fn.aerizEditor || (t.fn.aerizEditor = p), t.fn.aerizViewer || (t.fn.aerizViewer = z);
|
|
86
|
+
}
|
|
87
|
+
const g = globalThis.jQuery;
|
|
88
|
+
g && o(g);
|
|
89
|
+
export {
|
|
90
|
+
o as registerAerizJQuery
|
|
91
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("react"),l=require("./shared.cjs");function s(r,n){const c=i.useRef(null),t=i.useRef(null),e=i.useRef(n);return e.current=n,i.useEffect(()=>{const o=c.current;if(!o)return;const u=r(o,e.current);return t.current=u,()=>{u.destroy(),t.current=null}},[]),i.useEffect(()=>{var o;(o=t.current)==null||o.update(n)}),{hostRef:c,controllerRef:t}}function f(r){const n={};return r.className!==void 0&&(n.className=r.className),r.style!==void 0&&(n.style=r.style),r.id!==void 0&&(n.id=r.id),n}function m(r,n){const{hostRef:c,controllerRef:t}=s(l.createEditorController,r);return i.useImperativeHandle(n,()=>({get editor(){var e;return((e=t.current)==null?void 0:e.editor)??null},getHTML:()=>{var e;return((e=t.current)==null?void 0:e.editor.getHTML())??""},setHTML:e=>{var o;return(o=t.current)==null?void 0:o.editor.setHTML(e)},focus:()=>{var e;return(e=t.current)==null?void 0:e.editor.focus()}}),[t]),i.createElement("div",{...f(r),ref:c})}function R(r,n){const{hostRef:c,controllerRef:t}=s(l.createViewerController,r);return i.useImperativeHandle(n,()=>({get viewer(){var e;return((e=t.current)==null?void 0:e.viewer)??null}}),[t]),i.createElement("div",{...f(r),ref:c})}const d=i.forwardRef(m);d.displayName="AerizEditor";const a=i.forwardRef(R);a.displayName="AerizViewer";exports.AerizEditor=d;exports.AerizViewer=a;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { forwardRef as s, useImperativeHandle as f, createElement as d, useRef as c, useEffect as u } from "react";
|
|
2
|
+
import { createEditorController as R, createViewerController as v } from "./shared.js";
|
|
3
|
+
function a(r, n) {
|
|
4
|
+
const i = c(null), t = c(null), e = c(n);
|
|
5
|
+
return e.current = n, u(() => {
|
|
6
|
+
const o = i.current;
|
|
7
|
+
if (!o) return;
|
|
8
|
+
const l = r(o, e.current);
|
|
9
|
+
return t.current = l, () => {
|
|
10
|
+
l.destroy(), t.current = null;
|
|
11
|
+
};
|
|
12
|
+
}, []), u(() => {
|
|
13
|
+
var o;
|
|
14
|
+
(o = t.current) == null || o.update(n);
|
|
15
|
+
}), { hostRef: i, controllerRef: t };
|
|
16
|
+
}
|
|
17
|
+
function m(r) {
|
|
18
|
+
const n = {};
|
|
19
|
+
return r.className !== void 0 && (n.className = r.className), r.style !== void 0 && (n.style = r.style), r.id !== void 0 && (n.id = r.id), n;
|
|
20
|
+
}
|
|
21
|
+
function w(r, n) {
|
|
22
|
+
const { hostRef: i, controllerRef: t } = a(R, r);
|
|
23
|
+
return f(
|
|
24
|
+
n,
|
|
25
|
+
() => ({
|
|
26
|
+
get editor() {
|
|
27
|
+
var e;
|
|
28
|
+
return ((e = t.current) == null ? void 0 : e.editor) ?? null;
|
|
29
|
+
},
|
|
30
|
+
getHTML: () => {
|
|
31
|
+
var e;
|
|
32
|
+
return ((e = t.current) == null ? void 0 : e.editor.getHTML()) ?? "";
|
|
33
|
+
},
|
|
34
|
+
setHTML: (e) => {
|
|
35
|
+
var o;
|
|
36
|
+
return (o = t.current) == null ? void 0 : o.editor.setHTML(e);
|
|
37
|
+
},
|
|
38
|
+
focus: () => {
|
|
39
|
+
var e;
|
|
40
|
+
return (e = t.current) == null ? void 0 : e.editor.focus();
|
|
41
|
+
}
|
|
42
|
+
}),
|
|
43
|
+
[t]
|
|
44
|
+
), d("div", { ...m(r), ref: i });
|
|
45
|
+
}
|
|
46
|
+
function A(r, n) {
|
|
47
|
+
const { hostRef: i, controllerRef: t } = a(v, r);
|
|
48
|
+
return f(
|
|
49
|
+
n,
|
|
50
|
+
() => ({
|
|
51
|
+
get viewer() {
|
|
52
|
+
var e;
|
|
53
|
+
return ((e = t.current) == null ? void 0 : e.viewer) ?? null;
|
|
54
|
+
}
|
|
55
|
+
}),
|
|
56
|
+
[t]
|
|
57
|
+
), d("div", { ...m(r), ref: i });
|
|
58
|
+
}
|
|
59
|
+
const y = s(w);
|
|
60
|
+
y.displayName = "AerizEditor";
|
|
61
|
+
const z = s(A);
|
|
62
|
+
z.displayName = "AerizViewer";
|
|
63
|
+
export {
|
|
64
|
+
y as AerizEditor,
|
|
65
|
+
z as AerizViewer
|
|
66
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const f=require("@aeriz/wysiwyg");function v(a){const e=document.createElement("div");e.innerHTML=a,f.normalizeContent(e);const t=new f.BlockIdRegistry;return f.assignMissingIds(e,t),f.serializeBlocks(f.listBlocks(e,o=>t.ensure(o)))}function T(a,e,t){const o={element:a,onChange:t},n=e.value??e.initialHTML;return n!==void 0&&(o.initialHTML=n),e.placeholder!==void 0&&(o.placeholder=e.placeholder),e.toolbar!==void 0&&(o.toolbar=e.toolbar),e.theme!==void 0&&(o.theme=e.theme),e.locale!==void 0&&(o.locale=e.locale),e.htmlStyles!==void 0&&(o.htmlStyles=e.htmlStyles),e.onImageUpload!==void 0&&(o.onImageUpload=e.onImageUpload),e.imageUploadUrl!==void 0&&(o.imageUploadUrl=e.imageUploadUrl),e.onFileUpload!==void 0&&(o.onFileUpload=e.onFileUpload),e.fileUploadUrl!==void 0&&(o.fileUploadUrl=e.fileUploadUrl),o}function w(a,e){return a===e?!0:a===!1||e===!1||a===void 0||e===void 0||a.sticky!==e.sticky||a.items.length!==e.items.length?!1:a.items.every((t,o)=>t===e.items[o])}function M(a,e){let t=e,o="",n=!1,d=!1;const m=l=>{var s;o=l,!n&&((s=t.onChange)==null||s.call(t,l))};let i,c=null,r;const S=l=>{l.onImageUpload===void 0?delete r.onImageUpload:r.onImageUpload=l.onImageUpload,l.imageUploadUrl===void 0?delete r.imageUploadUrl:r.imageUploadUrl=l.imageUploadUrl,l.onFileUpload===void 0?delete r.onFileUpload:r.onFileUpload=l.onFileUpload,l.fileUploadUrl===void 0?delete r.fileUploadUrl:r.fileUploadUrl=l.fileUploadUrl,l.htmlStyles===void 0?delete r.htmlStyles:r.htmlStyles=l.htmlStyles},u=(l,s)=>{var y;const h=s!==void 0?{...l,value:s}:l;r=T(a,h,m),i=new f.AerizEditor(r),o=i.getHTML(),c=i.onStateChange(k=>{var g;return(g=t.onStateChange)==null?void 0:g.call(t,k)}),(y=t.onReady)==null||y.call(t,i)},U=()=>{var l;(l=t.onDestroy)==null||l.call(t,i),c==null||c(),c=null,i.destroy()};return u(t),{get editor(){return i},update(l){if(d)return;const s=t;if(t=l,l.locale!==s.locale||!w(l.toolbar,s.toolbar)){const h=l.value??i.getHTML();U(),u(l,h);return}if(S(l),l.theme!==s.theme&&l.theme!==void 0&&i.setTheme(l.theme),l.placeholder!==s.placeholder&&(l.placeholder===void 0?delete i.content.dataset.placeholder:i.content.dataset.placeholder=l.placeholder),l.value!==void 0&&l.value!==o&&l.value!==i.getHTML()){n=!0;try{i.setHTML(l.value)}finally{n=!1}o=l.value}},destroy(){d||(d=!0,U())}}}function L(a,e){const t={element:a},o=e.blocks??(e.html!==void 0?v(e.html):void 0);return o!==void 0&&(t.initialBlocks=o),e.theme!==void 0&&(t.theme=e.theme),e.htmlStyles!==void 0&&(t.htmlStyles=e.htmlStyles),t}function C(a,e){var m;let t=e,o=!1;const n=L(a,e),d=new f.AerizViewer(n);return(m=t.onReady)==null||m.call(t,d),{viewer:d,update(i){if(o)return;const c=t;t=i,i.theme!==c.theme&&i.theme!==void 0&&d.setTheme(i.theme),i.htmlStyles===void 0?delete n.htmlStyles:n.htmlStyles=i.htmlStyles,i.blocks!==void 0?i.blocks!==c.blocks&&d.setBlocks(i.blocks):i.html!==void 0&&i.html!==c.html&&i.html!==d.getHTML()&&d.setBlocks(v(i.html))},destroy(){var i;o||(o=!0,(i=t.onDestroy)==null||i.call(t,d),d.destroy())}}}exports.createEditorController=M;exports.createViewerController=C;exports.htmlToBlocks=v;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { AerizViewer as k, AerizEditor as T, normalizeContent as L, BlockIdRegistry as M, assignMissingIds as H, serializeBlocks as I, listBlocks as w } from "@aeriz/wysiwyg";
|
|
2
|
+
function y(a) {
|
|
3
|
+
const e = document.createElement("div");
|
|
4
|
+
e.innerHTML = a, L(e);
|
|
5
|
+
const t = new M();
|
|
6
|
+
return H(e, t), I(w(e, (o) => t.ensure(o)));
|
|
7
|
+
}
|
|
8
|
+
function B(a, e, t) {
|
|
9
|
+
const o = { element: a, onChange: t }, n = e.value ?? e.initialHTML;
|
|
10
|
+
return n !== void 0 && (o.initialHTML = n), e.placeholder !== void 0 && (o.placeholder = e.placeholder), e.toolbar !== void 0 && (o.toolbar = e.toolbar), e.theme !== void 0 && (o.theme = e.theme), e.locale !== void 0 && (o.locale = e.locale), e.htmlStyles !== void 0 && (o.htmlStyles = e.htmlStyles), e.onImageUpload !== void 0 && (o.onImageUpload = e.onImageUpload), e.imageUploadUrl !== void 0 && (o.imageUploadUrl = e.imageUploadUrl), e.onFileUpload !== void 0 && (o.onFileUpload = e.onFileUpload), e.fileUploadUrl !== void 0 && (o.fileUploadUrl = e.fileUploadUrl), o;
|
|
11
|
+
}
|
|
12
|
+
function C(a, e) {
|
|
13
|
+
return a === e ? !0 : a === !1 || e === !1 || a === void 0 || e === void 0 || a.sticky !== e.sticky || a.items.length !== e.items.length ? !1 : a.items.every((t, o) => t === e.items[o]);
|
|
14
|
+
}
|
|
15
|
+
function z(a, e) {
|
|
16
|
+
let t = e, o = "", n = !1, d = !1;
|
|
17
|
+
const f = (l) => {
|
|
18
|
+
var s;
|
|
19
|
+
o = l, !n && ((s = t.onChange) == null || s.call(t, l));
|
|
20
|
+
};
|
|
21
|
+
let i, c = null, r;
|
|
22
|
+
const g = (l) => {
|
|
23
|
+
l.onImageUpload === void 0 ? delete r.onImageUpload : r.onImageUpload = l.onImageUpload, l.imageUploadUrl === void 0 ? delete r.imageUploadUrl : r.imageUploadUrl = l.imageUploadUrl, l.onFileUpload === void 0 ? delete r.onFileUpload : r.onFileUpload = l.onFileUpload, l.fileUploadUrl === void 0 ? delete r.fileUploadUrl : r.fileUploadUrl = l.fileUploadUrl, l.htmlStyles === void 0 ? delete r.htmlStyles : r.htmlStyles = l.htmlStyles;
|
|
24
|
+
}, h = (l, s) => {
|
|
25
|
+
var U;
|
|
26
|
+
const m = s !== void 0 ? { ...l, value: s } : l;
|
|
27
|
+
r = B(a, m, f), i = new T(r), o = i.getHTML(), c = i.onStateChange((S) => {
|
|
28
|
+
var u;
|
|
29
|
+
return (u = t.onStateChange) == null ? void 0 : u.call(t, S);
|
|
30
|
+
}), (U = t.onReady) == null || U.call(t, i);
|
|
31
|
+
}, v = () => {
|
|
32
|
+
var l;
|
|
33
|
+
(l = t.onDestroy) == null || l.call(t, i), c == null || c(), c = null, i.destroy();
|
|
34
|
+
};
|
|
35
|
+
return h(t), {
|
|
36
|
+
get editor() {
|
|
37
|
+
return i;
|
|
38
|
+
},
|
|
39
|
+
update(l) {
|
|
40
|
+
if (d) return;
|
|
41
|
+
const s = t;
|
|
42
|
+
if (t = l, l.locale !== s.locale || !C(l.toolbar, s.toolbar)) {
|
|
43
|
+
const m = l.value ?? i.getHTML();
|
|
44
|
+
v(), h(l, m);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (g(l), l.theme !== s.theme && l.theme !== void 0 && i.setTheme(l.theme), l.placeholder !== s.placeholder && (l.placeholder === void 0 ? delete i.content.dataset.placeholder : i.content.dataset.placeholder = l.placeholder), l.value !== void 0 && l.value !== o && l.value !== i.getHTML()) {
|
|
48
|
+
n = !0;
|
|
49
|
+
try {
|
|
50
|
+
i.setHTML(l.value);
|
|
51
|
+
} finally {
|
|
52
|
+
n = !1;
|
|
53
|
+
}
|
|
54
|
+
o = l.value;
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
destroy() {
|
|
58
|
+
d || (d = !0, v());
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function F(a, e) {
|
|
63
|
+
const t = { element: a }, o = e.blocks ?? (e.html !== void 0 ? y(e.html) : void 0);
|
|
64
|
+
return o !== void 0 && (t.initialBlocks = o), e.theme !== void 0 && (t.theme = e.theme), e.htmlStyles !== void 0 && (t.htmlStyles = e.htmlStyles), t;
|
|
65
|
+
}
|
|
66
|
+
function O(a, e) {
|
|
67
|
+
var f;
|
|
68
|
+
let t = e, o = !1;
|
|
69
|
+
const n = F(a, e), d = new k(n);
|
|
70
|
+
return (f = t.onReady) == null || f.call(t, d), {
|
|
71
|
+
viewer: d,
|
|
72
|
+
update(i) {
|
|
73
|
+
if (o) return;
|
|
74
|
+
const c = t;
|
|
75
|
+
t = i, i.theme !== c.theme && i.theme !== void 0 && d.setTheme(i.theme), i.htmlStyles === void 0 ? delete n.htmlStyles : n.htmlStyles = i.htmlStyles, i.blocks !== void 0 ? i.blocks !== c.blocks && d.setBlocks(i.blocks) : i.html !== void 0 && i.html !== c.html && i.html !== d.getHTML() && d.setBlocks(y(i.html));
|
|
76
|
+
},
|
|
77
|
+
destroy() {
|
|
78
|
+
var i;
|
|
79
|
+
o || (o = !0, (i = t.onDestroy) == null || i.call(t, d), d.destroy());
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export {
|
|
84
|
+
z as createEditorController,
|
|
85
|
+
O as createViewerController,
|
|
86
|
+
y as htmlToBlocks
|
|
87
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("./shared.cjs");function a(t,o={}){const e=r.createEditorController(t,o);return{update(i={}){e.update(i)},destroy(){e.destroy()}}}function l(t,o={}){const e=r.createViewerController(t,o);return{update(i={}){e.update(i)},destroy(){e.destroy()}}}exports.createEditorController=r.createEditorController;exports.createViewerController=r.createViewerController;exports.aerizEditor=a;exports.aerizViewer=l;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { createEditorController as n, createViewerController as d } from "./shared.js";
|
|
2
|
+
function a(e, t = {}) {
|
|
3
|
+
const r = n(e, t);
|
|
4
|
+
return {
|
|
5
|
+
update(o = {}) {
|
|
6
|
+
r.update(o);
|
|
7
|
+
},
|
|
8
|
+
destroy() {
|
|
9
|
+
r.destroy();
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function c(e, t = {}) {
|
|
14
|
+
const r = d(e, t);
|
|
15
|
+
return {
|
|
16
|
+
update(o = {}) {
|
|
17
|
+
r.update(o);
|
|
18
|
+
},
|
|
19
|
+
destroy() {
|
|
20
|
+
r.destroy();
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export {
|
|
25
|
+
a as aerizEditor,
|
|
26
|
+
c as aerizViewer,
|
|
27
|
+
n as createEditorController,
|
|
28
|
+
d as createViewerController
|
|
29
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=require("vue"),f=require("./shared.cjs"),r=l.defineComponent({name:"AerizEditor",props:{modelValue:{type:String,default:void 0},initialHTML:{type:String,default:void 0},placeholder:{type:String,default:void 0},toolbar:{type:[Object,Boolean],default:void 0},theme:{type:String,default:void 0},locale:{type:String,default:void 0},htmlStyles:{type:String,default:void 0},onImageUpload:{type:Function,default:void 0},imageUploadUrl:{type:String,default:void 0},onFileUpload:{type:Function,default:void 0},fileUploadUrl:{type:String,default:void 0}},emits:{"update:modelValue":e=>typeof e=="string",change:e=>typeof e=="string","state-change":e=>!0,ready:e=>!0},setup(e,{emit:o,expose:u}){const a=l.ref(null);let t=null;const n=()=>{const i={onChange:d=>{o("update:modelValue",d),o("change",d)},onStateChange:d=>o("state-change",d),onReady:d=>o("ready",d)};return e.modelValue!==void 0&&(i.value=e.modelValue),e.initialHTML!==void 0&&(i.initialHTML=e.initialHTML),e.placeholder!==void 0&&(i.placeholder=e.placeholder),e.toolbar!==void 0&&(i.toolbar=e.toolbar),e.theme!==void 0&&(i.theme=e.theme),e.locale!==void 0&&(i.locale=e.locale),e.htmlStyles!==void 0&&(i.htmlStyles=e.htmlStyles),e.onImageUpload!==void 0&&(i.onImageUpload=e.onImageUpload),e.imageUploadUrl!==void 0&&(i.imageUploadUrl=e.imageUploadUrl),e.onFileUpload!==void 0&&(i.onFileUpload=e.onFileUpload),e.fileUploadUrl!==void 0&&(i.fileUploadUrl=e.fileUploadUrl),i};return l.onMounted(()=>{a.value&&(t=f.createEditorController(a.value,n()))}),l.watch(()=>({...e}),()=>t==null?void 0:t.update(n()),{flush:"post"}),l.onBeforeUnmount(()=>{t==null||t.destroy(),t=null}),u({get editor(){return(t==null?void 0:t.editor)??null},getHTML:()=>(t==null?void 0:t.editor.getHTML())??"",setHTML:i=>t==null?void 0:t.editor.setHTML(i),focus:()=>t==null?void 0:t.editor.focus()}),()=>l.h("div",{ref:a})}}),v=l.defineComponent({name:"AerizViewer",props:{blocks:{type:Array,default:void 0},html:{type:String,default:void 0},theme:{type:String,default:void 0},htmlStyles:{type:String,default:void 0}},emits:{ready:e=>!0},setup(e,{emit:o,expose:u}){const a=l.ref(null);let t=null;const n=()=>{const i={onReady:d=>o("ready",d)};return e.blocks!==void 0&&(i.blocks=e.blocks),e.html!==void 0&&(i.html=e.html),e.theme!==void 0&&(i.theme=e.theme),e.htmlStyles!==void 0&&(i.htmlStyles=e.htmlStyles),i};return l.onMounted(()=>{a.value&&(t=f.createViewerController(a.value,n()))}),l.watch(()=>({...e}),()=>t==null?void 0:t.update(n()),{flush:"post"}),l.onBeforeUnmount(()=>{t==null||t.destroy(),t=null}),u({get viewer(){return(t==null?void 0:t.viewer)??null}}),()=>l.h("div",{ref:a})}}),m={install(e){e.component("AerizEditor",r),e.component("AerizViewer",v)}};exports.AerizEditor=r;exports.AerizViewer=v;exports.AerizWysiwygPlugin=m;
|