From b4f41ec8577846561d57ba64b5ddf6079a82a7de Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Thu, 5 Nov 2020 10:50:47 +0100 Subject: [PATCH] Convert `Ui/Redactor/Spoiler` to TypeScript --- .../WoltLabSuite/Core/Ui/Redactor/Spoiler.js | 197 ++++++++-------- .../ts/WoltLabSuite/Core/Ui/Redactor/Code.ts | 4 +- .../WoltLabSuite/Core/Ui/Redactor/Spoiler.js | 214 ------------------ .../WoltLabSuite/Core/Ui/Redactor/Spoiler.ts | 201 ++++++++++++++++ 4 files changed, 293 insertions(+), 323 deletions(-) delete mode 100644 wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/Spoiler.js create mode 100644 wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/Spoiler.ts diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Redactor/Spoiler.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Redactor/Spoiler.js index 3ef74dae6e..c7fdbbefaf 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Redactor/Spoiler.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Redactor/Spoiler.js @@ -2,176 +2,159 @@ * Manages spoilers. * * @author Alexander Ebert - * @copyright 2001-2019 WoltLab GmbH + * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * @module WoltLabSuite/Core/Ui/Redactor/Spoiler */ -define(['EventHandler', 'EventKey', 'Language', 'StringUtil', 'Dom/Util', 'Ui/Dialog', './PseudoHeader'], function (EventHandler, EventKey, Language, StringUtil, DomUtil, UiDialog, UiRedactorPseudoHeader) { +define(["require", "exports", "tslib", "../../Core", "../../Dom/Util", "../../Event/Handler", "../../Language", "../Dialog", "./PseudoHeader"], function (require, exports, tslib_1, Core, Util_1, EventHandler, Language, Dialog_1, UiRedactorPseudoHeader) { "use strict"; - if (!COMPILER_TARGET_DEFAULT) { - var Fake = function () { }; - Fake.prototype = { - init: function () { }, - _bbcodeSpoiler: function () { }, - _observeLoad: function () { }, - _edit: function () { }, - _setTitle: function () { }, - _delete: function () { }, - _dialogSetup: function () { }, - _dialogSubmit: function () { } - }; - return Fake; - } - var _headerHeight = 0; - /** - * @param {Object} editor editor instance - * @constructor - */ - function UiRedactorSpoiler(editor) { this.init(editor); } - UiRedactorSpoiler.prototype = { + Core = tslib_1.__importStar(Core); + Util_1 = tslib_1.__importDefault(Util_1); + EventHandler = tslib_1.__importStar(EventHandler); + Language = tslib_1.__importStar(Language); + Dialog_1 = tslib_1.__importDefault(Dialog_1); + UiRedactorPseudoHeader = tslib_1.__importStar(UiRedactorPseudoHeader); + let _headerHeight = 0; + class UiRedactorSpoiler { /** * Initializes the spoiler management. - * - * @param {Object} editor editor instance */ - init: function (editor) { + constructor(editor) { + this._spoiler = null; this._editor = editor; this._elementId = this._editor.$element[0].id; - this._spoiler = null; - EventHandler.add('com.woltlab.wcf.redactor2', 'bbcode_spoiler_' + this._elementId, this._bbcodeSpoiler.bind(this)); - EventHandler.add('com.woltlab.wcf.redactor2', 'observe_load_' + this._elementId, this._observeLoad.bind(this)); - // static bind to ensure that removing works - this._callbackEdit = this._edit.bind(this); + EventHandler.add("com.woltlab.wcf.redactor2", `bbcode_spoiler_${this._elementId}`, (data) => this._bbcodeSpoiler(data)); + EventHandler.add("com.woltlab.wcf.redactor2", `observe_load_${this._elementId}`, () => this._observeLoad()); // bind listeners on init this._observeLoad(); - }, + } /** * Intercepts the insertion of `[spoiler]` tags and uses * the custom `` element instead. - * - * @param {Object} data event data - * @protected */ - _bbcodeSpoiler: function (data) { + _bbcodeSpoiler(data) { data.cancel = true; - this._editor.button.toggle({}, 'woltlab-spoiler', 'func', 'block.format'); - var spoiler = this._editor.selection.block(); + this._editor.button.toggle({}, "woltlab-spoiler", "func", "block.format"); + let spoiler = this._editor.selection.block(); if (spoiler) { // iOS Safari might set the caret inside the spoiler. - if (spoiler.nodeName === 'P') { - spoiler = spoiler.parentNode; + if (spoiler.nodeName === "P") { + spoiler = spoiler.parentElement; } - if (spoiler.nodeName === 'WOLTLAB-SPOILER') { + if (spoiler.nodeName === "WOLTLAB-SPOILER") { this._setTitle(spoiler); - spoiler.addEventListener('click', this._callbackEdit); + spoiler.addEventListener("click", (ev) => this._edit(ev)); // work-around for Safari this._editor.caret.end(spoiler); } } - }, + } /** * Binds event listeners and sets quote title on both editor * initialization and when switching back from code view. - * - * @protected */ - _observeLoad: function () { - elBySelAll('woltlab-spoiler', this._editor.$editor[0], (function (spoiler) { - spoiler.addEventListener('mousedown', this._callbackEdit); + _observeLoad() { + this._editor.$editor[0].querySelectorAll("woltlab-spoiler").forEach((spoiler) => { + spoiler.addEventListener("mousedown", (ev) => this._edit(ev)); this._setTitle(spoiler); - }).bind(this)); - }, + }); + } /** * Opens the dialog overlay to edit the spoiler's properties. - * - * @param {Event} event event object - * @protected */ - _edit: function (event) { - var spoiler = event.currentTarget; + _edit(event) { + const spoiler = event.currentTarget; if (_headerHeight === 0) { _headerHeight = UiRedactorPseudoHeader.getHeight(spoiler); } // check if the click hit the header - var offset = DomUtil.offset(spoiler); - if (event.pageY > offset.top && event.pageY < (offset.top + _headerHeight)) { + const offset = Util_1.default.offset(spoiler); + if (event.pageY > offset.top && event.pageY < offset.top + _headerHeight) { event.preventDefault(); this._editor.selection.save(); this._spoiler = spoiler; - UiDialog.open(this); + Dialog_1.default.open(this); } - }, + } /** * Saves the changes to the spoiler's properties. * * @protected */ - _dialogSubmit: function () { - elData(this._spoiler, 'label', elById('redactor-spoiler-' + this._elementId + '-label').value); - this._setTitle(this._spoiler); - this._editor.caret.after(this._spoiler); - UiDialog.close(this); - }, + _dialogSubmit() { + const spoiler = this._spoiler; + const label = document.getElementById("redactor-spoiler-" + this._elementId + "-label"); + spoiler.dataset.label = label.value; + this._setTitle(spoiler); + this._editor.caret.after(spoiler); + Dialog_1.default.close(this); + } /** * Sets or updates the spoiler's header title. - * - * @param {Element} spoiler spoiler element - * @protected */ - _setTitle: function (spoiler) { - var title = Language.get('wcf.editor.spoiler.title', { label: elData(spoiler, 'label') }); - if (elData(spoiler, 'title') !== title) { - elData(spoiler, 'title', title); + _setTitle(spoiler) { + const title = Language.get("wcf.editor.spoiler.title", { label: spoiler.dataset.label || "" }); + if (spoiler.dataset.title !== title) { + spoiler.dataset.title = title; } - }, - _delete: function (event) { + } + _delete(event) { event.preventDefault(); - var caretEnd = this._spoiler.nextElementSibling || this._spoiler.previousElementSibling; - if (caretEnd === null && this._spoiler.parentNode !== this._editor.core.editor()[0]) { - caretEnd = this._spoiler.parentNode; + const spoiler = this._spoiler; + let caretEnd = spoiler.nextElementSibling || spoiler.previousElementSibling; + if (caretEnd === null && spoiler.parentElement !== this._editor.core.editor()[0]) { + caretEnd = spoiler.parentElement; } if (caretEnd === null) { - this._editor.code.set(''); + this._editor.code.set(""); this._editor.focus.end(); } else { - elRemove(this._spoiler); + spoiler.remove(); this._editor.caret.end(caretEnd); } - UiDialog.close(this); - }, - _dialogSetup: function () { - var id = 'redactor-spoiler-' + this._elementId, idButtonDelete = id + '-button-delete', idButtonSave = id + '-button-save', idLabel = id + '-label'; + Dialog_1.default.close(this); + } + _dialogSetup() { + const id = `redactor-spoiler-${this._elementId}`; + const idButtonDelete = `${id}-button-delete`; + const idButtonSave = `${id}-button-save`; + const idLabel = `${id}-label`; return { id: id, options: { - onClose: (function () { + onClose: () => { this._editor.selection.restore(); - UiDialog.destroy(this); - }).bind(this), - onSetup: (function () { - elById(idButtonDelete).addEventListener('click', this._delete.bind(this)); - }).bind(this), - onShow: (function () { - elById(idLabel).value = elData(this._spoiler, 'label'); - }).bind(this), - title: Language.get('wcf.editor.spoiler.edit') + Dialog_1.default.destroy(this); + }, + onSetup: () => { + const button = document.getElementById(idButtonDelete); + button.addEventListener("click", (ev) => this._delete(ev)); + }, + onShow: () => { + const label = document.getElementById(idLabel); + label.value = this._spoiler.dataset.label || ""; + }, + title: Language.get("wcf.editor.spoiler.edit"), }, - source: '
' - + '
' - + '
' - + '
' - + '' - + '' + Language.get('wcf.editor.spoiler.label.description') + '' - + '
' - + '
' - + '
' - + '
' - + '' - + '' - + '
' + source: `
+
+
+ +
+
+ + ${Language.get("wcf.editor.spoiler.label.description")} +
+
+
+
+ + +
`, }; } - }; + } + Core.enableLegacyInheritance(UiRedactorSpoiler); return UiRedactorSpoiler; }); diff --git a/wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/Code.ts b/wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/Code.ts index a2cb0fa107..80abe05afc 100644 --- a/wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/Code.ts +++ b/wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/Code.ts @@ -14,7 +14,7 @@ import * as Language from "../../Language"; import * as StringUtil from "../../StringUtil"; import UiDialog from "../Dialog"; import { DialogCallbackObject, DialogCallbackSetup } from "../Dialog/Data"; -import { RedactorEditor } from "./Editor"; +import { RedactorEditor, WoltLabEventData } from "./Editor"; import * as UiRedactorPseudoHeader from "./PseudoHeader"; import PrismMeta from "../../prism-meta"; @@ -51,7 +51,7 @@ class UiRedactorCode implements DialogCallbackObject { /** * Intercepts the insertion of `[code]` tags and uses a native `
` instead.
    */
-  protected _bbcodeCode(data: { cancel: boolean }): void {
+  protected _bbcodeCode(data: WoltLabEventData): void {
     data.cancel = true;
 
     let pre = this._editor.selection.block();
diff --git a/wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/Spoiler.js b/wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/Spoiler.js
deleted file mode 100644
index 2c71b30aa7..0000000000
--- a/wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/Spoiler.js
+++ /dev/null
@@ -1,214 +0,0 @@
-/**
- * Manages spoilers.
- *
- * @author      Alexander Ebert
- * @copyright	2001-2019 WoltLab GmbH
- * @license     GNU Lesser General Public License 
- * @module      WoltLabSuite/Core/Ui/Redactor/Spoiler
- */
-define(['EventHandler', 'EventKey', 'Language', 'StringUtil', 'Dom/Util', 'Ui/Dialog', './PseudoHeader'], function (EventHandler, EventKey, Language, StringUtil, DomUtil, UiDialog, UiRedactorPseudoHeader) {
-	"use strict";
-	
-	if (!COMPILER_TARGET_DEFAULT) {
-		var Fake = function() {};
-		Fake.prototype = {
-			init: function() {},
-			_bbcodeSpoiler: function() {},
-			_observeLoad: function() {},
-			_edit: function() {},
-			_setTitle: function() {},
-			_delete: function() {},
-			_dialogSetup: function() {},
-			_dialogSubmit: function() {}
-		};
-		return Fake;
-	}
-	
-	var _headerHeight = 0;
-	
-	/**
-	 * @param       {Object}        editor  editor instance
-	 * @constructor
-	 */
-	function UiRedactorSpoiler(editor) { this.init(editor); }
-	UiRedactorSpoiler.prototype = {
-		/**
-		 * Initializes the spoiler management.
-		 * 
-		 * @param       {Object}        editor  editor instance
-		 */
-		init: function(editor) {
-			this._editor = editor;
-			this._elementId = this._editor.$element[0].id;
-			this._spoiler = null;
-			
-			EventHandler.add('com.woltlab.wcf.redactor2', 'bbcode_spoiler_' + this._elementId, this._bbcodeSpoiler.bind(this));
-			EventHandler.add('com.woltlab.wcf.redactor2', 'observe_load_' + this._elementId, this._observeLoad.bind(this));
-			
-			// static bind to ensure that removing works
-			this._callbackEdit = this._edit.bind(this);
-			
-			// bind listeners on init
-			this._observeLoad();
-		},
-		
-		/**
-		 * Intercepts the insertion of `[spoiler]` tags and uses
-		 * the custom `` element instead.
-		 * 
-		 * @param       {Object}        data    event data
-		 * @protected
-		 */
-		_bbcodeSpoiler: function(data) {
-			data.cancel = true;
-			
-			this._editor.button.toggle({}, 'woltlab-spoiler', 'func', 'block.format');
-			
-			var spoiler = this._editor.selection.block();
-			if (spoiler) {
-				// iOS Safari might set the caret inside the spoiler.
-				if (spoiler.nodeName === 'P') {
-					spoiler = spoiler.parentNode;
-				}
-
-				if (spoiler.nodeName === 'WOLTLAB-SPOILER') {
-					this._setTitle(spoiler);
-
-					spoiler.addEventListener('click', this._callbackEdit);
-
-					// work-around for Safari
-					this._editor.caret.end(spoiler);
-				}
-			}
-		},
-		
-		/**
-		 * Binds event listeners and sets quote title on both editor
-		 * initialization and when switching back from code view.
-		 * 
-		 * @protected
-		 */
-		_observeLoad: function() {
-			elBySelAll('woltlab-spoiler', this._editor.$editor[0], (function(spoiler) {
-				spoiler.addEventListener('mousedown', this._callbackEdit);
-				this._setTitle(spoiler);
-			}).bind(this));
-		},
-		
-		/**
-		 * Opens the dialog overlay to edit the spoiler's properties.
-		 * 
-		 * @param       {Event}         event           event object
-		 * @protected
-		 */
-		_edit: function(event) {
-			var spoiler = event.currentTarget;
-			
-			if (_headerHeight === 0) {
-				_headerHeight = UiRedactorPseudoHeader.getHeight(spoiler);
-			}
-			
-			// check if the click hit the header
-			var offset = DomUtil.offset(spoiler);
-			if (event.pageY > offset.top && event.pageY < (offset.top + _headerHeight)) {
-				event.preventDefault();
-				
-				this._editor.selection.save();
-				this._spoiler = spoiler;
-				
-				UiDialog.open(this);
-			}
-		},
-		
-		/**
-		 * Saves the changes to the spoiler's properties.
-		 * 
-		 * @protected
-		 */
-		_dialogSubmit: function() {
-			elData(this._spoiler, 'label', elById('redactor-spoiler-' + this._elementId + '-label').value);
-			
-			this._setTitle(this._spoiler);
-			this._editor.caret.after(this._spoiler);
-			
-			UiDialog.close(this);
-		},
-		
-		/**
-		 * Sets or updates the spoiler's header title.
-		 * 
-		 * @param       {Element}       spoiler     spoiler element
-		 * @protected
-		 */
-		_setTitle: function(spoiler) {
-			var title = Language.get('wcf.editor.spoiler.title', { label: elData(spoiler, 'label') });
-			
-			if (elData(spoiler, 'title') !== title) {
-				elData(spoiler, 'title', title);
-			}
-		},
-		
-		_delete: function (event) {
-			event.preventDefault();
-			
-			var caretEnd = this._spoiler.nextElementSibling || this._spoiler.previousElementSibling;
-			if (caretEnd === null && this._spoiler.parentNode !== this._editor.core.editor()[0]) {
-				caretEnd = this._spoiler.parentNode;
-			}
-			
-			if (caretEnd === null) {
-				this._editor.code.set('');
-				this._editor.focus.end();
-			}
-			else {
-				elRemove(this._spoiler);
-				this._editor.caret.end(caretEnd);
-			}
-			
-			UiDialog.close(this);
-		},
-		
-		_dialogSetup: function() {
-			var id = 'redactor-spoiler-' + this._elementId,
-			    idButtonDelete = id + '-button-delete',
-			    idButtonSave = id + '-button-save',
-			    idLabel = id + '-label';
-			
-			return {
-				id: id,
-				options: {
-					onClose: (function () {
-						this._editor.selection.restore();
-						
-						UiDialog.destroy(this);
-					}).bind(this),
-					
-					onSetup: (function() {
-						elById(idButtonDelete).addEventListener('click', this._delete.bind(this));
-					}).bind(this),
-					
-					onShow: (function() {
-						elById(idLabel).value = elData(this._spoiler, 'label');
-					}).bind(this),
-					
-					title: Language.get('wcf.editor.spoiler.edit')
-				},
-				source: '
' - + '
' - + '
' - + '
' - + '' - + '' + Language.get('wcf.editor.spoiler.label.description') + '' - + '
' - + '
' - + '
' - + '
' - + '' - + '' - + '
' - }; - } - }; - - return UiRedactorSpoiler; -}); diff --git a/wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/Spoiler.ts b/wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/Spoiler.ts new file mode 100644 index 0000000000..f6e760cbcd --- /dev/null +++ b/wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/Spoiler.ts @@ -0,0 +1,201 @@ +/** + * Manages spoilers. + * + * @author Alexander Ebert + * @copyright 2001-2019 WoltLab GmbH + * @license GNU Lesser General Public License + * @module WoltLabSuite/Core/Ui/Redactor/Spoiler + */ + +import * as Core from "../../Core"; +import { DialogCallbackObject, DialogCallbackSetup } from "../Dialog/Data"; +import DomUtil from "../../Dom/Util"; +import * as EventHandler from "../../Event/Handler"; +import * as Language from "../../Language"; +import UiDialog from "../Dialog"; +import { RedactorEditor, WoltLabEventData } from "./Editor"; +import * as UiRedactorPseudoHeader from "./PseudoHeader"; + +let _headerHeight = 0; + +class UiRedactorSpoiler implements DialogCallbackObject { + protected readonly _editor: RedactorEditor; + protected readonly _elementId: string; + protected _spoiler: HTMLElement | null = null; + + /** + * Initializes the spoiler management. + */ + constructor(editor: RedactorEditor) { + this._editor = editor; + this._elementId = this._editor.$element[0].id; + + EventHandler.add("com.woltlab.wcf.redactor2", `bbcode_spoiler_${this._elementId}`, (data) => + this._bbcodeSpoiler(data), + ); + EventHandler.add("com.woltlab.wcf.redactor2", `observe_load_${this._elementId}`, () => this._observeLoad()); + + // bind listeners on init + this._observeLoad(); + } + + /** + * Intercepts the insertion of `[spoiler]` tags and uses + * the custom `` element instead. + */ + protected _bbcodeSpoiler(data: WoltLabEventData): void { + data.cancel = true; + + this._editor.button.toggle({}, "woltlab-spoiler", "func", "block.format"); + + let spoiler = this._editor.selection.block(); + if (spoiler) { + // iOS Safari might set the caret inside the spoiler. + if (spoiler.nodeName === "P") { + spoiler = spoiler.parentElement!; + } + + if (spoiler.nodeName === "WOLTLAB-SPOILER") { + this._setTitle(spoiler); + + spoiler.addEventListener("click", (ev) => this._edit(ev)); + + // work-around for Safari + this._editor.caret.end(spoiler); + } + } + } + + /** + * Binds event listeners and sets quote title on both editor + * initialization and when switching back from code view. + */ + protected _observeLoad(): void { + this._editor.$editor[0].querySelectorAll("woltlab-spoiler").forEach((spoiler: HTMLElement) => { + spoiler.addEventListener("mousedown", (ev) => this._edit(ev)); + this._setTitle(spoiler); + }); + } + + /** + * Opens the dialog overlay to edit the spoiler's properties. + */ + protected _edit(event: MouseEvent): void { + const spoiler = event.currentTarget as HTMLElement; + + if (_headerHeight === 0) { + _headerHeight = UiRedactorPseudoHeader.getHeight(spoiler); + } + + // check if the click hit the header + const offset = DomUtil.offset(spoiler); + if (event.pageY > offset.top && event.pageY < offset.top + _headerHeight) { + event.preventDefault(); + + this._editor.selection.save(); + this._spoiler = spoiler; + + UiDialog.open(this); + } + } + + /** + * Saves the changes to the spoiler's properties. + * + * @protected + */ + _dialogSubmit(): void { + const spoiler = this._spoiler!; + + const label = document.getElementById("redactor-spoiler-" + this._elementId + "-label") as HTMLInputElement; + spoiler.dataset.label = label.value; + + this._setTitle(spoiler); + this._editor.caret.after(spoiler); + + UiDialog.close(this); + } + + /** + * Sets or updates the spoiler's header title. + */ + protected _setTitle(spoiler: HTMLElement): void { + const title = Language.get("wcf.editor.spoiler.title", { label: spoiler.dataset.label || "" }); + + if (spoiler.dataset.title !== title) { + spoiler.dataset.title = title; + } + } + + protected _delete(event: MouseEvent): void { + event.preventDefault(); + + const spoiler = this._spoiler!; + + let caretEnd = spoiler.nextElementSibling || spoiler.previousElementSibling; + if (caretEnd === null && spoiler.parentElement !== this._editor.core.editor()[0]) { + caretEnd = spoiler.parentElement; + } + + if (caretEnd === null) { + this._editor.code.set(""); + this._editor.focus.end(); + } else { + spoiler.remove(); + this._editor.caret.end(caretEnd); + } + + UiDialog.close(this); + } + + _dialogSetup(): ReturnType { + const id = `redactor-spoiler-${this._elementId}`; + const idButtonDelete = `${id}-button-delete`; + const idButtonSave = `${id}-button-save`; + const idLabel = `${id}-label`; + + return { + id: id, + options: { + onClose: () => { + this._editor.selection.restore(); + + UiDialog.destroy(this); + }, + + onSetup: () => { + const button = document.getElementById(idButtonDelete) as HTMLButtonElement; + button.addEventListener("click", (ev) => this._delete(ev)); + }, + + onShow: () => { + const label = document.getElementById(idLabel) as HTMLInputElement; + label.value = this._spoiler!.dataset.label || ""; + }, + + title: Language.get("wcf.editor.spoiler.edit"), + }, + source: `
+
+
+ +
+
+ + ${Language.get("wcf.editor.spoiler.label.description")} +
+
+
+
+ + +
`, + }; + } +} + +Core.enableLegacyInheritance(UiRedactorSpoiler); + +export = UiRedactorSpoiler; -- 2.20.1