Skip to content

Commit 50ffdde

Browse files
committed
INT-2767: Prepare for TinyMCE 6; change license to MIT
1 parent b04addc commit 50ffdde

File tree

7 files changed

+94
-69
lines changed

7 files changed

+94
-69
lines changed

CHANGELOG.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,36 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7-
## [Unreleased]
7+
## 2.0.0
8+
### Changed
9+
- License changed to MIT (from Apache 2) this matches TinyMCE 6 license
10+
- Changed default cloudChannel to `'6'`.
11+
812
### Fixed
913
- Updated dependencies to latest available versions.
1014

11-
## [1.2.0] - 2021-03-11
15+
## 1.2.0 - 2021-03-11
1216
### Fixed
1317
- Updated dependencies to latest available versions.
1418

15-
## [1.1.0] - 2021-01-07
19+
## 1.1.0 - 2021-01-07
1620
### Changed
1721
- Converted demo server app to TypeScript.
1822
- Updated dependencies.
1923
- Added eslint.
2024
- Adopted beehive-flow branching and versioning process/tooling.
2125

22-
## [1.0.2] - 2020-09-22
26+
## 1.0.2 - 2020-09-22
2327
### Changed
2428
- Updated dependencies to latest available versions
2529

26-
## [1.0.1] - 2020-08-31
30+
## 1.0.1 - 2020-08-31
2731
### Added
2832
- Added CDN demo.
2933

3034
### Changed
3135
- Updated README.md
3236

33-
## [1.0.0] - 2020-08-27
37+
## 1.0.0 - 2020-08-27
3438
### Added
3539
- Initial release of web component wrapper around TinyMCE.

Jenkinsfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!groovy
2-
@Library('waluigi@v4.0.0') _
2+
@Library('waluigi@v5.0.0') _
33

44
standardProperties()
55

@@ -12,7 +12,7 @@ node("primary") {
1212
}
1313

1414
stage("dependencies") {
15-
sh "yarn install --frozen-lockfile"
15+
yarnInstall()
1616
}
1717

1818
stage("stamp") {

LICENSE.txt

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
1-
Copyright 2020-present Tiny Technologies, Inc.
1+
MIT License
22

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
3+
Copyright (c) 2022 Ephox Corporation DBA Tiny Technologies, Inc.
64

7-
http://www.apache.org/licenses/LICENSE-2.0
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
811

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.
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"webcomponent"
2222
],
2323
"author": "Tiny Technologies",
24-
"license": "Apache-2.0",
24+
"license": "MIT",
2525
"devDependencies": {
2626
"@ephox/agar": "^7.0.1",
2727
"@ephox/bedrock-client": "^13.0.0",
@@ -42,13 +42,13 @@
4242
"esm": "^3.2.25",
4343
"express": "^4.17.3",
4444
"rollup": "^2.70.1",
45-
"tinymce": "^5.10.0",
45+
"tinymce": "^6.0.0",
4646
"ts-loader": "^9.2.8",
4747
"ts-node": "^10.7.0",
4848
"typescript": "~4.6.2",
4949
"webpack": "^5.70.0"
5050
},
5151
"dependencies": {},
52-
"version": "1.2.1-rc",
52+
"version": "2.0.0-rc",
5353
"name": "@tinymce/tinymce-webcomponent"
5454
}

src/main/ts/component/Editor.ts

Lines changed: 56 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { Resolve, Obj, Fun, Global } from '@ephox/katamari';
2+
import { TinyMCE, Editor } from 'tinymce';
23
import { ScriptLoader } from '../utils/ScriptLoader';
4+
type EditorOptions = Parameters<TinyMCE['init']>[0];
5+
type EventHandler = Parameters<Editor['on']>[1];
36

47
// the advanced config will accept any attributes that start with `config-`
58
// and try to parse them as JSON or resolve them on the Global state.
@@ -11,17 +14,18 @@ enum Status {
1114
Ready
1215
}
1316

