@tinymce/tinymce-webcomponent 1.2.1-rc.20210919052935061.sha755c450

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/CHANGELOG.md ADDED
@@ -0,0 +1,35 @@
1
+ # Change log
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+ ### Fixed
9
+ - Updated dependencies to latest available versions.
10
+
11
+ ## [1.2.0] - 2021-03-11
12
+ ### Fixed
13
+ - Updated dependencies to latest available versions.
14
+
15
+ ## [1.1.0] - 2021-01-07
16
+ ### Changed
17
+ - Converted demo server app to TypeScript.
18
+ - Updated dependencies.
19
+ - Added eslint.
20
+ - Adopted beehive-flow branching and versioning process/tooling.
21
+
22
+ ## [1.0.2] - 2020-09-22
23
+ ### Changed
24
+ - Updated dependencies to latest available versions
25
+
26
+ ## [1.0.1] - 2020-08-31
27
+ ### Added
28
+ - Added CDN demo.
29
+
30
+ ### Changed
31
+ - Updated README.md
32
+
33
+ ## [1.0.0] - 2020-08-27
34
+ ### Added
35
+ - Initial release of web component wrapper around TinyMCE.
package/LICENSE.txt ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2020-present Tiny Technologies, Inc.
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,19 @@
1
+
2
+ # Official TinyMCE Web Component
3
+
4
+ Web Components are a set of built-in browser capabilities that let developers create custom HTML elements in a similar manner to what is available in frameworks like React or Angular.
5
+
6
+ Web Components comprise 3 basic capabilities:
7
+ - Shadow DOM
8
+ - Custom Elements
9
+ - HTML Templating
10
+
11
+ Shadow DOM provides the ability to create a "sandboxed" area of a web page, in a similar manner to iframes. An HTML element can have a "shadow root" attached to it, which is a tree of elements that are separate to the main document. Shadow roots are useful for having an area of the document that doesn't inherit styles from the main document. This is particularly handy for rich components like TinyMCE which have their own complex stylesheets and have to fit into any of our customer's web apps.
12
+
13
+ Custom Elements allow a developer to register a new tag/element that can be included in the HTML of the page. The custom element's behaviour is defined in JavaScript code and then registered for use in HTML.
14
+ TinyMCE for Web Components provides the Custom Element, building on the experimental Shadow DOM support added in TinyMCE 5.4.
15
+
16
+ Once the TinyMCE custom element is installed on a web page, creating an editor instance is as simple as adding a `<tinymce-editor></tinymce-editor>` tag to the page. This tag is used in place of calling tinymce.init(). Many of the standard configuration properties can be specified as attributes to this tag, instead of using JavaScript code.
17
+
18
+ TinyMCE for Web Components is available for free under an Apache 2.0 license, and can be installed via NPM. It is compatible with open source TinyMCE, Tiny Cloud, and TinyMCE commercial self-hosted offerings.
19
+ At this stage, TinyMCE for Web Components is an experimental integration - we would love to hear your [feedback](https://github.com/tinymce/tinymce-webcomponent/issues) on how it can be improved.
@@ -0,0 +1,465 @@
1
+ (function () {
2
+ 'use strict';
3
+
4
+ var Global = typeof window !== 'undefined' ? window : Function('return this;')();
5
+
6
+ var path = function (parts, scope) {
7
+ var o = scope !== undefined && scope !== null ? scope : Global;
8
+ for (var i = 0; i < parts.length && o !== undefined && o !== null; ++i) {
9
+ o = o[parts[i]];
10
+ }
11
+ return o;
12
+ };
13
+ var resolve = function (p, scope) {
14
+ var parts = p.split('.');
15
+ return path(parts, scope);
16
+ };
17
+
18
+ var identity = function (x) {
19
+ return x;
20
+ };
21
+
22
+ var hasOwnProperty = Object.hasOwnProperty;
23
+ var has = function (obj, key) {
24
+ return hasOwnProperty.call(obj, key);
25
+ };
26
+
27
+ var unique = 0;
28
+ var generate = function (prefix) {
29
+ var date = new Date();
30
+ var time = date.getTime();
31
+ var random = Math.floor(Math.random() * 1000000000);
32
+ unique++;
33
+ return prefix + '_' + random + unique + String(time);
34
+ };
35
+
36
+ const createState = () => ({
37
+ listeners: [],
38
+ scriptId: generate('tiny-script'),
39
+ scriptLoaded: false
40
+ });
41
+ const CreateScriptLoader = () => {
42
+ let state = createState();
43
+ const injectScriptTag = (scriptId, doc, url, callback) => {
44
+ const scriptTag = doc.createElement('script');
45
+ scriptTag.referrerPolicy = 'origin';
46
+ scriptTag.type = 'application/javascript';
47
+ scriptTag.id = scriptId;
48
+ scriptTag.src = url;
49
+ const handler = () => {
50
+ scriptTag.removeEventListener('load', handler);
51
+ callback();
52
+ };
53
+ scriptTag.addEventListener('load', handler);
54
+ if (doc.head) {
55
+ doc.head.appendChild(scriptTag);
56
+ }
57
+ };
58
+ const load = (doc, url, callback) => {
59
+ if (state.scriptLoaded) {
60
+ callback();
61
+ } else {
62
+ state.listeners.push(callback);
63
+ if (!doc.getElementById(state.scriptId)) {
64
+ injectScriptTag(state.scriptId, doc, url, () => {
65
+ state.listeners.forEach(fn => fn());
66
+ state.scriptLoaded = true;
67
+ });
68
+ }
69
+ }
70
+ };
71
+ const reinitialize = () => {
72
+ state = createState();
73
+ };
74
+ return {
75
+ load,
76
+ reinitialize
77
+ };
78
+ };
79
+ const ScriptLoader = CreateScriptLoader();
80
+
81
+ var Status;
82
+ (function (Status) {
83
+ Status[Status['Raw'] = 0] = 'Raw';
84
+ Status[Status['Initializing'] = 1] = 'Initializing';
85
+ Status[Status['Ready'] = 2] = 'Ready';
86
+ }(Status || (Status = {})));
87
+ const lookup = values => key => has(values, key) ? values[key] : key;
88
+ const parseGlobal = resolve;
89
+ const parseString = identity;
90
+ const parseFalseOrString = lookup({ 'false': false });
91
+ const parseBooleanOrString = lookup({
92
+ 'true': true,
93
+ 'false': false
94
+ });
95
+ const parseNumberOrString = value => /^\d+$/.test(value) ? Number.parseInt(value, 10) : value;
96
+ const configAttributes = {
97
+ setup: parseGlobal,
98
+ toolbar: parseFalseOrString,
99
+ menubar: parseFalseOrString,
100
+ plugins: parseString,
101
+ content_css: parseString,
102
+ content_style: parseString,
103
+ width: parseNumberOrString,
104
+ height: parseNumberOrString,
105
+ toolbar_mode: parseString,
106
+ contextmenu: parseFalseOrString,
107
+ quickbars_insert_toolbar: parseFalseOrString,
108
+ quickbars_selection_toolbar: parseFalseOrString,
109
+ powerpaste_word_import: parseString,
110
+ powerpaste_html_import: parseString,
111
+ powerpaste_allow_local_images: parseBooleanOrString,
112
+ resize: parseBooleanOrString,
113
+ skin: parseString,
114
+ skin_url: parseString,
115
+ images_upload_url: parseString,
116
+ images_upload_handler: parseGlobal,
117
+ images_upload_base_path: parseString,
118
+ images_upload_credentials: parseBooleanOrString,
119
+ images_reuse_filename: parseBooleanOrString,
120
+ icons: parseString,
121
+ icons_url: parseString
122
+ };
123
+ const configRenames = {};
124
+ class TinyMceEditor extends HTMLElement {
125
+ constructor() {
126
+ super();
127
+ this._eventAttrHandler = records => {
128
+ records.forEach(record => {
129
+ var _a;
130
+ if (record.type === 'attributes' && record.target === this && ((_a = record.attributeName) === null || _a === void 0 ? void 0 : _a.toLowerCase().startsWith('on-'))) {
131
+ this._updateEventAttr(record.attributeName, this.getAttribute(record.attributeName));
132
+ }
133
+ });
134
+ };
135
+ this._formDataHandler = evt => {
136
+ const name = this.name;
137
+ if (name !== null) {
138
+ const data = evt.formData;
139
+ data.append(name, this.value);
140
+ }
141
+ };
142
+ this._status = Status.Raw;
143
+ this._shadowDom = this.attachShadow({ mode: 'open' });
144
+ this._form = null;
145
+ this._eventHandlers = {};
146
+ this._mutationObserver = new MutationObserver(this._eventAttrHandler);
147
+ }
148
+ static get formAssociated() {
149
+ return true;
150
+ }
151
+ static get observedAttributes() {
152
+ const nativeEvents = [
153
+ 'on-BeforePaste',
154
+ 'on-Blur',
155
+ 'on-Click',
156
+ 'on-ContextMenu',
157
+ 'on-Copy',
158
+ 'on-Cut',
159
+ 'on-Dblclick',
160
+ 'on-Drag',
161
+ 'on-DragDrop',
162
+ 'on-DragEnd',
163
+ 'on-DragGesture',
164
+ 'on-DragOver',
165
+ 'on-Drop',
166
+ 'on-Focus',
167
+ 'on-FocusIn',
168
+ 'on-FocusOut',
169
+ 'on-KeyDown',
170
+ 'on-KeyPress',
171
+ 'on-KeyUp',
172
+ 'on-MouseDown',
173
+ 'on-MouseEnter',
174
+ 'on-MouseLeave',
175
+ 'on-MouseMove',
176
+ 'on-MouseOut',
177
+ 'on-MouseOver',
178
+ 'on-MouseUp',
179
+ 'on-Paste',
180
+ 'on-SelectionChange'
181
+ ];
182
+ const tinyEvents = [
183
+ 'on-Activate',
184
+ 'on-AddUndo',
185
+ 'on-BeforeAddUndo',
186
+ 'on-BeforeExecCommand',
187
+ 'on-BeforeGetContent',
188
+ 'on-BeforeRenderUI',
189
+ 'on-BeforeSetContent',
190
+ 'on-Change',
191
+ 'on-ClearUndos',
192
+ 'on-Deactivate',
193
+ 'on-Dirty',
194
+ 'on-ExecCommand',
195
+ 'on-GetContent',
196
+ 'on-Hide',
197
+ 'on-Init',
198
+ 'on-LoadContent',
199
+ 'on-NodeChange',
200
+ 'on-PostProcess',
201
+ 'on-PostRender',
202
+ 'on-PreProcess',
203
+ 'on-ProgressState',
204
+ 'on-Redo',
205
+ 'on-Remove',
206
+ 'on-Reset',
207
+ 'on-SaveContent',
208
+ 'on-SetAttrib',
209
+ 'on-ObjectResizeStart',
210
+ 'on-ObjectResized',
211
+ 'on-ObjectSelected',
212
+ 'on-SetContent',
213
+ 'on-Show',
214
+ 'on-Submit',
215
+ 'on-Undo',
216
+ 'on-VisualAid'
217
+ ];
218
+ return [
219
+ 'form',
220
+ 'readonly',
221
+ 'autofocus',
222
+ 'placeholder'
223
+ ].concat(nativeEvents).concat(tinyEvents);
224
+ }
225
+ _updateEventAttr(attrKey, attrValue) {
226
+ const event = attrKey.substring('on-'.length).toLowerCase();
227
+ const handler = attrValue !== null ? resolve(attrValue) : undefined;
228
+ if (this._eventHandlers[event] !== handler) {
229
+ if (this._editor && this._eventHandlers[event]) {
230
+ this._editor.off(event, this._eventHandlers[event]);
231
+ }
232
+ if (handler) {
233
+ if (this._editor) {
234
+ this._editor.on(event, handler);
235
+ }
236
+ this._eventHandlers[event] = handler;
237
+ } else {
238
+ delete this._eventHandlers[event];
239
+ }
240
+ }
241
+ }
242
+ _updateForm() {
243
+ if (this.isConnected) {
244
+ const formId = this.getAttribute('form');
245
+ const form = formId !== null ? this.ownerDocument.querySelector('form#' + formId) : this.closest('form');
246
+ if (this._form !== form) {
247
+ if (this._form !== null) {
248
+ this._form.removeEventListener('formdata', this._formDataHandler);
249
+ }
250
+ this._form = form;
251
+ if (this._form !== null) {
252
+ this._form.addEventListener('formdata', this._formDataHandler);
253
+ }
254
+ }
255
+ } else {
256
+ if (this._form !== null) {
257
+ this._form.removeEventListener('formdata', this._formDataHandler);
258
+ this._form = null;
259
+ }
260
+ }
261
+ }
262
+ _getTinymce() {
263
+ return Global.tinymce;
264
+ }
265
+ _getConfig() {
266
+ var _a, _b;
267
+ const config = (_b = parseGlobal((_a = this.getAttribute('config')) !== null && _a !== void 0 ? _a : '')) !== null && _b !== void 0 ? _b : {};
268
+ for (let i = 0; i < this.attributes.length; i++) {
269
+ const attr = this.attributes.item(i);
270
+ if (attr !== null) {
271
+ if (has(configAttributes, attr.name)) {
272
+ const prop = has(configRenames, attr.name) ? configRenames[attr.name] : attr.name;
273
+ config[prop] = configAttributes[attr.name](attr.value);
274
+ }
275
+ }
276
+ }
277
+ if (this.readonly) {
278
+ config.readonly = true;
279
+ }
280
+ if (this.autofocus) {
281
+ config.auto_focus = true;
282
+ }
283
+ delete config.target;
284
+ delete config.selector;
285
+ return config;
286
+ }
287
+ _getEventHandlers() {
288
+ const handlers = {};
289
+ for (let i = 0; i < this.attributes.length; i++) {
290
+ const attr = this.attributes.item(i);
291
+ if (attr !== null) {
292
+ if (attr.name.toLowerCase().startsWith('on-')) {
293
+ const event = attr.name.toLowerCase().substr('on-'.length);
294
+ const handler = resolve(attr.value);
295
+ handlers[event] = handler;
296
+ }
297
+ }
298
+ }
299
+ return handlers;
300
+ }
301
+ _doInit() {
302
+ var _a;
303
+ this._status = Status.Initializing;
304
+ const target = document.createElement('textarea');
305
+ target.value = (_a = this.textContent) !== null && _a !== void 0 ? _a : '';
306
+ if (this.placeholder !== null) {
307
+ target.placeholder = this.placeholder;
308
+ }
309
+ this._shadowDom.appendChild(target);
310
+ const baseConfig = this._getConfig();
311
+ const conf = Object.assign(Object.assign({}, baseConfig), {
312
+ target,
313
+ setup: editor => {
314
+ this._editor = editor;
315
+ editor.on('init', _e => {
316
+ this._status = Status.Ready;
317
+ });
318
+ editor.on('SwitchMode', _e => {
319
+ this.readonly = this.readonly;
320
+ });
321
+ Object.keys(this._eventHandlers).forEach(event => {
322
+ editor.on(event, this._eventHandlers[event]);
323
+ });
324
+ if (typeof baseConfig.setup === 'function') {
325
+ baseConfig.setup(editor);
326
+ }
327
+ }
328
+ });
329
+ this._getTinymce().init(conf);
330
+ }
331
+ _getTinymceSrc() {
332
+ var _a;
333
+ const src = this.getAttribute('src');
334
+ if (src) {
335
+ return src;
336
+ }
337
+ const channel = (_a = this.getAttribute('channel')) !== null && _a !== void 0 ? _a : '5-stable';
338
+ const apiKey = this.hasAttribute('api-key') ? this.getAttribute('api-key') : 'no-api-key';
339
+ return `https://cdn.tiny.cloud/1/${ apiKey }/tinymce/${ channel }/tinymce.min.js`;
340
+ }
341
+ _loadTinyDoInit() {
342
+ if (this._getTinymce()) {
343
+ this._doInit();
344
+ } else {
345
+ ScriptLoader.load(this.ownerDocument, this._getTinymceSrc(), () => this._doInit());
346
+ }
347
+ }
348
+ attributeChangedCallback(attribute, oldValue, newValue) {
349
+ if (oldValue !== newValue) {
350
+ if (attribute === 'form') {
351
+ this._updateForm();
352
+ } else if (attribute === 'readonly') {
353
+ this.readonly = newValue !== null;
354
+ } else if (attribute === 'autofocus') {
355
+ this.autofocus = newValue !== null;
356
+ } else if (attribute === 'placeholder') {
357
+ this.placeholder = newValue;
358
+ } else if (attribute.toLowerCase().startsWith('on')) {
359
+ this._updateEventAttr(attribute, newValue);
360
+ }
361
+ }
362
+ }
363
+ connectedCallback() {
364
+ this._eventHandlers = this._getEventHandlers();
365
+ this._mutationObserver.observe(this, {
366
+ attributes: true,
367
+ childList: false,
368
+ subtree: false
369
+ });
370
+ this._updateForm();
371
+ if (this._status === Status.Raw) {
372
+ this._loadTinyDoInit();
373
+ }
374
+ }
375
+ disconnectedCallback() {
376
+ this._mutationObserver.disconnect();
377
+ this._updateForm();
378
+ }
379
+ get value() {
380
+ return this._status === Status.Ready ? this._editor.getContent() : undefined;
381
+ }
382
+ set value(newValue) {
383
+ if (this._status === Status.Ready) {
384
+ this._editor.setContent(newValue);
385
+ }
386
+ }
387
+ get readonly() {
388
+ if (this._editor) {
389
+ return this._editor.mode.get() === 'readonly';
390
+ } else {
391
+ return this.hasAttribute('readonly');
392
+ }
393
+ }
394
+ set readonly(value) {
395
+ if (value) {
396
+ if (this._editor && this._editor.mode.get() !== 'readonly') {
397
+ this._editor.mode.set('readonly');
398
+ }
399
+ if (!this.hasAttribute('readonly')) {
400
+ this.setAttribute('readonly', '');
401
+ }
402
+ } else {
403
+ if (this._editor && this._editor.mode.get() === 'readonly') {
404
+ this._editor.mode.set('design');
405
+ }
406
+ if (this.hasAttribute('readonly')) {
407
+ this.removeAttribute('readonly');
408
+ }
409
+ }
410
+ }
411
+ get placeholder() {
412
+ return this.getAttribute('placeholder');
413
+ }
414
+ set placeholder(value) {
415
+ if (this._editor) {
416
+ const target = this._editor.getElement();
417
+ if (target !== null) {
418
+ if (value !== null) {
419
+ target.setAttribute('placeholder', value);
420
+ } else {
421
+ target.removeAttribute('placeholder');
422
+ }
423
+ }
424
+ }
425
+ if (value !== null) {
426
+ if (this.getAttribute('placeholder') !== value) {
427
+ this.setAttribute('placeholder', value);
428
+ }
429
+ } else {
430
+ if (this.hasAttribute('placeholder')) {
431
+ this.removeAttribute('placeholder');
432
+ }
433
+ }
434
+ }
435
+ get autofocus() {
436
+ return this.hasAttribute('autofocus');
437
+ }
438
+ set autofocus(value) {
439
+ if (value) {
440
+ if (!this.hasAttribute('autofocus')) {
441
+ this.setAttribute('autofocus', '');
442
+ }
443
+ } else {
444
+ if (this.hasAttribute('autofocus')) {
445
+ this.removeAttribute('autofocus');
446
+ }
447
+ }
448
+ }
449
+ get form() {
450
+ return this._form;
451
+ }
452
+ get name() {
453
+ return this.getAttribute('name');
454
+ }
455
+ get type() {
456
+ return this.localName;
457
+ }
458
+ }
459
+ var Editor = () => {
460
+ window.customElements.define('tinymce-editor', TinyMceEditor);
461
+ };
462
+
463
+ Editor();
464
+
465
+ }());
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "description": "Official TinyMCE Web Component",
3
+ "repository": {
4
+ "url": "https://github.com/tinymce/tinymce-webcomponent"
5
+ },
6
+ "files": [
7
+ "dist",
8
+ "CHANGELOG.md",
9
+ "README.md",
10
+ "LICENSE.txt"
11
+ ],
12
+ "main": "dist/tinymce-webcomponent.js",
13
+ "scripts": {
14
+ "test": "bedrock-auto -b chrome-headless -d src/test/ts",
15
+ "build": "tsc -p ./tsconfig.json && rollup -c rollup.config.js",
16
+ "lint": "yarn eslint src/**/*.ts",
17
+ "serve": "yarn ts-node -r esm src/demo/ts/Server.ts"
18
+ },
19
+ "keywords": [
20
+ "TinyMCE",
21
+ "webcomponent"
22
+ ],
23
+ "author": "Tiny Technologies",
24
+ "license": "Apache-2.0",
25
+ "devDependencies": {
26
+ "@ephox/agar": "^5.3.1",
27
+ "@ephox/bedrock-client": "^11.3.0",
28
+ "@ephox/bedrock-server": "^11.3.0",
29
+ "@ephox/katamari": "^7.2.1",
30
+ "@ephox/sugar": "^7.1.3",
31
+ "@ephox/swag": "^4.3.1",
32
+ "@tinymce/beehive-flow": "^0.15.0",
33
+ "@tinymce/eslint-plugin": "^1.8.2",
34
+ "@types/esm": "^3.2.0",
35
+ "@types/express": "^4.17.12",
36
+ "@types/node": "^15.12.2",
37
+ "eslint": "^7.28.0",
38
+ "esm": "^3.2.25",
39
+ "express": "^4.17.1",
40
+ "rollup": "^2.51.1",
41
+ "tinymce": "^5.7.1",
42
+ "ts-loader": "^9.2.3",
43
+ "ts-node": "^10.0.0",
44
+ "typescript": "~4.2.4"
45
+ },
46
+ "dependencies": {},
47
+ "version": "1.2.1-rc.20210919052935061.sha755c450",
48
+ "name": "@tinymce/tinymce-webcomponent"
49
+ }