1 | import { Component, EventEmitter, Input, NgModule, Output, ViewChild, ViewEncapsulation, forwardRef } from '@angular/core';
|
2 | import { CommonModule } from '@angular/common';
|
3 | import { FormsModule, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms';
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 | var NgxWigToolbarService = (function () {
|
10 | function NgxWigToolbarService() {
|
11 | this._buttonLibrary = {
|
12 | list1: { title: 'Unordered List', command: 'insertunorderedlist', styleClass: 'list-ul' },
|
13 | list2: { title: 'Ordered List', command: 'insertorderedlist', styleClass: 'list-ol' },
|
14 | bold: { title: 'Bold', command: 'bold', styleClass: 'bold' },
|
15 | italic: { title: 'Italic', command: 'italic', styleClass: 'italic' },
|
16 | link: { title: 'Link', command: 'createlink', styleClass: 'link' }
|
17 | };
|
18 | this._defaultButtonsList = ['list1', 'list2', 'bold', 'italic', 'link'];
|
19 | }
|
20 | |
21 |
|
22 |
|
23 |
|
24 | NgxWigToolbarService.prototype.setButtons = |
25 |
|
26 |
|
27 |
|
28 | function (buttons) {
|
29 |
|
30 |
|
31 |
|
32 | this._defaultButtonsList = buttons;
|
33 | };
|
34 |
|
35 | |
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 | NgxWigToolbarService.prototype.addStandardButton = |
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 | function (name, title, command, styleClass) {
|
50 | if (!name || !title || !command) {
|
51 | throw 'Arguments "name", "title" and "command" are required';
|
52 | }
|
53 | styleClass = styleClass || '';
|
54 | this._buttonLibrary[name] = { title: title, command: command, styleClass: styleClass };
|
55 | this._defaultButtonsList.push(name);
|
56 | };
|
57 | |
58 |
|
59 |
|
60 |
|
61 |
|
62 | NgxWigToolbarService.prototype.addCustomButton = |
63 |
|
64 |
|
65 |
|
66 |
|
67 | function (name, pluginName) {
|
68 | if (!name || !pluginName) {
|
69 | throw 'Arguments "name" and "pluginName" are required';
|
70 | }
|
71 | this._buttonLibrary[name] = { pluginName: pluginName, isComplex: true };
|
72 | this._defaultButtonsList.push(name);
|
73 | };
|
74 | |
75 |
|
76 |
|
77 |
|
78 | NgxWigToolbarService.prototype.getToolbarButtons = |
79 |
|
80 |
|
81 |
|
82 | function (buttonsList) {
|
83 | var _this = this;
|
84 | var buttons = this._defaultButtonsList;
|
85 | var toolbarButtons = [];
|
86 | if (typeof buttonsList !== 'undefined') {
|
87 | buttons = string2array(buttonsList);
|
88 | }
|
89 | buttons.forEach(function (buttonKey) {
|
90 | if (!buttonKey) {
|
91 | return;
|
92 | }
|
93 | if (!_this._buttonLibrary[buttonKey]) {
|
94 | throw 'There is no "' + buttonKey + '" in your library. Possible variants: ' + Object.keys(_this._buttonLibrary);
|
95 | }
|
96 | var button = Object.assign({}, _this._buttonLibrary[buttonKey]);
|
97 |
|
98 | toolbarButtons.push(button);
|
99 | });
|
100 | return toolbarButtons;
|
101 | };
|
102 | return NgxWigToolbarService;
|
103 | }());
|
104 |
|
105 |
|
106 |
|
107 |
|
108 | function string2array(keysString) {
|
109 | return keysString.split(',').map(Function.prototype.call, String.prototype.trim);
|
110 | }
|
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 | var NgxWigComponent = (function () {
|
117 | function NgxWigComponent(_ngWigToolbarService) {
|
118 | this._ngWigToolbarService = _ngWigToolbarService;
|
119 | this.isSourceModeAllowed = false;
|
120 | this.contentChange = new EventEmitter();
|
121 | this.editMode = false;
|
122 | this.toolbarButtons = [];
|
123 | this.hasFocus = false;
|
124 | this.propagateChange = function (_) { };
|
125 |
|
126 | this.iconsTheme = "nw-button-mdi";
|
127 | }
|
128 | |
129 |
|
130 |
|
131 | NgxWigComponent.prototype.toggleEditMode = |
132 |
|
133 |
|
134 | function () {
|
135 | this.editMode = !this.editMode;
|
136 | };
|
137 | |
138 |
|
139 |
|
140 |
|
141 |
|
142 | NgxWigComponent.prototype.execCommand = |
143 |
|
144 |
|
145 |
|
146 |
|
147 | function (command, options) {
|
148 | if (this.editMode) {
|
149 | return false;
|
150 | }
|
151 | if (document.queryCommandSupported && !document.queryCommandSupported(command)) {
|
152 | throw 'The command "' + command + '" is not supported';
|
153 | }
|
154 | if (command === 'createlink' || command === 'insertImage') {
|
155 | options = window.prompt('Please enter the URL', 'http://');
|
156 | if (!options) {
|
157 | return;
|
158 | }
|
159 | }
|
160 |
|
161 | var selection = document.getSelection().toString();
|
162 | if (command === 'createlink' && selection === '') {
|
163 | document.execCommand('insertHtml', false, '<a href="' + options + '">' + options + '</a>');
|
164 | }
|
165 | else {
|
166 | document.execCommand(command, false, options);
|
167 | }
|
168 | this.container.focus();
|
169 | };
|
170 | |
171 |
|
172 |
|
173 | NgxWigComponent.prototype.ngOnInit = |
174 |
|
175 |
|
176 | function () {
|
177 | var _this = this;
|
178 | this.toolbarButtons = this._ngWigToolbarService.getToolbarButtons(this.buttons);
|
179 | this.container = this.ngxWigEditable.nativeElement;
|
180 | if (this.content) {
|
181 | this.container.innerHTML = this.content;
|
182 | }
|
183 |
|
184 | ('keyup change focus click'.split(' ')).forEach(function (event) {
|
185 | return _this.container.addEventListener(event, function () {
|
186 | _this.content = _this.container.innerHTML;
|
187 | _this.contentChange.emit(_this.content);
|
188 | _this.propagateChange(_this.content);
|
189 | }, false);
|
190 | });
|
191 | };
|
192 | |
193 |
|
194 |
|
195 |
|
196 | NgxWigComponent.prototype.ngOnChanges = |
197 |
|
198 |
|
199 |
|
200 | function (changes) {
|
201 | if (this.container && changes['content']) {
|
202 |
|
203 | this.container.innerHTML = '';
|
204 |
|
205 | this.pasteHtmlAtCaret(changes['content'].currentValue);
|
206 | }
|
207 | };
|
208 | |
209 |
|
210 |
|
211 |
|
212 | NgxWigComponent.prototype.onChange = |
213 |
|
214 |
|
215 |
|
216 | function (event) {
|
217 |
|
218 | this.container.innerHTML = this.content;
|
219 | this.contentChange.emit(this.content);
|
220 | this.propagateChange(this.content);
|
221 | };
|
222 | |
223 |
|
224 |
|
225 |
|
226 | NgxWigComponent.prototype.writeValue = |
227 |
|
228 |
|
229 |
|
230 | function (value) {
|
231 | if (value) {
|
232 | this.content = value;
|
233 | this.container.innerHTML = this.content;
|
234 | }
|
235 | };
|
236 | |
237 |
|
238 |
|
239 |
|
240 | NgxWigComponent.prototype.registerOnChange = |
241 |
|
242 |
|
243 |
|
244 | function (fn) {
|
245 | this.propagateChange = fn;
|
246 | };
|
247 | |
248 |
|
249 |
|
250 | NgxWigComponent.prototype.registerOnTouched = |
251 |
|
252 |
|
253 | function () { };
|
254 | |
255 |
|
256 |
|
257 | NgxWigComponent.prototype.shouldShowPlaceholder = |
258 |
|
259 |
|
260 | function () {
|
261 | return this.placeholder
|
262 | && !this.hasFocus
|
263 | && !this.container.innerText;
|
264 | };
|
265 | |
266 |
|
267 |
|
268 |
|
269 | NgxWigComponent.prototype.pasteHtmlAtCaret = |
270 |
|
271 |
|
272 |
|
273 | function (html) {
|
274 | var sel, range;
|
275 | if (window.getSelection) {
|
276 | sel = window.getSelection();
|
277 | if (sel.getRangeAt && sel.rangeCount) {
|
278 | range = sel.getRangeAt(0);
|
279 | range.deleteContents();
|
280 |
|
281 | var el = document.createElement('div');
|
282 | el.innerHTML = html;
|
283 | var frag = document.createDocumentFragment(), node = void 0, lastNode = void 0;
|
284 | while ((node = el.firstChild)) {
|
285 | lastNode = frag.appendChild(node);
|
286 | }
|
287 | range.insertNode(frag);
|
288 |
|
289 | if (lastNode) {
|
290 | range = range.cloneRange();
|
291 | range.setStartAfter(lastNode);
|
292 | range.collapse(true);
|
293 | sel.removeAllRanges();
|
294 | sel.addRange(range);
|
295 | }
|
296 | }
|
297 | }
|
298 | };
|
299 | |
300 |
|
301 |
|
302 |
|
303 | NgxWigComponent.prototype.setDisabledState = |
304 |
|
305 |
|
306 |
|
307 | function (isDisabled) {
|
308 | this.disabled = isDisabled;
|
309 | };
|
310 | NgxWigComponent.decorators = [
|
311 | { type: Component, args: [{
|
312 | selector: 'ngx-wig',
|
313 | template: "<div class=\"ng-wig\"> <ul class=\"nw-toolbar\" *ngIf=\"toolbarButtons.length\"> <li class=\"nw-toolbar__item\" *ngFor=\"let button of toolbarButtons\"> <div *ngIf=\"!button.isComplex\"> <button type=\"button\" class=\"nw-button\" [ngClass]=\"[button.styleClass, iconsTheme]\" [title]=\"button.title\" (click)=\"execCommand(button.command)\" [disabled]=\"disabled\"> {{ button.title }} </button> </div> </li><!-- --><li class=\"nw-toolbar__item\"> <button type=\"button\" class=\"nw-button nw-button--source\" title=\"Edit HTML\" [class.nw-button--active] = \"editMode\" [ngClass]=\"iconsTheme\" *ngIf=\"isSourceModeAllowed\" (click)=\"toggleEditMode()\" [disabled]=\"disabled\"> Edit HTML </button> </li> </ul> <div class=\"nw-editor-container\" (click)=\"container.focus()\" [ngClass]=\"{ 'nw-editor-container--with-toolbar': toolbarButtons.length }\"> <div class=\"nw-editor__src-container\" *ngIf=\"editMode\"> <textarea [(ngModel)]=\"content\" (ngModelChange)=\"onChange($event)\" class=\"nw-editor__src\"> </textarea> </div> <div class=\"nw-editor\" [ngClass]=\"{ 'nw-disabled': disabled,'nw-invisible': editMode}\"> <div class=\"nw-editor__placeholder\" [innerText]=\"placeholder\" *ngIf=\"shouldShowPlaceholder()\"> </div> <div #ngWigEditable class=\"nw-editor__res\" [attr.contenteditable]=\"!disabled\" [ngClass]=\"{ disabled: disabled}\" (focus)=\"hasFocus = true\" (blur)=\"hasFocus = false\"> </div> </div> </div> </div>",
|
314 | styles: ["/* -------- NG-WIG -------- */ /** * * RESET BOX MODEL * */ .ng-wig, [class^=\"nw-\"] { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -o-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box; } /** * main wrapper for the editor * * .ngx-wig * */ .ng-wig { display: block; padding: 0; margin: 0; } /** * styling for toolbar and its items * * .nw-toolbar * &__item * */ .nw-toolbar { display: block; margin: 0; padding: 0; list-style: none; font-size: 12px; color: #6B7277; background: -webkit-linear-gradient(90deg, #ffffff 0%, #f9f9f9 100%); background: -moz-linear-gradient(90deg, #ffffff 0%, #f9f9f9 100%); background: linear-gradient(180deg, #ffffff 0%, #f9f9f9 100%); border: 1px solid #CCCCCC; border-radius: 3px 3px 0 0; } .nw-toolbar__item { display: inline-block; vertical-align: top; margin: 0; border-right: 1px solid #DEDEDE; } .nw-toolbar label { line-height: 30px; display: inline-block; padding: 0 6px 0 3px; } .nw-toolbar input[type=checkbox] { vertical-align: -3px; margin-right: -1px; } /** * styling for the editor part: source code (original textarea) and resulting div * * .nw-editor * &__src * &__res * */ .nw-editor { display: table; /* Default when height is not set */ height: 300px; background: #fff; cursor: text; width: 100%; } .nw-editor-container { border: 1px solid #CCCCCC; border-radius: 0 0 3px 3px; position: relative; } .nw-editor-container--with-toolbar { border-top: none; } .nw-editor__res { min-height: 100%; padding: 0 8px; display: table-cell; } .nw-editor__placeholder { padding: 1px 8px; color: lightgray; display: table-cell; width: 100%; } .nw-editor__src, .nw-editor__res { width: 100%; outline: none; box-sizing: border-box; border: none; margin: 0; } .nw-editor__res.disabled { opacity: 0.5; } .nw-editor__src-container { position: absolute; left: 0; top: 0; right: 0; bottom: 0; } .nw-editor__src { height: 100%; resize: none; padding: 0 8px; } .nw-editor--fixed .nw-editor { display: block; overflow-y: auto; } .nw-editor--fixed .nw-editor__res { padding: 1px 8px; display: block; } .nw-invisible { visibility: hidden; } .nw-editor--fixed .nw-invisible { display: none; } .nw-editor.nw-disabled { cursor: default; } /** * styling for toolbar button, has two modifiers: active and type of icon for background * * .nw-button * &--active * &--{button type} * */ .nw-button { -webkit-appearance: none; -moz-appearance: none; appearance: none; display: block; width: 30px; height: 30px; margin: 0; padding: 0; opacity: 0.5; line-height: 30px; background-color: transparent; background-position: center center; background-repeat: no-repeat; border: none; border-radius: 2px; font-size: 0; cursor: pointer; } .nw-button-fa:before { font-size: 12px; font-family: FontAwesome; } .nw-button-fa.bold:before { content: '\\f032'; } .nw-button-fa.italic:before { content: '\\f033'; } .nw-button-fa.list-ul:before { content: '\\f0ca'; } .nw-button-fa.list-ol:before { content: '\\f0cb'; } .nw-button-fa.link:before { content: '\\f0c1'; } .nw-button-fa.font-color:before { content: '\\f031'; } .nw-button-fa.nw-button--source:before { content: '\\f040'; } .nw-button-fa.clear-styles:before { content: '\\f12d'; } .nw-button-mdi:before { vertical-align: middle; font-size: 14px; font-family: \"Material Design Icons\"; } .nw-button-mdi.bold:before { content: '\\f264'; } .nw-button-mdi.italic:before { content: '\\f277'; } .nw-button-mdi.list-ul:before { content: '\\f279'; } .nw-button-mdi.list-ol:before { content: '\\f27B'; } .nw-button-mdi.link:before { content: '\\f339'; } .nw-button-mdi.font-color:before { content: '\\f6D5'; } .nw-button-mdi.nw-button--source:before { content: '\\f3EB'; } .nw-button-mdi.clear-styles:before { content: '\\f1fE'; } .nw-button:focus { outline: none; } .nw-button:hover, .nw-button.nw-button--active { opacity: 1 } .nw-button--active { background-color: #EEEEEE; } .nw-button:disabled { cursor: default; } .nw-button:disabled:hover { opacity: 0.5; } /** * styling & formatting of content inside contenteditable div * * .nw-content * */ .nw-content { padding: 12px; margin: 0; font-family: sans-serif; font-size: 14px; line-height: 24px; } .nw-select { height: 30px; padding: 6px; color: #555; background-color: inherit; border: 0; } .nw-select:disabled { opacity: 0.5; } .nw-select:focus { outline: none; } .nw-button:focus { border-color: lightgray; border-style: solid; } [contenteditable]:empty:before { content: attr(placeholder); color: grey; display: inline-block; }"],
|
315 | providers: [
|
316 | NgxWigToolbarService,
|
317 | {
|
318 | provide: NG_VALUE_ACCESSOR,
|
319 | useExisting: forwardRef(function () { return NgxWigComponent; }),
|
320 | multi: true
|
321 | }
|
322 | ],
|
323 | encapsulation: ViewEncapsulation.None
|
324 | },] },
|
325 | ];
|
326 |
|
327 | NgxWigComponent.ctorParameters = function () { return [
|
328 | { type: NgxWigToolbarService, },
|
329 | ]; };
|
330 | NgxWigComponent.propDecorators = {
|
331 | "content": [{ type: Input },],
|
332 | "placeholder": [{ type: Input },],
|
333 | "buttons": [{ type: Input },],
|
334 | "disabled": [{ type: Input },],
|
335 | "isSourceModeAllowed": [{ type: Input },],
|
336 | "contentChange": [{ type: Output },],
|
337 | "ngxWigEditable": [{ type: ViewChild, args: ['ngWigEditable',] },],
|
338 | };
|
339 | return NgxWigComponent;
|
340 | }());
|
341 |
|
342 |
|
343 |
|
344 |
|
345 |
|
346 | var NgxWigModule = (function () {
|
347 | function NgxWigModule() {
|
348 | }
|
349 | NgxWigModule.decorators = [
|
350 | { type: NgModule, args: [{
|
351 | imports: [
|
352 | CommonModule,
|
353 | FormsModule,
|
354 | ReactiveFormsModule
|
355 | ],
|
356 | declarations: [
|
357 | NgxWigComponent,
|
358 | ],
|
359 | exports: [
|
360 | NgxWigComponent,
|
361 | ],
|
362 | providers: [NgxWigToolbarService]
|
363 | },] },
|
364 | ];
|
365 |
|
366 | NgxWigModule.ctorParameters = function () { return []; };
|
367 | return NgxWigModule;
|
368 | }());
|
369 |
|
370 | export { NgxWigModule, NgxWigComponent, NgxWigToolbarService };
|