@tmdjr/ngx-editor-js2 20.0.6 → 20.0.7
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/package.json +1 -1
- package/schematics/ng-add/files/demo/app.ts.template +66 -0
- package/schematics/ng-add/files/demo/components/hero.ts.template +126 -0
- package/schematics/ng-add/files/demo/services/ngx-editor-js2.ts.template +140 -0
- package/schematics/ng-add/index.js +10 -1
- package/schematics/ng-add/index.ts +13 -3
- package/schematics/ng-add/schema.json +9 -0
package/package.json
CHANGED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Component, inject } from '@angular/core';
|
|
2
|
+
import { AsyncPipe } from '@angular/common';
|
|
3
|
+
import { MatCard, MatCardContent } from '@angular/material/card';
|
|
4
|
+
import { NgxEditorJs2Component } from '@tmdjr/ngx-editor-js2';
|
|
5
|
+
|
|
6
|
+
import { NgxEditorJs2 } from '../services/ngx-editor-js2';
|
|
7
|
+
|
|
8
|
+
@Component({
|
|
9
|
+
selector: 'app-root',
|
|
10
|
+
imports: [
|
|
11
|
+
AsyncPipe,
|
|
12
|
+
MatCard,
|
|
13
|
+
MatCardContent,
|
|
14
|
+
NgxEditorJs2Component,
|
|
15
|
+
Hero,
|
|
16
|
+
],
|
|
17
|
+
template: `
|
|
18
|
+
<main>
|
|
19
|
+
<app-hero></app-hero>
|
|
20
|
+
<mat-card appearance="outlined">
|
|
21
|
+
<mat-card-content>
|
|
22
|
+
<ngx-editor-js2
|
|
23
|
+
[blocks]="(ngxEditorJs2.ngxEditorJsBlocks$ | async)!"
|
|
24
|
+
[requestBlocks]="ngxEditorJs2.requestBlocks$ | async"
|
|
25
|
+
(blocksRequested)="ngxEditorJs2.handleBlocks($event)"
|
|
26
|
+
></ngx-editor-js2>
|
|
27
|
+
</mat-card-content>
|
|
28
|
+
</mat-card>
|
|
29
|
+
</main>
|
|
30
|
+
`,
|
|
31
|
+
styles: [
|
|
32
|
+
`
|
|
33
|
+
@use '@angular/material' as mat;
|
|
34
|
+
:host {
|
|
35
|
+
@include mat.card-overrides(
|
|
36
|
+
(
|
|
37
|
+
outlined-outline-width: 0.5px,
|
|
38
|
+
outlined-container-color: var(--mat-sys-surface-container-low),
|
|
39
|
+
outlined-outline-color: var(--mat-sys-on-surface),
|
|
40
|
+
)
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
display: flex;
|
|
44
|
+
flex-direction: column;
|
|
45
|
+
min-height: 100vh;
|
|
46
|
+
|
|
47
|
+
main {
|
|
48
|
+
flex: 1;
|
|
49
|
+
display: flex;
|
|
50
|
+
flex-direction: column;
|
|
51
|
+
align-items: center;
|
|
52
|
+
gap: 3em;
|
|
53
|
+
margin-top: 56px;
|
|
54
|
+
mat-card {
|
|
55
|
+
width: 100%;
|
|
56
|
+
max-width: 800px;
|
|
57
|
+
margin-bottom: 3em;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
`,
|
|
62
|
+
],
|
|
63
|
+
})
|
|
64
|
+
export class AppComponent {
|
|
65
|
+
ngxEditorJs2 = inject(NgxEditorJs2);
|
|
66
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { Component, inject } from '@angular/core';
|
|
2
|
+
import { MatButton } from '@angular/material/button';
|
|
3
|
+
import { NgxEditorJs2, TEST_DATA, TEST_DATA_TWO } from '../services/ngx-editor-js2';
|
|
4
|
+
import { MatTooltip } from '@angular/material/tooltip';
|
|
5
|
+
import { of } from 'rxjs';
|
|
6
|
+
|
|
7
|
+
@Component({
|
|
8
|
+
selector: 'app-hero',
|
|
9
|
+
imports: [MatButton, MatTooltip],
|
|
10
|
+
template: `
|
|
11
|
+
<header class="header-background">
|
|
12
|
+
<div class="header-section">
|
|
13
|
+
<div class="header-headline">
|
|
14
|
+
<h1>Ngx EditorJs2</h1>
|
|
15
|
+
<h2>A Custom Themeable Angular Material 3 Component</h2>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="header-start">
|
|
18
|
+
<button
|
|
19
|
+
mat-stroked-button
|
|
20
|
+
matTooltip="Simulate loading blocks"
|
|
21
|
+
(click)="loadValue()"
|
|
22
|
+
>
|
|
23
|
+
Load
|
|
24
|
+
</button>
|
|
25
|
+
<button
|
|
26
|
+
mat-stroked-button
|
|
27
|
+
matTooltip="Simulate clearing blocks"
|
|
28
|
+
(click)="clearValue()"
|
|
29
|
+
>
|
|
30
|
+
Clear
|
|
31
|
+
</button>
|
|
32
|
+
<button
|
|
33
|
+
mat-stroked-button
|
|
34
|
+
matTooltip="Open the console for blocks"
|
|
35
|
+
(click)="saveValue()"
|
|
36
|
+
>
|
|
37
|
+
Save
|
|
38
|
+
</button>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
</header>
|
|
42
|
+
`,
|
|
43
|
+
styles: [
|
|
44
|
+
`
|
|
45
|
+
@use '@angular/material' as mat;
|
|
46
|
+
|
|
47
|
+
:host {
|
|
48
|
+
width: 100%;
|
|
49
|
+
@include mat.button-overrides(
|
|
50
|
+
(
|
|
51
|
+
outlined-label-text-color: var(--mat-sys-on-secondary),
|
|
52
|
+
)
|
|
53
|
+
);
|
|
54
|
+
.header-background {
|
|
55
|
+
overflow: hidden;
|
|
56
|
+
position: relative;
|
|
57
|
+
height: 360px;
|
|
58
|
+
color: var(--mat-sys-on-secondary);
|
|
59
|
+
background: var(--mat-sys-secondary);
|
|
60
|
+
&::before {
|
|
61
|
+
content: '';
|
|
62
|
+
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48" fill="%23FFFFFF"><path d="M14.5 40V13H4V8h26v5H19.5v27Zm18 0V23H26v-5h18v5h-6.5v17Z"/></svg>');
|
|
63
|
+
background-repeat: no-repeat;
|
|
64
|
+
background-size: 400px;
|
|
65
|
+
background-position: 80% -25px;
|
|
66
|
+
opacity: 0.2;
|
|
67
|
+
position: absolute;
|
|
68
|
+
top: 0;
|
|
69
|
+
bottom: 0;
|
|
70
|
+
left: 0;
|
|
71
|
+
right: 0;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
.header-section {
|
|
75
|
+
display: flex;
|
|
76
|
+
justify-content: center;
|
|
77
|
+
flex-direction: column;
|
|
78
|
+
align-items: center;
|
|
79
|
+
height: 100%;
|
|
80
|
+
text-align: center;
|
|
81
|
+
.header-headline {
|
|
82
|
+
h1 {
|
|
83
|
+
font-size: 56px;
|
|
84
|
+
font-weight: bold;
|
|
85
|
+
line-height: 56px;
|
|
86
|
+
margin: 15px 5px;
|
|
87
|
+
}
|
|
88
|
+
h2 {
|
|
89
|
+
font-size: 20px;
|
|
90
|
+
font-weight: 300;
|
|
91
|
+
line-height: 28px;
|
|
92
|
+
margin: 15px 0 25px 0;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
.header-start {
|
|
96
|
+
display: flex;
|
|
97
|
+
flex-direction: row;
|
|
98
|
+
gap: 10px;
|
|
99
|
+
button {
|
|
100
|
+
margin: 0 5px;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
`,
|
|
106
|
+
],
|
|
107
|
+
})
|
|
108
|
+
export class HeroComponent {
|
|
109
|
+
ngxEditorJs2 = inject(NgxEditorJs2);
|
|
110
|
+
|
|
111
|
+
saveValue() {
|
|
112
|
+
this.ngxEditorJs2.requestBlocks.next({});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
switch = false;
|
|
116
|
+
loadValue() {
|
|
117
|
+
this.switch = !this.switch;
|
|
118
|
+
this.ngxEditorJs2.ngxEditorJsBlocks.next(
|
|
119
|
+
this.switch ? TEST_DATA : TEST_DATA_TWO
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
clearValue() {
|
|
124
|
+
this.ngxEditorJs2.ngxEditorJsBlocks.next([]);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { NgxEditorJsBlock } from '@tmdjr/ngx-editor-js2';
|
|
3
|
+
import { BehaviorSubject, lastValueFrom, Observable, tap } from 'rxjs';
|
|
4
|
+
|
|
5
|
+
export const TEST_DATA: NgxEditorJsBlock[] = [
|
|
6
|
+
{
|
|
7
|
+
blockId: 'n177d7',
|
|
8
|
+
sortIndex: 0,
|
|
9
|
+
componentInstanceName: 'NgxEditorJs2BlockquotesComponent',
|
|
10
|
+
savedAction: 'display-large',
|
|
11
|
+
dataClean:
|
|
12
|
+
'`Design is not just what it looks like and feels like. Design is how it works.',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
blockId: 'n177dsd',
|
|
16
|
+
sortIndex: 1,
|
|
17
|
+
componentInstanceName: 'NgxEditorJs2ImageComponent',
|
|
18
|
+
savedAction: 'stretch',
|
|
19
|
+
dataClean:
|
|
20
|
+
'{"url":"https://res.cloudinary.com/dowdpiikk/image/upload/w_650,q_auto:best,f_auto/v1709445782/lnyst5aqppuin8wt73ci.webp","title":"test"}',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
blockId: 'iovlbzgosf',
|
|
24
|
+
sortIndex: 2,
|
|
25
|
+
componentInstanceName: 'HeaderBlockComponent',
|
|
26
|
+
savedAction: 'h1',
|
|
27
|
+
dataClean: 'Prerequisites',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
blockId: '8u3uiij5vyj',
|
|
31
|
+
sortIndex: 3,
|
|
32
|
+
componentInstanceName: 'ParagraphBlockComponent',
|
|
33
|
+
savedAction: 'large',
|
|
34
|
+
dataClean:
|
|
35
|
+
'<ul><li><a href="https://www.typescriptlang.org/">TypeScript</a> and HTML5 programming</li><li>Angular app-design fundamentals, as described in <a href="https://angular.io/guide/architecture">Angular Concepts</a><br></li><li>The basics of <a href="https://angular.io/guide/architecture-components#template-syntax">Angular template syntax</a><br></li></ul>',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
blockId: 'bu23hwyltss',
|
|
39
|
+
sortIndex: 4,
|
|
40
|
+
componentInstanceName: 'ParagraphBlockComponent',
|
|
41
|
+
savedAction: 'large',
|
|
42
|
+
dataClean:
|
|
43
|
+
'Evaluation of a template expression should have no visible side effects. Use the syntax for template expressions to help avoid side effects. In general, the correct syntax prevents you from assigning a value to anything in a property binding expression. The syntax also prevents you from using increment and decrement operators.',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
blockId: 'uapf2',
|
|
47
|
+
sortIndex: 5,
|
|
48
|
+
componentInstanceName: 'NgxEditorJs2MermaidjsComponent',
|
|
49
|
+
savedAction: 'center',
|
|
50
|
+
dataClean:
|
|
51
|
+
'flowchart TD\n A[Christmas] -->|Get money| B(Go shopping)\n B --> C{Let me think}\n C -->|One| D[Laptop]\n C -->|Two| E[Hello World iPhone]\n C -->|Three| F[fa:fa-car Car]',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
blockId: 'bu23hwyltsww',
|
|
55
|
+
sortIndex: 6,
|
|
56
|
+
componentInstanceName: 'ParagraphBlockComponent',
|
|
57
|
+
savedAction: 'small',
|
|
58
|
+
dataClean:
|
|
59
|
+
'Material Design uses color to create accessible, personal color schemes that communicate your products hierarchy, state, and brand. See Material Designs Color System page to learn more about its use and purpose.',
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
blockId: 'asdfasdf',
|
|
63
|
+
sortIndex: 7,
|
|
64
|
+
componentInstanceName: 'NgxEditorJs2CodemirrorComponent',
|
|
65
|
+
savedAction: 'text/typescript',
|
|
66
|
+
dataClean:
|
|
67
|
+
"export class SimpleFormGroup {\n form = new FormGroup({\n first: new FormControl('Nancy', Validators.minLength(2)),\n last: new FormControl('Drew'),\n });\n\n get first(): any {\n return this.form.get('first');\n }\n\n onSubmit(): void {\n console.log(this.form.value); // {first: 'Nancy', last: 'Drew'}\n }\n\n setValue() {\n this.form.setValue({first: 'Carson', last: 'Drew'});\n }\n}",
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
blockId: 'l13u3k',
|
|
71
|
+
sortIndex: 8,
|
|
72
|
+
componentInstanceName: 'HeaderBlockComponent',
|
|
73
|
+
savedAction: 'h1',
|
|
74
|
+
dataClean: 'New way of learning...',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
blockId: '9bqhk',
|
|
78
|
+
sortIndex: 9,
|
|
79
|
+
componentInstanceName: 'NgxEditorJs2PopQuizComponent',
|
|
80
|
+
savedAction: 'display-large',
|
|
81
|
+
dataClean:
|
|
82
|
+
'{"question":"Which of the following statements is true about Angular\'s default RouteReuseStrategy?","answer":"It reuses components when the route configuration remains the same.","correctResponse":"That\'s correct! Angular\'s default RouteReuseStrategy reuses components when the route configuration remains the same. This prevents components from being destroyed and recreated when only the fragment or query parameters change.","incorrectResponse":"That\'s incorrect. The correct answer is C. Angular\'s default RouteReuseStrategy reuses components when the route configuration remains the same. This prevents components from being destroyed and recreated when only the fragment or query parameters change.","choices":[{"value":"It only reuses components when the route configuration changes."},{"value":"It only reuses components when the route parameters change."},{"value":"It reuses components when the route configuration remains the same."},{"value":"It never reuses components."}]}',
|
|
83
|
+
},
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
export const TEST_DATA_TWO: NgxEditorJsBlock[] = [
|
|
87
|
+
{
|
|
88
|
+
blockId: 'iovlbzgosf',
|
|
89
|
+
sortIndex: 0,
|
|
90
|
+
componentInstanceName: 'HeaderBlockComponent',
|
|
91
|
+
dataClean: 'Different Prerequisites',
|
|
92
|
+
savedAction: 'h1',
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
blockId: 'bu23hwyltwl',
|
|
96
|
+
sortIndex: 1,
|
|
97
|
+
componentInstanceName: 'ParagraphBlockComponent',
|
|
98
|
+
dataClean:
|
|
99
|
+
'Skips the very first call to startViewTransition. This can be useful for disabling the animation during the applications initial loading phase.',
|
|
100
|
+
savedAction: 'meduim',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
blockId: 'bu23hwyltss',
|
|
104
|
+
sortIndex: 2,
|
|
105
|
+
componentInstanceName: 'ParagraphBlockComponent',
|
|
106
|
+
dataClean: 'SOmeehting Different then the last one',
|
|
107
|
+
savedAction: 'meduim',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
blockId: 'iovlbzgosuu',
|
|
111
|
+
sortIndex: 3,
|
|
112
|
+
componentInstanceName: 'HeaderBlockComponent',
|
|
113
|
+
dataClean: 'Woah! This is cool..',
|
|
114
|
+
savedAction: 'h3',
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
blockId: 'bu23hwyltsww',
|
|
118
|
+
sortIndex: 2,
|
|
119
|
+
componentInstanceName: 'ParagraphBlockComponent',
|
|
120
|
+
dataClean:
|
|
121
|
+
'Material Design uses color to create accessible, personal color schemes that communicate your products hierarchy, state, and brand. See Material Designs Color System page to learn more about its use and purpose.',
|
|
122
|
+
savedAction: 'small',
|
|
123
|
+
},
|
|
124
|
+
];
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@Injectable({
|
|
128
|
+
providedIn: 'root',
|
|
129
|
+
})
|
|
130
|
+
export class NgxEditorJs2 {
|
|
131
|
+
ngxEditorJsBlocks = new BehaviorSubject<NgxEditorJsBlock[]>(TEST_DATA);
|
|
132
|
+
ngxEditorJsBlocks$ = this.ngxEditorJsBlocks.asObservable();
|
|
133
|
+
|
|
134
|
+
requestBlocks = new BehaviorSubject<{}>({});
|
|
135
|
+
requestBlocks$ = this.requestBlocks.asObservable();
|
|
136
|
+
|
|
137
|
+
handleBlocks(blocks$: Observable<NgxEditorJsBlock[]>) {
|
|
138
|
+
void lastValueFrom(blocks$.pipe(tap(console.table)));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.ngAdd = ngAdd;
|
|
13
|
+
const schematics_1 = require("@angular-devkit/schematics");
|
|
13
14
|
const tasks_1 = require("@angular-devkit/schematics/tasks");
|
|
14
15
|
const dependencies_1 = require("@schematics/angular/utility/dependencies");
|
|
15
16
|
const optionalBlocks = {
|
|
@@ -88,6 +89,14 @@ function ngAdd(options) {
|
|
|
88
89
|
updateStylesScss(tree, blocks, context, sourceRoot);
|
|
89
90
|
updateAppConfig(tree, blocks, context, sourceRoot);
|
|
90
91
|
addCodeMirrorSetup(tree, blocks, context, sourceRoot);
|
|
92
|
+
if (options.demo) {
|
|
93
|
+
// Add demo files
|
|
94
|
+
context.logger.info('✨ Adding demo AppComponent...');
|
|
95
|
+
(0, schematics_1.mergeWith)((0, schematics_1.apply)((0, schematics_1.url)('./files/demo'), [
|
|
96
|
+
(0, schematics_1.applyTemplates)({}), // you can pass vars here if you want
|
|
97
|
+
(0, schematics_1.move)('src/app'), // adjust this path if needed
|
|
98
|
+
]))(tree, context);
|
|
99
|
+
}
|
|
91
100
|
context.logger.info('✅ Installation setup complete.');
|
|
92
101
|
return tree;
|
|
93
102
|
});
|
|
@@ -184,7 +193,7 @@ import 'codemirror/mode/xml/xml';
|
|
|
184
193
|
@use "codemirror/theme/material-palenight";
|
|
185
194
|
`;
|
|
186
195
|
if (!stylesContent.includes('CODEMIRROR Dependencies')) {
|
|
187
|
-
tree.overwrite(stylesPath, codeMirrorStyles + stylesContent);
|
|
196
|
+
tree.overwrite(stylesPath, codeMirrorStyles + stylesContent);
|
|
188
197
|
context.logger.info('CodeMirror styles added to styles.scss');
|
|
189
198
|
}
|
|
190
199
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';
|
|
1
|
+
import { apply, applyTemplates, mergeWith, move, Rule, SchematicContext, Tree, url } from '@angular-devkit/schematics';
|
|
2
2
|
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
|
|
3
3
|
import {
|
|
4
4
|
addPackageJsonDependency,
|
|
@@ -94,8 +94,18 @@ export function ngAdd(options: any): Rule {
|
|
|
94
94
|
updateAppConfig(tree, blocks, context, sourceRoot);
|
|
95
95
|
addCodeMirrorSetup(tree, blocks, context, sourceRoot);
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
if (options.demo) {
|
|
98
|
+
// Add demo files
|
|
99
|
+
context.logger.info('✨ Adding demo AppComponent...');
|
|
100
|
+
mergeWith(
|
|
101
|
+
apply(url('./files/demo'), [
|
|
102
|
+
applyTemplates({}), // you can pass vars here if you want
|
|
103
|
+
move('src/app'), // adjust this path if needed
|
|
104
|
+
])
|
|
105
|
+
)(tree, context);
|
|
106
|
+
}
|
|
98
107
|
|
|
108
|
+
context.logger.info('✅ Installation setup complete.');
|
|
99
109
|
return tree;
|
|
100
110
|
};
|
|
101
111
|
}
|
|
@@ -249,7 +259,7 @@ import 'codemirror/mode/xml/xml';
|
|
|
249
259
|
`;
|
|
250
260
|
|
|
251
261
|
if (!stylesContent.includes('CODEMIRROR Dependencies')) {
|
|
252
|
-
tree.overwrite(stylesPath, codeMirrorStyles + stylesContent);
|
|
262
|
+
tree.overwrite(stylesPath, codeMirrorStyles + stylesContent);
|
|
253
263
|
context.logger.info('CodeMirror styles added to styles.scss');
|
|
254
264
|
}
|
|
255
265
|
} else {
|
|
@@ -25,6 +25,15 @@
|
|
|
25
25
|
"type": "string",
|
|
26
26
|
"description": "The Angular project to update",
|
|
27
27
|
"x-prompt": "Which Angular project would you like to update?"
|
|
28
|
+
},
|
|
29
|
+
"demo": {
|
|
30
|
+
"type": "boolean",
|
|
31
|
+
"default": false,
|
|
32
|
+
"description": "Add component and service",
|
|
33
|
+
"x-prompt": {
|
|
34
|
+
"message": "Would you like to create demo of ng-editor-js2?",
|
|
35
|
+
"type": "confirm"
|
|
36
|
+
}
|
|
28
37
|
}
|
|
29
38
|
}
|
|
30
39
|
}
|