/**
* Provides editing support for comments.
*
- * @author Alexander Ebert
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module WoltLabSuite/Core/Ui/Comment/Edit
+ * @author Alexander Ebert
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/Ui/Comment/Edit
*/
-define([
- 'Ajax', 'Core', 'Dictionary', 'Environment',
- 'EventHandler', 'Language', 'List', 'Dom/ChangeListener', 'Dom/Traverse',
- 'Dom/Util', 'Ui/Notification', 'Ui/ReusableDropdown', 'WoltLabSuite/Core/Ui/Scroll'
-], function (Ajax, Core, Dictionary, Environment, EventHandler, Language, List, DomChangeListener, DomTraverse, DomUtil, UiNotification, UiReusableDropdown, UiScroll) {
+define(["require", "exports", "tslib", "../../Ajax", "../../Core", "../../Dom/Change/Listener", "../../Dom/Util", "../../Environment", "../../Event/Handler", "../../Language", "../Scroll", "../Notification"], function (require, exports, tslib_1, Ajax, Core, Listener_1, Util_1, Environment, EventHandler, Language, UiScroll, UiNotification) {
"use strict";
- if (!COMPILER_TARGET_DEFAULT) {
- var Fake = function () { };
- Fake.prototype = {
- init: function () { },
- rebuild: function () { },
- _click: function () { },
- _prepare: function () { },
- _showEditor: function () { },
- _restoreMessage: function () { },
- _save: function () { },
- _validate: function () { },
- throwError: function () { },
- _showMessage: function () { },
- _hideEditor: function () { },
- _restoreEditor: function () { },
- _destroyEditor: function () { },
- _getEditorId: function () { },
- _getObjectId: function () { },
- _ajaxFailure: function () { },
- _ajaxSuccess: function () { },
- _ajaxSetup: function () { }
- };
- return Fake;
- }
- /**
- * @constructor
- */
- function UiCommentEdit(container) { this.init(container); }
- UiCommentEdit.prototype = {
+ Ajax = tslib_1.__importStar(Ajax);
+ Core = tslib_1.__importStar(Core);
+ Listener_1 = tslib_1.__importDefault(Listener_1);
+ Util_1 = tslib_1.__importDefault(Util_1);
+ Environment = tslib_1.__importStar(Environment);
+ EventHandler = tslib_1.__importStar(EventHandler);
+ Language = tslib_1.__importStar(Language);
+ UiScroll = tslib_1.__importStar(UiScroll);
+ UiNotification = tslib_1.__importStar(UiNotification);
+ class UiCommentEdit {
/**
* Initializes the comment edit manager.
- *
- * @param {Element} container container element
*/
- init: function (container) {
+ constructor(container) {
this._activeElement = null;
- this._callbackClick = null;
- this._comments = new List();
- this._container = container;
+ this._comments = new Set();
this._editorContainer = null;
+ this._container = container;
this.rebuild();
- DomChangeListener.add('Ui/Comment/Edit_' + DomUtil.identify(this._container), this.rebuild.bind(this));
- },
+ Listener_1.default.add("Ui/Comment/Edit_" + Util_1.default.identify(this._container), this.rebuild.bind(this));
+ }
/**
* Initializes each applicable message, should be called whenever new
* messages are being displayed.
*/
- rebuild: function () {
- elBySelAll('.comment', this._container, (function (comment) {
+ rebuild() {
+ this._container.querySelectorAll(".comment").forEach((comment) => {
if (this._comments.has(comment)) {
return;
}
- if (elDataBool(comment, 'can-edit')) {
- var button = elBySel('.jsCommentEditButton', comment);
+ if (Core.stringToBool(comment.dataset.canEdit || "")) {
+ const button = comment.querySelector(".jsCommentEditButton");
if (button !== null) {
- if (this._callbackClick === null) {
- this._callbackClick = this._click.bind(this);
- }
- button.addEventListener('click', this._callbackClick);
+ button.addEventListener("click", (ev) => this._click(ev));
}
}
this._comments.add(comment);
- }).bind(this));
- },
+ });
+ }
/**
* Handles clicks on the edit button.
- *
- * @param {?Event} event event object
- * @protected
*/
- _click: function (event) {
+ _click(event) {
event.preventDefault();
if (this._activeElement === null) {
- this._activeElement = event.currentTarget.closest('.comment');
+ const target = event.currentTarget;
+ this._activeElement = target.closest(".comment");
this._prepare();
Ajax.api(this, {
- actionName: 'beginEdit',
- objectIDs: [this._getObjectId(this._activeElement)]
+ actionName: "beginEdit",
+ objectIDs: [this._getObjectId(this._activeElement)],
});
}
else {
- UiNotification.show('wcf.message.error.editorAlreadyInUse', null, 'warning');
+ UiNotification.show("wcf.message.error.editorAlreadyInUse", null, "warning");
}
- },
+ }
/**
* Prepares the message for editor display.
- *
- * @protected
*/
- _prepare: function () {
- this._editorContainer = elCreate('div');
- this._editorContainer.className = 'commentEditorContainer';
+ _prepare() {
+ this._editorContainer = document.createElement("div");
+ this._editorContainer.className = "commentEditorContainer";
this._editorContainer.innerHTML = '<span class="icon icon48 fa-spinner"></span>';
- var content = elBySel('.commentContentContainer', this._activeElement);
+ const content = this._activeElement.querySelector(".commentContentContainer");
content.insertBefore(this._editorContainer, content.firstChild);
- },
+ }
/**
* Shows the message editor.
- *
- * @param {Object} data ajax response data
- * @protected
*/
- _showEditor: function (data) {
- var id = this._getEditorId();
- var icon = elBySel('.icon', this._editorContainer);
- elRemove(icon);
- var editor = elCreate('div');
- editor.className = 'editorContainer';
- //noinspection JSUnresolvedVariable
- DomUtil.setInnerHtml(editor, data.returnValues.template);
- this._editorContainer.appendChild(editor);
+ _showEditor(data) {
+ const id = this._getEditorId();
+ const editorContainer = this._editorContainer;
+ const icon = editorContainer.querySelector(".icon");
+ icon.remove();
+ const editor = document.createElement("div");
+ editor.className = "editorContainer";
+ Util_1.default.setInnerHtml(editor, data.returnValues.template);
+ editorContainer.appendChild(editor);
// bind buttons
- var formSubmit = elBySel('.formSubmit', editor);
- var buttonSave = elBySel('button[data-type="save"]', formSubmit);
- buttonSave.addEventListener('click', this._save.bind(this));
- var buttonCancel = elBySel('button[data-type="cancel"]', formSubmit);
- buttonCancel.addEventListener('click', this._restoreMessage.bind(this));
- EventHandler.add('com.woltlab.wcf.redactor', 'submitEditor_' + id, (function (data) {
+ const formSubmit = editorContainer.querySelector(".formSubmit");
+ const buttonSave = formSubmit.querySelector('button[data-type="save"]');
+ buttonSave.addEventListener("click", () => this._save());
+ const buttonCancel = formSubmit.querySelector('button[data-type="cancel"]');
+ buttonCancel.addEventListener("click", () => this._restoreMessage());
+ EventHandler.add("com.woltlab.wcf.redactor", `submitEditor_${id}`, (data) => {
data.cancel = true;
this._save();
- }).bind(this));
- var editorElement = elById(id);
- if (Environment.editor() === 'redactor') {
- window.setTimeout((function () {
+ });
+ const editorElement = document.getElementById(id);
+ if (Environment.editor() === "redactor") {
+ window.setTimeout(() => {
UiScroll.element(this._activeElement);
- }).bind(this), 250);
+ }, 250);
}
else {
editorElement.focus();
}
- },
+ }
/**
* Restores the message view.
- *
- * @protected
*/
- _restoreMessage: function () {
+ _restoreMessage() {
this._destroyEditor();
- elRemove(this._editorContainer);
+ this._editorContainer.remove();
this._activeElement = null;
- },
+ }
/**
* Saves the editor message.
- *
- * @protected
*/
- _save: function () {
- var parameters = {
+ _save() {
+ const parameters = {
data: {
- message: ''
- }
+ message: "",
+ },
};
- var id = this._getEditorId();
- EventHandler.fire('com.woltlab.wcf.redactor2', 'getText_' + id, parameters.data);
+ const id = this._getEditorId();
+ EventHandler.fire("com.woltlab.wcf.redactor2", `getText_${id}`, parameters.data);
if (!this._validate(parameters)) {
// validation failed
return;
}
- EventHandler.fire('com.woltlab.wcf.redactor2', 'submit_' + id, parameters);
+ EventHandler.fire("com.woltlab.wcf.redactor2", `submit_${id}`, parameters);
Ajax.api(this, {
- actionName: 'save',
+ actionName: "save",
objectIDs: [this._getObjectId(this._activeElement)],
- parameters: parameters
+ parameters: parameters,
});
this._hideEditor();
- },
+ }
/**
* Validates the message and invokes listeners to perform additional validation.
- *
- * @param {Object} parameters request parameters
- * @return {boolean} validation result
- * @protected
*/
- _validate: function (parameters) {
+ _validate(parameters) {
// remove all existing error elements
- elBySelAll('.innerError', this._activeElement, elRemove);
+ this._activeElement.querySelectorAll(".innerError").forEach((el) => el.remove());
// check if editor contains actual content
- var editorElement = elById(this._getEditorId());
- if (window.jQuery(editorElement).data('redactor').utils.isEmpty()) {
- this.throwError(editorElement, Language.get('wcf.global.form.error.empty'));
+ const editorElement = document.getElementById(this._getEditorId());
+ const redactor = window.jQuery(editorElement).data("redactor");
+ if (redactor.utils.isEmpty()) {
+ this.throwError(editorElement, Language.get("wcf.global.form.error.empty"));
return false;
}
- var data = {
+ const data = {
api: this,
parameters: parameters,
- valid: true
+ valid: true,
};
- EventHandler.fire('com.woltlab.wcf.redactor2', 'validate_' + this._getEditorId(), data);
- return (data.valid !== false);
- },
+ EventHandler.fire("com.woltlab.wcf.redactor2", "validate_" + this._getEditorId(), data);
+ return data.valid;
+ }
/**
* Throws an error by adding an inline error to target element.
- *
- * @param {Element} element erroneous element
- * @param {string} message error message
*/
- throwError: function (element, message) {
- elInnerError(element, message);
- },
+ throwError(element, message) {
+ Util_1.default.innerError(element, message);
+ }
/**
* Shows the update message.
- *
- * @param {Object} data ajax response data
- * @protected
*/
- _showMessage: function (data) {
+ _showMessage(data) {
// set new content
- //noinspection JSCheckFunctionSignatures
- DomUtil.setInnerHtml(elBySel('.commentContent .userMessage', this._editorContainer.parentNode), data.returnValues.message);
+ const container = this._editorContainer.parentElement.querySelector(".commentContent .userMessage");
+ Util_1.default.setInnerHtml(container, data.returnValues.message);
this._restoreMessage();
UiNotification.show();
- },
+ }
/**
* Hides the editor from view.
- *
- * @protected
*/
- _hideEditor: function () {
- elHide(elBySel('.editorContainer', this._editorContainer));
- var icon = elCreate('span');
- icon.className = 'icon icon48 fa-spinner';
+ _hideEditor() {
+ const editorContainer = this._editorContainer.querySelector(".editorContainer");
+ Util_1.default.hide(editorContainer);
+ const icon = document.createElement("span");
+ icon.className = "icon icon48 fa-spinner";
this._editorContainer.appendChild(icon);
- },
+ }
/**
* Restores the previously hidden editor.
- *
- * @protected
*/
- _restoreEditor: function () {
- var icon = elBySel('.fa-spinner', this._editorContainer);
- elRemove(icon);
- var editorContainer = elBySel('.editorContainer', this._editorContainer);
- if (editorContainer !== null)
- elShow(editorContainer);
- },
+ _restoreEditor() {
+ const icon = this._editorContainer.querySelector(".fa-spinner");
+ icon.remove();
+ const editorContainer = this._editorContainer.querySelector(".editorContainer");
+ if (editorContainer !== null) {
+ Util_1.default.show(editorContainer);
+ }
+ }
/**
* Destroys the editor instance.
- *
- * @protected
*/
- _destroyEditor: function () {
- EventHandler.fire('com.woltlab.wcf.redactor2', 'autosaveDestroy_' + this._getEditorId());
- EventHandler.fire('com.woltlab.wcf.redactor2', 'destroy_' + this._getEditorId());
- },
+ _destroyEditor() {
+ EventHandler.fire("com.woltlab.wcf.redactor2", `autosaveDestroy_${this._getEditorId()}`);
+ EventHandler.fire("com.woltlab.wcf.redactor2", `destroy_${this._getEditorId()}`);
+ }
/**
* Returns the unique editor id.
- *
- * @return {string} editor id
- * @protected
*/
- _getEditorId: function () {
- return 'commentEditor' + this._getObjectId(this._activeElement);
- },
+ _getEditorId() {
+ return `commentEditor${this._getObjectId(this._activeElement)}`;
+ }
/**
* Returns the element's `data-object-id` value.
- *
- * @param {Element} element target element
- * @return {int}
- * @protected
*/
- _getObjectId: function (element) {
- return ~~elData(element, 'object-id');
- },
- _ajaxFailure: function (data) {
- var editor = elBySel('.redactor-layer', this._editorContainer);
+ _getObjectId(element) {
+ return ~~element.dataset.objectId;
+ }
+ _ajaxFailure(data) {
+ const editor = this._editorContainer.querySelector(".redactor-layer");
// handle errors occurring on editor load
if (editor === null) {
this._restoreMessage();
return true;
}
this._restoreEditor();
- //noinspection JSUnresolvedVariable
if (!data || data.returnValues === undefined || data.returnValues.errorType === undefined) {
return true;
}
- //noinspection JSUnresolvedVariable
- elInnerError(editor, data.returnValues.errorType);
+ Util_1.default.innerError(editor, data.returnValues.errorType);
return false;
- },
- _ajaxSuccess: function (data) {
+ }
+ _ajaxSuccess(data) {
switch (data.actionName) {
- case 'beginEdit':
+ case "beginEdit":
this._showEditor(data);
break;
- case 'save':
+ case "save":
this._showMessage(data);
break;
}
- },
- _ajaxSetup: function () {
- var objectTypeId = ~~elData(this._container, 'object-type-id');
+ }
+ _ajaxSetup() {
+ const objectTypeId = ~~this._container.dataset.objectTypeId;
return {
data: {
- className: 'wcf\\data\\comment\\CommentAction',
+ className: "wcf\\data\\comment\\CommentAction",
parameters: {
data: {
- objectTypeID: objectTypeId
- }
- }
+ objectTypeID: objectTypeId,
+ },
+ },
},
- silent: true
+ silent: true,
};
}
- };
+ }
+ Core.enableLegacyInheritance(UiCommentEdit);
return UiCommentEdit;
});
let _notificationElement;
let _timeout;
function init() {
- if (_didInit)
+ if (_didInit) {
return;
+ }
_didInit = true;
_notificationElement = document.createElement("div");
_notificationElement.id = "systemNotification";
+++ /dev/null
-/**
- * Provides editing support for comments.
- *
- * @author Alexander Ebert
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module WoltLabSuite/Core/Ui/Comment/Edit
- */
-define(
- [
- 'Ajax', 'Core', 'Dictionary', 'Environment',
- 'EventHandler', 'Language', 'List', 'Dom/ChangeListener', 'Dom/Traverse',
- 'Dom/Util', 'Ui/Notification', 'Ui/ReusableDropdown', 'WoltLabSuite/Core/Ui/Scroll'
- ],
- function(
- Ajax, Core, Dictionary, Environment,
- EventHandler, Language, List, DomChangeListener, DomTraverse,
- DomUtil, UiNotification, UiReusableDropdown, UiScroll
- )
-{
- "use strict";
-
- if (!COMPILER_TARGET_DEFAULT) {
- var Fake = function() {};
- Fake.prototype = {
- init: function() {},
- rebuild: function() {},
- _click: function() {},
- _prepare: function() {},
- _showEditor: function() {},
- _restoreMessage: function() {},
- _save: function() {},
- _validate: function() {},
- throwError: function() {},
- _showMessage: function() {},
- _hideEditor: function() {},
- _restoreEditor: function() {},
- _destroyEditor: function() {},
- _getEditorId: function() {},
- _getObjectId: function() {},
- _ajaxFailure: function() {},
- _ajaxSuccess: function() {},
- _ajaxSetup: function() {}
- };
- return Fake;
- }
-
- /**
- * @constructor
- */
- function UiCommentEdit(container) { this.init(container); }
- UiCommentEdit.prototype = {
- /**
- * Initializes the comment edit manager.
- *
- * @param {Element} container container element
- */
- init: function(container) {
- this._activeElement = null;
- this._callbackClick = null;
- this._comments = new List();
- this._container = container;
- this._editorContainer = null;
-
- this.rebuild();
-
- DomChangeListener.add('Ui/Comment/Edit_' + DomUtil.identify(this._container), this.rebuild.bind(this));
- },
-
- /**
- * Initializes each applicable message, should be called whenever new
- * messages are being displayed.
- */
- rebuild: function() {
- elBySelAll('.comment', this._container, (function (comment) {
- if (this._comments.has(comment)) {
- return;
- }
-
- if (elDataBool(comment, 'can-edit')) {
- var button = elBySel('.jsCommentEditButton', comment);
- if (button !== null) {
- if (this._callbackClick === null) {
- this._callbackClick = this._click.bind(this);
- }
-
- button.addEventListener('click', this._callbackClick);
- }
- }
-
- this._comments.add(comment);
- }).bind(this));
- },
-
- /**
- * Handles clicks on the edit button.
- *
- * @param {?Event} event event object
- * @protected
- */
- _click: function(event) {
- event.preventDefault();
-
- if (this._activeElement === null) {
- this._activeElement = event.currentTarget.closest('.comment');
-
- this._prepare();
-
- Ajax.api(this, {
- actionName: 'beginEdit',
- objectIDs: [this._getObjectId(this._activeElement)]
- });
- }
- else {
- UiNotification.show('wcf.message.error.editorAlreadyInUse', null, 'warning');
- }
- },
-
- /**
- * Prepares the message for editor display.
- *
- * @protected
- */
- _prepare: function() {
- this._editorContainer = elCreate('div');
- this._editorContainer.className = 'commentEditorContainer';
- this._editorContainer.innerHTML = '<span class="icon icon48 fa-spinner"></span>';
-
- var content = elBySel('.commentContentContainer', this._activeElement);
- content.insertBefore(this._editorContainer, content.firstChild);
- },
-
- /**
- * Shows the message editor.
- *
- * @param {Object} data ajax response data
- * @protected
- */
- _showEditor: function(data) {
- var id = this._getEditorId();
-
- var icon = elBySel('.icon', this._editorContainer);
- elRemove(icon);
-
- var editor = elCreate('div');
- editor.className = 'editorContainer';
- //noinspection JSUnresolvedVariable
- DomUtil.setInnerHtml(editor, data.returnValues.template);
- this._editorContainer.appendChild(editor);
-
- // bind buttons
- var formSubmit = elBySel('.formSubmit', editor);
-
- var buttonSave = elBySel('button[data-type="save"]', formSubmit);
- buttonSave.addEventListener('click', this._save.bind(this));
-
- var buttonCancel = elBySel('button[data-type="cancel"]', formSubmit);
- buttonCancel.addEventListener('click', this._restoreMessage.bind(this));
-
- EventHandler.add('com.woltlab.wcf.redactor', 'submitEditor_' + id, (function(data) {
- data.cancel = true;
-
- this._save();
- }).bind(this));
-
- var editorElement = elById(id);
- if (Environment.editor() === 'redactor') {
- window.setTimeout((function() {
- UiScroll.element(this._activeElement);
- }).bind(this), 250);
- }
- else {
- editorElement.focus();
- }
- },
-
- /**
- * Restores the message view.
- *
- * @protected
- */
- _restoreMessage: function() {
- this._destroyEditor();
-
- elRemove(this._editorContainer);
-
- this._activeElement = null;
- },
-
- /**
- * Saves the editor message.
- *
- * @protected
- */
- _save: function() {
- var parameters = {
- data: {
- message: ''
- }
- };
-
- var id = this._getEditorId();
-
- EventHandler.fire('com.woltlab.wcf.redactor2', 'getText_' + id, parameters.data);
-
- if (!this._validate(parameters)) {
- // validation failed
- return;
- }
-
- EventHandler.fire('com.woltlab.wcf.redactor2', 'submit_' + id, parameters);
-
- Ajax.api(this, {
- actionName: 'save',
- objectIDs: [this._getObjectId(this._activeElement)],
- parameters: parameters
- });
-
- this._hideEditor();
- },
-
- /**
- * Validates the message and invokes listeners to perform additional validation.
- *
- * @param {Object} parameters request parameters
- * @return {boolean} validation result
- * @protected
- */
- _validate: function(parameters) {
- // remove all existing error elements
- elBySelAll('.innerError', this._activeElement, elRemove);
-
- // check if editor contains actual content
- var editorElement = elById(this._getEditorId());
- if (window.jQuery(editorElement).data('redactor').utils.isEmpty()) {
- this.throwError(editorElement, Language.get('wcf.global.form.error.empty'));
- return false;
- }
-
- var data = {
- api: this,
- parameters: parameters,
- valid: true
- };
-
- EventHandler.fire('com.woltlab.wcf.redactor2', 'validate_' + this._getEditorId(), data);
-
- return (data.valid !== false);
- },
-
- /**
- * Throws an error by adding an inline error to target element.
- *
- * @param {Element} element erroneous element
- * @param {string} message error message
- */
- throwError: function(element, message) {
- elInnerError(element, message);
- },
-
- /**
- * Shows the update message.
- *
- * @param {Object} data ajax response data
- * @protected
- */
- _showMessage: function(data) {
- // set new content
- //noinspection JSCheckFunctionSignatures
- DomUtil.setInnerHtml(elBySel('.commentContent .userMessage', this._editorContainer.parentNode), data.returnValues.message);
-
- this._restoreMessage();
-
- UiNotification.show();
- },
-
- /**
- * Hides the editor from view.
- *
- * @protected
- */
- _hideEditor: function() {
- elHide(elBySel('.editorContainer', this._editorContainer));
-
- var icon = elCreate('span');
- icon.className = 'icon icon48 fa-spinner';
- this._editorContainer.appendChild(icon);
- },
-
- /**
- * Restores the previously hidden editor.
- *
- * @protected
- */
- _restoreEditor: function() {
- var icon = elBySel('.fa-spinner', this._editorContainer);
- elRemove(icon);
-
- var editorContainer = elBySel('.editorContainer', this._editorContainer);
- if (editorContainer !== null) elShow(editorContainer);
- },
-
- /**
- * Destroys the editor instance.
- *
- * @protected
- */
- _destroyEditor: function() {
- EventHandler.fire('com.woltlab.wcf.redactor2', 'autosaveDestroy_' + this._getEditorId());
- EventHandler.fire('com.woltlab.wcf.redactor2', 'destroy_' + this._getEditorId());
- },
-
- /**
- * Returns the unique editor id.
- *
- * @return {string} editor id
- * @protected
- */
- _getEditorId: function() {
- return 'commentEditor' + this._getObjectId(this._activeElement);
- },
-
- /**
- * Returns the element's `data-object-id` value.
- *
- * @param {Element} element target element
- * @return {int}
- * @protected
- */
- _getObjectId: function(element) {
- return ~~elData(element, 'object-id');
- },
-
- _ajaxFailure: function(data) {
- var editor = elBySel('.redactor-layer', this._editorContainer);
-
- // handle errors occurring on editor load
- if (editor === null) {
- this._restoreMessage();
-
- return true;
- }
-
- this._restoreEditor();
-
- //noinspection JSUnresolvedVariable
- if (!data || data.returnValues === undefined || data.returnValues.errorType === undefined) {
- return true;
- }
-
- //noinspection JSUnresolvedVariable
- elInnerError(editor, data.returnValues.errorType);
-
- return false;
- },
-
- _ajaxSuccess: function(data) {
- switch (data.actionName) {
- case 'beginEdit':
- this._showEditor(data);
- break;
-
- case 'save':
- this._showMessage(data);
- break;
- }
- },
-
- _ajaxSetup: function() {
- var objectTypeId = ~~elData(this._container, 'object-type-id');
-
- return {
- data: {
- className: 'wcf\\data\\comment\\CommentAction',
- parameters: {
- data: {
- objectTypeID: objectTypeId
- }
- }
- },
- silent: true
- };
- }
- };
-
- return UiCommentEdit;
-});
--- /dev/null
+/**
+ * Provides editing support for comments.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/Ui/Comment/Edit
+ */
+
+import * as Ajax from "../../Ajax";
+import { AjaxCallbackSetup, ResponseData } from "../../Ajax/Data";
+import * as Core from "../../Core";
+import DomChangeListener from "../../Dom/Change/Listener";
+import DomUtil from "../../Dom/Util";
+import * as Environment from "../../Environment";
+import * as EventHandler from "../../Event/Handler";
+import * as Language from "../../Language";
+import { RedactorEditor } from "../Redactor/Editor";
+import * as UiScroll from "../Scroll";
+import * as UiNotification from "../Notification";
+
+interface AjaxResponse {
+ actionName: string;
+ returnValues: {
+ message: string;
+ template: string;
+ };
+}
+
+class UiCommentEdit {
+ protected _activeElement: HTMLElement | null = null;
+ protected readonly _comments = new Set<HTMLElement>();
+ protected readonly _container: HTMLElement;
+ protected _editorContainer: HTMLElement | null = null;
+
+ /**
+ * Initializes the comment edit manager.
+ */
+ constructor(container: HTMLElement) {
+ this._container = container;
+
+ this.rebuild();
+
+ DomChangeListener.add("Ui/Comment/Edit_" + DomUtil.identify(this._container), this.rebuild.bind(this));
+ }
+
+ /**
+ * Initializes each applicable message, should be called whenever new
+ * messages are being displayed.
+ */
+ rebuild(): void {
+ this._container.querySelectorAll(".comment").forEach((comment: HTMLElement) => {
+ if (this._comments.has(comment)) {
+ return;
+ }
+
+ if (Core.stringToBool(comment.dataset.canEdit || "")) {
+ const button = comment.querySelector(".jsCommentEditButton") as HTMLAnchorElement;
+ if (button !== null) {
+ button.addEventListener("click", (ev) => this._click(ev));
+ }
+ }
+
+ this._comments.add(comment);
+ });
+ }
+
+ /**
+ * Handles clicks on the edit button.
+ */
+ protected _click(event: MouseEvent): void {
+ event.preventDefault();
+
+ if (this._activeElement === null) {
+ const target = event.currentTarget as HTMLElement;
+ this._activeElement = target.closest(".comment") as HTMLElement;
+
+ this._prepare();
+
+ Ajax.api(this, {
+ actionName: "beginEdit",
+ objectIDs: [this._getObjectId(this._activeElement)],
+ });
+ } else {
+ UiNotification.show("wcf.message.error.editorAlreadyInUse", null, "warning");
+ }
+ }
+
+ /**
+ * Prepares the message for editor display.
+ */
+ protected _prepare(): void {
+ this._editorContainer = document.createElement("div");
+ this._editorContainer.className = "commentEditorContainer";
+ this._editorContainer.innerHTML = '<span class="icon icon48 fa-spinner"></span>';
+
+ const content = this._activeElement!.querySelector(".commentContentContainer")!;
+ content.insertBefore(this._editorContainer, content.firstChild);
+ }
+
+ /**
+ * Shows the message editor.
+ */
+ protected _showEditor(data: AjaxResponse): void {
+ const id = this._getEditorId();
+ const editorContainer = this._editorContainer!;
+
+ const icon = editorContainer.querySelector(".icon")!;
+ icon.remove();
+
+ const editor = document.createElement("div");
+ editor.className = "editorContainer";
+ DomUtil.setInnerHtml(editor, data.returnValues.template);
+ editorContainer.appendChild(editor);
+
+ // bind buttons
+ const formSubmit = editorContainer.querySelector(".formSubmit") as HTMLElement;
+
+ const buttonSave = formSubmit.querySelector('button[data-type="save"]') as HTMLButtonElement;
+ buttonSave.addEventListener("click", () => this._save());
+
+ const buttonCancel = formSubmit.querySelector('button[data-type="cancel"]') as HTMLButtonElement;
+ buttonCancel.addEventListener("click", () => this._restoreMessage());
+
+ EventHandler.add("com.woltlab.wcf.redactor", `submitEditor_${id}`, (data) => {
+ data.cancel = true;
+
+ this._save();
+ });
+
+ const editorElement = document.getElementById(id) as HTMLElement;
+ if (Environment.editor() === "redactor") {
+ window.setTimeout(() => {
+ UiScroll.element(this._activeElement!);
+ }, 250);
+ } else {
+ editorElement.focus();
+ }
+ }
+
+ /**
+ * Restores the message view.
+ */
+ protected _restoreMessage(): void {
+ this._destroyEditor();
+
+ this._editorContainer!.remove();
+
+ this._activeElement = null;
+ }
+
+ /**
+ * Saves the editor message.
+ */
+ protected _save(): void {
+ const parameters = {
+ data: {
+ message: "",
+ },
+ };
+
+ const id = this._getEditorId();
+
+ EventHandler.fire("com.woltlab.wcf.redactor2", `getText_${id}`, parameters.data);
+
+ if (!this._validate(parameters)) {
+ // validation failed
+ return;
+ }
+
+ EventHandler.fire("com.woltlab.wcf.redactor2", `submit_${id}`, parameters);
+
+ Ajax.api(this, {
+ actionName: "save",
+ objectIDs: [this._getObjectId(this._activeElement!)],
+ parameters: parameters,
+ });
+
+ this._hideEditor();
+ }
+
+ /**
+ * Validates the message and invokes listeners to perform additional validation.
+ */
+ protected _validate(parameters: ArbitraryObject): boolean {
+ // remove all existing error elements
+ this._activeElement!.querySelectorAll(".innerError").forEach((el) => el.remove());
+
+ // check if editor contains actual content
+ const editorElement = document.getElementById(this._getEditorId())!;
+ const redactor: RedactorEditor = window.jQuery(editorElement).data("redactor");
+ if (redactor.utils.isEmpty()) {
+ this.throwError(editorElement, Language.get("wcf.global.form.error.empty"));
+ return false;
+ }
+
+ const data = {
+ api: this,
+ parameters: parameters,
+ valid: true,
+ };
+
+ EventHandler.fire("com.woltlab.wcf.redactor2", "validate_" + this._getEditorId(), data);
+
+ return data.valid;
+ }
+
+ /**
+ * Throws an error by adding an inline error to target element.
+ */
+ throwError(element: HTMLElement, message: string): void {
+ DomUtil.innerError(element, message);
+ }
+
+ /**
+ * Shows the update message.
+ */
+ protected _showMessage(data: AjaxResponse): void {
+ // set new content
+ const container = this._editorContainer!.parentElement!.querySelector(
+ ".commentContent .userMessage",
+ ) as HTMLElement;
+ DomUtil.setInnerHtml(container, data.returnValues.message);
+
+ this._restoreMessage();
+
+ UiNotification.show();
+ }
+
+ /**
+ * Hides the editor from view.
+ */
+ protected _hideEditor(): void {
+ const editorContainer = this._editorContainer!.querySelector(".editorContainer") as HTMLElement;
+ DomUtil.hide(editorContainer);
+
+ const icon = document.createElement("span");
+ icon.className = "icon icon48 fa-spinner";
+ this._editorContainer!.appendChild(icon);
+ }
+
+ /**
+ * Restores the previously hidden editor.
+ */
+ protected _restoreEditor(): void {
+ const icon = this._editorContainer!.querySelector(".fa-spinner")!;
+ icon.remove();
+
+ const editorContainer = this._editorContainer!.querySelector(".editorContainer") as HTMLElement;
+ if (editorContainer !== null) {
+ DomUtil.show(editorContainer);
+ }
+ }
+
+ /**
+ * Destroys the editor instance.
+ */
+ protected _destroyEditor(): void {
+ EventHandler.fire("com.woltlab.wcf.redactor2", `autosaveDestroy_${this._getEditorId()}`);
+ EventHandler.fire("com.woltlab.wcf.redactor2", `destroy_${this._getEditorId()}`);
+ }
+
+ /**
+ * Returns the unique editor id.
+ */
+ protected _getEditorId(): string {
+ return `commentEditor${this._getObjectId(this._activeElement!)}`;
+ }
+
+ /**
+ * Returns the element's `data-object-id` value.
+ */
+ protected _getObjectId(element: HTMLElement): number {
+ return ~~element.dataset.objectId!;
+ }
+
+ _ajaxFailure(data: ResponseData): boolean {
+ const editor = this._editorContainer!.querySelector(".redactor-layer") as HTMLElement;
+
+ // handle errors occurring on editor load
+ if (editor === null) {
+ this._restoreMessage();
+
+ return true;
+ }
+
+ this._restoreEditor();
+
+ if (!data || data.returnValues === undefined || data.returnValues.errorType === undefined) {
+ return true;
+ }
+
+ DomUtil.innerError(editor, data.returnValues.errorType);
+
+ return false;
+ }
+
+ _ajaxSuccess(data: AjaxResponse): void {
+ switch (data.actionName) {
+ case "beginEdit":
+ this._showEditor(data);
+ break;
+
+ case "save":
+ this._showMessage(data);
+ break;
+ }
+ }
+
+ _ajaxSetup(): ReturnType<AjaxCallbackSetup> {
+ const objectTypeId = ~~this._container.dataset.objectTypeId!;
+
+ return {
+ data: {
+ className: "wcf\\data\\comment\\CommentAction",
+ parameters: {
+ data: {
+ objectTypeID: objectTypeId,
+ },
+ },
+ },
+ silent: true,
+ };
+ }
+}
+
+Core.enableLegacyInheritance(UiCommentEdit);
+
+export = UiCommentEdit;
let _timeout: number;
function init() {
- if (_didInit) return;
+ if (_didInit) {
+ return;
+ }
_didInit = true;
_notificationElement = document.createElement("div");
/**
* Displays a notification.
*/
-export function show(message?: string, callback?: Callback, cssClassName?: string): void {
+export function show(message?: string, callback?: Callback | null, cssClassName?: string): void {
if (_busy) {
return;
}