14-
const parseJsonResolveGlobals = (value: string): any => {
17+
const parseJsonResolveGlobals = (value: string): unknown => {
1518
try {
1619
return JSON.parse(value);
1720
} catch (_e) { /* ignore */ }
1821
return Resolve.resolve(value);
1922
};
20-
const lookup = (values: Record<string, any>) => (key: string) => Obj.has(values, key) ? values[key] : key;
23+
const isLookupKey = <T extends Record<string, any>, K extends keyof T>(values: T, key: string | K): key is K => Obj.has(values, key);
24+
const lookup = <T extends Record<string, unknown>, K extends keyof T>(values: T) => (key: string | K) => isLookupKey(values, key) ? values[key] : key;
2125

2226
const parseGlobal = Resolve.resolve;
2327
const parseString = Fun.identity;
24-
const parseFalseOrString = lookup({ 'false': false });
28+
const parseFalseOrString = lookup({ 'false': false as const });
2529
const parseBooleanOrString = lookup({ 'true': true, 'false': false });
2630
const parseNumberOrString = (value: string) => /^\d+$/.test(value) ? Number.parseInt(value, 10) : value;
2731

@@ -59,9 +63,9 @@ const configRenames: Record<string, string> = {
5963
class TinyMceEditor extends HTMLElement {
6064
private _status: Status;
6165
private _shadowDom: ShadowRoot;
62-
private _editor: any;
66+
private _editor: Editor | undefined;
6367
private _form: HTMLFormElement | null;
64-
private _eventHandlers: Record<string, any>;
68+
private _eventHandlers: Record<string, EventHandler | undefined>;
6569
private _mutationObserver: MutationObserver;
6670

6771
static get formAssociated() {
@@ -105,17 +109,21 @@ class TinyMceEditor extends HTMLElement {
105109
});
106110
};
107111

108-
private _formDataHandler = (evt: Event) => {
112+
private _formDataHandler = (evt: FormDataEvent): void => {
109113
const name = this.name;
110-
if (name !== null) {
111-
const data = (evt as any).formData as FormData;
112-
data.append(name, this.value);
114+
if (name != null) {
115+
const value = this.value;
116+
if (value != null) {
117+
const data = evt.formData;
118+
data.append(name, value);
119+
}
113120
}
114121
};
115122

116-
private _updateEventAttr(attrKey: string, attrValue: string | null) {
123+
private _updateEventAttr(attrKey: string, attrValue: string | null): void {
117124
const event = attrKey.substring('on-'.length).toLowerCase();
118-
const handler = attrValue !== null ? Resolve.resolve(attrValue) : undefined;
125+
const resolved = attrValue !== null ? Resolve.resolve(attrValue) : undefined;
126+
const handler = typeof resolved === 'function' ? resolved as EventHandler : undefined;
119127
if (this._eventHandlers[event] !== handler) {
120128
if (this._editor && this._eventHandlers[event]) {
121129
this._editor.off(event, this._eventHandlers[event]);
@@ -131,7 +139,7 @@ class TinyMceEditor extends HTMLElement {
131139
}
132140
}
133141

134-
private _updateForm() {
142+
private _updateForm(): void {
135143
if (this.isConnected) {
136144
const formId = this.getAttribute('form');
137145
const form = formId !== null ? this.ownerDocument.querySelector<HTMLFormElement>('form#' + formId) : this.closest('form');
@@ -152,18 +160,18 @@ class TinyMceEditor extends HTMLElement {
152160
}
153161
}
154162

155-
private _getTinymce() {
163+
private _getTinymce(): TinyMCE {
156164
return Global.tinymce;
157165
}
158166

159-
private _getConfig() {
160-
const config: Record<string, unknown> = parseGlobal(this.getAttribute('config') ?? '') ?? {};
167+
private _getConfig(): EditorOptions {
168+
const config: EditorOptions = parseGlobal(this.getAttribute('config') ?? '') ?? {};
161169
for (let i = 0; i < this.attributes.length; i++) {
162170
const attr = this.attributes.item(i);
163171
if (attr !== null) {
164172
if (ADVANCED_CONFIG && attr.name.startsWith('config-')) {
165173
// add to config
166-
const prop = attr.name.substr('config-'.length);
174+
const prop = attr.name.substring('config-'.length);
167175
config[prop] = parseJsonResolveGlobals(attr.value);
168176
} else if (Obj.has(configAttributes, attr.name)) {
169177
const prop = Obj.has(configRenames, attr.name) ? configRenames[attr.name] : attr.name;
@@ -182,22 +190,24 @@ class TinyMceEditor extends HTMLElement {
182190
return config;
183191
}
184192

185-
private _getEventHandlers() {
186-
const handlers: Record<string, any> = {};
193+
private _getEventHandlers(): Record<string, EventHandler> {
194+
const handlers: Record<string, EventHandler> = {};
187195
for (let i = 0; i < this.attributes.length; i++) {
188196
const attr = this.attributes.item(i);
189197
if (attr !== null) {
190198
if (attr.name.toLowerCase().startsWith('on-')) {
191-
const event = attr.name.toLowerCase().substr('on-'.length);
199+
const event = attr.name.toLowerCase().substring('on-'.length);
192200
const handler = Resolve.resolve(attr.value);
193-
handlers[event] = handler;
201+
if (typeof handler === 'function') {
202+
handlers[event] = handler as EventHandler;
203+
}
194204
}
195205
}
196206
}
197207
return handlers;
198208
}
199209

200-
private _doInit() {
210+
private _doInit(): void {
201211
this._status = Status.Initializing;
202212
// load
203213
const target = document.createElement('textarea');
@@ -207,10 +217,10 @@ class TinyMceEditor extends HTMLElement {
207217
}
208218
this._shadowDom.appendChild(target);
209219
const baseConfig = this._getConfig();
210-
const conf = {
220+
const conf: EditorOptions = {
211221
...baseConfig,
212222
target,
213-
setup: (editor: any) => {
223+
setup: (editor: Editor) => {
214224
this._editor = editor;
215225
editor.on('init', (_e: unknown) => {
216226
this._status = Status.Ready;
@@ -219,8 +229,10 @@ class TinyMceEditor extends HTMLElement {
219229
// this assignment ensures the attribute is in sync with the editor
220230
this.readonly = this.readonly;
221231
});
222-
Object.keys(this._eventHandlers).forEach((event) => {
223-
editor.on(event, this._eventHandlers[event]);
232+
Obj.each(this._eventHandlers, (handler, event) => {
233+
if (handler !== undefined) {
234+
editor.on(event, handler);
235+
}
224236
});
225237
if (typeof baseConfig.setup === 'function') {
226238
baseConfig.setup(editor);
@@ -231,18 +243,18 @@ class TinyMceEditor extends HTMLElement {
231243
this._getTinymce().init(conf);
232244
}
233245

234-
private _getTinymceSrc() {
246+
private _getTinymceSrc(): string {
235247
const src = this.getAttribute('src');
236248
if (src) {
237249
return src;
238250
}
239-
const channel = this.getAttribute('channel') ?? '5-stable';
251+
const channel = this.getAttribute('channel') ?? '6';
240252
const apiKey = this.hasAttribute('api-key') ? this.getAttribute('api-key') : 'no-api-key';
241253
return `https://cdn.tiny.cloud/1/${apiKey}/tinymce/${channel}/tinymce.min.js`;
242254

243255
}
244256

245-
private _loadTinyDoInit() {
257+
private _loadTinyDoInit(): void {
246258
if (this._getTinymce()) {
247259
this._doInit();
248260
} else {
@@ -254,7 +266,7 @@ class TinyMceEditor extends HTMLElement {
254266
}
255267
}
256268

257-
attributeChangedCallback(attribute: string, oldValue: string | null, newValue: string | null) {
269+
attributeChangedCallback(attribute: string, oldValue: string | null, newValue: string | null): void {
258270
if (oldValue !== newValue) {
259271
if (attribute === 'form') {
260272
this._updateForm();
@@ -264,13 +276,13 @@ class TinyMceEditor extends HTMLElement {
264276
this.autofocus = newValue !== null;
265277
} else if (attribute === 'placeholder') {
266278
this.placeholder = newValue;
267-
} else if (attribute.toLowerCase().startsWith('on')) {
279+
} else if (attribute.toLowerCase().startsWith('on-')) {
268280
this._updateEventAttr(attribute, newValue);
269281
}
270282
}
271283
}
272284

273-
connectedCallback() {
285+
connectedCallback(): void {
274286
this._eventHandlers = this._getEventHandlers();
275287
this._mutationObserver.observe(this, { attributes: true, childList: false, subtree: false });
276288
this._updateForm();
@@ -279,22 +291,22 @@ class TinyMceEditor extends HTMLElement {
279291
}
280292
}
281293

282-
disconnectedCallback() {
294+
disconnectedCallback(): void {
283295
this._mutationObserver.disconnect();
284296
this._updateForm();
285297
}
286298

287-
get value() {
288-
return this._status === Status.Ready ? this._editor.getContent() : undefined;
299+
get value(): string | null {
300+
return (this._status === Status.Ready ? this._editor?.getContent() : undefined) ?? null;
289301
}
290302

291-
set value(newValue: string) {
292-
if (this._status === Status.Ready) {
293-
this._editor.setContent(newValue);
303+
set value(newValue: string | null) {
304+
if (this._status === Status.Ready && newValue != null) {
305+
this._editor?.setContent(newValue);
294306
}
295307
}
296308

297-
get readonly() {
309+
get readonly(): boolean {
298310
if (this._editor) {
299311
return this._editor.mode.get() === 'readonly';
300312
} else {
@@ -320,13 +332,13 @@ class TinyMceEditor extends HTMLElement {
320332
}
321333
}
322334

323-
get placeholder() {
335+
get placeholder(): string | null {
324336
return this.getAttribute('placeholder');
325337
}
326338

327339
set placeholder(value: string | null) {
328340
if (this._editor) {
329-
const target: HTMLTextAreaElement = this._editor.getElement();
341+
const target = this._editor.getElement();
330342
if (target !== null) {
331343
if (value !== null) {
332344
target.setAttribute('placeholder', value);
@@ -346,7 +358,7 @@ class TinyMceEditor extends HTMLElement {
346358
}
347359
}
348360

349-
get autofocus() {
361+
get autofocus(): boolean {
350362
return this.hasAttribute('autofocus');
351363
}
352364

@@ -362,13 +374,13 @@ class TinyMceEditor extends HTMLElement {
362374
}
363375
}
364376

365-
get form() {
377+
get form(): HTMLFormElement | null {
366378
return this._form;
367379
}
368-
get name() {
380+
get name(): string | null {
369381
return this.getAttribute('name');
370382
}
371-
get type() {
383+
get type(): string {
372384
return this.localName;
373385
}
374386
}

0 commit comments

Comments
 (0)