UNPKG

17.7 kBJavaScriptView Raw
1import { Component, EventEmitter, Input, NgModule, Output, ViewChild, ViewEncapsulation, forwardRef } from '@angular/core';
2import { CommonModule } from '@angular/common';
3import { FormsModule, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms';
4
5/**
6 * @fileoverview added by tsickle
7 * @suppress {checkTypes} checked by tsc
8 */
9var 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 * @param {?} buttons
22 * @return {?}
23 */
24 NgxWigToolbarService.prototype.setButtons = /**
25 * @param {?} buttons
26 * @return {?}
27 */
28 function (buttons) {
29 // if(!angular.isArray(buttons)) {
30 // throw 'Argument "buttons" should be an array';
31 // }
32 this._defaultButtonsList = buttons;
33 };
34
35 /**
36 * @param {?} name
37 * @param {?} title
38 * @param {?} command
39 * @param {?} styleClass
40 * @return {?}
41 */
42 NgxWigToolbarService.prototype.addStandardButton = /**
43 * @param {?} name
44 * @param {?} title
45 * @param {?} command
46 * @param {?} styleClass
47 * @return {?}
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 * @param {?} name
59 * @param {?} pluginName
60 * @return {?}
61 */
62 NgxWigToolbarService.prototype.addCustomButton = /**
63 * @param {?} name
64 * @param {?} pluginName
65 * @return {?}
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 * @param {?=} buttonsList
76 * @return {?}
77 */
78 NgxWigToolbarService.prototype.getToolbarButtons = /**
79 * @param {?=} buttonsList
80 * @return {?}
81 */
82 function (buttonsList) {
83 var _this = this;
84 var /** @type {?} */ buttons = this._defaultButtonsList;
85 var /** @type {?} */ 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 /** @type {?} */ button = Object.assign({}, _this._buttonLibrary[buttonKey]);
97 // button.isActive = () => {return !!this.command && document.queryCommandState(this.command);}
98 toolbarButtons.push(button);
99 });
100 return toolbarButtons;
101 };
102 return NgxWigToolbarService;
103}());
104/**
105 * @param {?} keysString
106 * @return {?}
107 */
108function string2array(keysString) {
109 return keysString.split(',').map(Function.prototype.call, String.prototype.trim);
110}
111
112/**
113 * @fileoverview added by tsickle
114 * @suppress {checkTypes} checked by tsc
115 */
116var 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 // hardcoded icons theme for now
126 this.iconsTheme = "nw-button-mdi";
127 }
128 /**
129 * @return {?}
130 */
131 NgxWigComponent.prototype.toggleEditMode = /**
132 * @return {?}
133 */
134 function () {
135 this.editMode = !this.editMode;
136 };
137 /**
138 * @param {?} command
139 * @param {?} options
140 * @return {?}
141 */
142 NgxWigComponent.prototype.execCommand = /**
143 * @param {?} command
144 * @param {?} options
145 * @return {?}
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 // use insertHtml for `createlink` command to account for IE/Edge purposes, in case there is no selection
161 var /** @type {?} */ 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 * @return {?}
172 */
173 NgxWigComponent.prototype.ngOnInit = /**
174 * @return {?}
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 // view --> model
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 * @param {?} changes
194 * @return {?}
195 */
196 NgxWigComponent.prototype.ngOnChanges = /**
197 * @param {?} changes
198 * @return {?}
199 */
200 function (changes) {
201 if (this.container && changes['content']) {
202 // clear the previous content
203 this.container.innerHTML = '';
204 // add the new content
205 this.pasteHtmlAtCaret(changes['content'].currentValue);
206 }
207 };
208 /**
209 * @param {?} event
210 * @return {?}
211 */
212 NgxWigComponent.prototype.onChange = /**
213 * @param {?} event
214 * @return {?}
215 */
216 function (event) {
217 // model -> view
218 this.container.innerHTML = this.content;
219 this.contentChange.emit(this.content);
220 this.propagateChange(this.content);
221 };
222 /**
223 * @param {?} value
224 * @return {?}
225 */
226 NgxWigComponent.prototype.writeValue = /**
227 * @param {?} value
228 * @return {?}
229 */
230 function (value) {
231 if (value) {
232 this.content = value;
233 this.container.innerHTML = this.content;
234 }
235 };
236 /**
237 * @param {?} fn
238 * @return {?}
239 */
240 NgxWigComponent.prototype.registerOnChange = /**
241 * @param {?} fn
242 * @return {?}
243 */
244 function (fn) {
245 this.propagateChange = fn;
246 };
247 /**
248 * @return {?}
249 */
250 NgxWigComponent.prototype.registerOnTouched = /**
251 * @return {?}
252 */
253 function () { };
254 /**
255 * @return {?}
256 */
257 NgxWigComponent.prototype.shouldShowPlaceholder = /**
258 * @return {?}
259 */
260 function () {
261 return this.placeholder
262 && !this.hasFocus
263 && !this.container.innerText;
264 };
265 /**
266 * @param {?} html
267 * @return {?}
268 */
269 NgxWigComponent.prototype.pasteHtmlAtCaret = /**
270 * @param {?} html
271 * @return {?}
272 */
273 function (html) {
274 var /** @type {?} */ sel, /** @type {?} */ range;
275 if (window.getSelection) {
276 sel = window.getSelection();
277 if (sel.getRangeAt && sel.rangeCount) {
278 range = sel.getRangeAt(0);
279 range.deleteContents();
280 // append the content in a temporary div
281 var /** @type {?} */ el = document.createElement('div');
282 el.innerHTML = html;
283 var /** @type {?} */ frag = document.createDocumentFragment(), /** @type {?} */ node = void 0, /** @type {?} */ lastNode = void 0;
284 while ((node = el.firstChild)) {
285 lastNode = frag.appendChild(node);
286 }
287 range.insertNode(frag);
288 // Preserve the selection
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 * @param {?} isDisabled
301 * @return {?}
302 */
303 NgxWigComponent.prototype.setDisabledState = /**
304 * @param {?} isDisabled
305 * @return {?}
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 /** @nocollapse */
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 * @fileoverview added by tsickle
344 * @suppress {checkTypes} checked by tsc
345 */
346var 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 /** @nocollapse */
366 NgxWigModule.ctorParameters = function () { return []; };
367 return NgxWigModule;
368}());
369
370export { NgxWigModule, NgxWigComponent, NgxWigToolbarService };