find wcfsetup/install/files/ts/WoltLabSuite/Core/ -iname '*.ts' -print0 |xargs -0 npx prettier -w
* for success and failure callbacks.
*/
function api(callbackObject, data, success, failure) {
- if (typeof data !== 'object')
+ if (typeof data !== "object")
data = {};
let request = _cache.get(callbackObject);
if (request === undefined) {
- if (typeof callbackObject._ajaxSetup !== 'function') {
+ if (typeof callbackObject._ajaxSetup !== "function") {
throw new TypeError("Callback object must implement at least _ajaxSetup().");
}
const options = callbackObject._ajaxSetup();
options.pinData = true;
options.callbackObject = callbackObject;
if (!options.url) {
- options.url = 'index.php?ajax-proxy/&t=' + window.SECURITY_TOKEN;
+ options.url = "index.php?ajax-proxy/&t=" + window.SECURITY_TOKEN;
options.withCredentials = true;
}
request = new Request_1.default(options);
}
let oldSuccess = null;
let oldFailure = null;
- if (typeof success === 'function') {
- oldSuccess = request.getOption('success');
- request.setOption('success', success);
+ if (typeof success === "function") {
+ oldSuccess = request.getOption("success");
+ request.setOption("success", success);
}
- if (typeof failure === 'function') {
- oldFailure = request.getOption('failure');
- request.setOption('failure', failure);
+ if (typeof failure === "function") {
+ oldFailure = request.getOption("failure");
+ request.setOption("failure", failure);
}
request.setData(data);
request.sendRequest();
// restore callbacks
if (oldSuccess !== null)
- request.setOption('success', oldSuccess);
+ request.setOption("success", oldSuccess);
if (oldFailure !== null)
- request.setOption('failure', oldFailure);
+ request.setOption("failure", oldFailure);
return request;
}
exports.api = api;
options.pinData = false;
options.callbackObject = null;
if (!options.url) {
- options.url = 'index.php?ajax-proxy/&t=' + window.SECURITY_TOKEN;
+ options.url = "index.php?ajax-proxy/&t=" + window.SECURITY_TOKEN;
options.withCredentials = true;
}
const request = new Request_1.default(options);
*/
function getRequestObject(callbackObject) {
if (!_cache.has(callbackObject)) {
- throw new Error('Expected a previously used callback object, provided object is unknown.');
+ throw new Error("Expected a previously used callback object, provided object is unknown.");
}
return _cache.get(callbackObject);
}
* Dispatch a JSONP request, the `url` must not contain a callback parameter.
*/
function send(url, success, failure, options) {
- url = (typeof url === 'string') ? url.trim() : '';
+ url = typeof url === "string" ? url.trim() : "";
if (url.length === 0) {
- throw new Error('Expected a non-empty string for parameter \'url\'.');
+ throw new Error("Expected a non-empty string for parameter 'url'.");
}
- if (typeof success !== 'function') {
- throw new TypeError('Expected a valid callback function for parameter \'success\'.');
+ if (typeof success !== "function") {
+ throw new TypeError("Expected a valid callback function for parameter 'success'.");
}
options = Core.extend({
- parameterName: 'callback',
+ parameterName: "callback",
timeout: 10,
}, options || {});
- const callbackName = 'wcf_jsonp_' + Core.getUuid().replace(/-/g, '').substr(0, 8);
+ const callbackName = "wcf_jsonp_" + Core.getUuid().replace(/-/g, "").substr(0, 8);
let script;
const timeout = window.setTimeout(() => {
- if (typeof failure === 'function') {
+ if (typeof failure === "function") {
failure();
}
window[callbackName] = undefined;
window[callbackName] = undefined;
script.remove();
};
- url += (url.indexOf('?') === -1) ? '?' : '&';
- url += options.parameterName + '=' + callbackName;
- script = document.createElement('script');
+ url += url.indexOf("?") === -1 ? "?" : "&";
+ url += options.parameterName + "=" + callbackName;
+ script = document.createElement("script");
script.async = true;
script.src = url;
document.head.appendChild(script);
constructor(options) {
this._options = Core.extend({
data: {},
- contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
- responseType: 'application/json',
- type: 'POST',
- url: '',
+ contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+ responseType: "application/json",
+ type: "POST",
+ url: "",
withCredentials: false,
// behavior
autoAbort: false,
uploadProgress: null,
callbackObject: null,
}, options);
- if (typeof options.callbackObject === 'object') {
+ if (typeof options.callbackObject === "object") {
this._options.callbackObject = options.callbackObject;
}
this._options.url = Core.convertLegacyUrl(this._options.url);
- if (this._options.url.indexOf('index.php') === 0) {
+ if (this._options.url.indexOf("index.php") === 0) {
this._options.url = window.WSC_API_URL + this._options.url;
}
if (this._options.url.indexOf(window.WSC_API_URL) === 0) {
this._data = this._options.data;
}
if (this._options.callbackObject) {
- if (typeof this._options.callbackObject._ajaxFailure === 'function')
+ if (typeof this._options.callbackObject._ajaxFailure === "function")
this._options.failure = this._options.callbackObject._ajaxFailure.bind(this._options.callbackObject);
- if (typeof this._options.callbackObject._ajaxFinalize === 'function')
+ if (typeof this._options.callbackObject._ajaxFinalize === "function")
this._options.finalize = this._options.callbackObject._ajaxFinalize.bind(this._options.callbackObject);
- if (typeof this._options.callbackObject._ajaxSuccess === 'function')
+ if (typeof this._options.callbackObject._ajaxSuccess === "function")
this._options.success = this._options.callbackObject._ajaxSuccess.bind(this._options.callbackObject);
- if (typeof this._options.callbackObject._ajaxProgress === 'function')
+ if (typeof this._options.callbackObject._ajaxProgress === "function")
this._options.progress = this._options.callbackObject._ajaxProgress.bind(this._options.callbackObject);
- if (typeof this._options.callbackObject._ajaxUploadProgress === 'function')
+ if (typeof this._options.callbackObject._ajaxUploadProgress === "function")
this._options.uploadProgress = this._options.callbackObject._ajaxUploadProgress.bind(this._options.callbackObject);
}
if (!_didInit) {
_didInit = true;
- window.addEventListener('beforeunload', () => _ignoreAllErrors = true);
+ window.addEventListener("beforeunload", () => (_ignoreAllErrors = true));
}
}
/**
this._xhr = new XMLHttpRequest();
this._xhr.open(this._options.type, this._options.url, true);
if (this._options.contentType) {
- this._xhr.setRequestHeader('Content-Type', this._options.contentType);
+ this._xhr.setRequestHeader("Content-Type", this._options.contentType);
}
if (this._options.withCredentials || this._options.includeRequestedWith) {
- this._xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
+ this._xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
}
if (this._options.withCredentials) {
this._xhr.withCredentials = true;
const options = Core.clone(this._options);
this._xhr.onload = function () {
if (this.readyState === XMLHttpRequest.DONE) {
- if (this.status >= 200 && this.status < 300 || this.status === 304) {
- if (options.responseType && this.getResponseHeader('Content-Type').indexOf(options.responseType) !== 0) {
+ if ((this.status >= 200 && this.status < 300) || this.status === 304) {
+ if (options.responseType && this.getResponseHeader("Content-Type").indexOf(options.responseType) !== 0) {
// request succeeded but invalid response type
self._failure(this, options);
}
if (this._options.uploadProgress) {
this._xhr.upload.onprogress = this._options.uploadProgress;
}
- if (this._options.type === 'POST') {
+ if (this._options.type === "POST") {
let data = this._options.data;
- if (typeof data === 'object' && Core.getType(data) !== 'FormData') {
+ if (typeof data === "object" && Core.getType(data) !== "FormData") {
data = Core.serialize(data);
}
this._xhr.send(data);
* Sets request data while honoring pinned data from setup callback.
*/
setData(data) {
- if (this._data !== null && Core.getType(data) !== 'FormData') {
+ if (this._data !== null && Core.getType(data) !== "FormData") {
data = Core.extend(this._data, data);
}
this._options.data = data;
if (!options.silent) {
AjaxStatus.hide();
}
- if (typeof options.success === 'function') {
+ if (typeof options.success === "function") {
let data = null;
- if (xhr.getResponseHeader('Content-Type').split(';', 1)[0].trim() === 'application/json') {
+ if (xhr.getResponseHeader("Content-Type").split(";", 1)[0].trim() === "application/json") {
try {
data = JSON.parse(xhr.responseText);
}
}
// force-invoke the background queue
if (data && data.forceBackgroundQueuePerform) {
- new Promise((resolve_1, reject_1) => { require(['../BackgroundQueue'], resolve_1, reject_1); }).then(tslib_1.__importStar).then(backgroundQueue => backgroundQueue.invoke());
+ new Promise((resolve_1, reject_1) => { require(["../BackgroundQueue"], resolve_1, reject_1); }).then(tslib_1.__importStar).then((backgroundQueue) => backgroundQueue.invoke());
}
}
options.success(data, xhr.responseText, xhr, options.data);
try {
data = JSON.parse(xhr.responseText);
}
- catch (e) {
- }
+ catch (e) { }
let showError = true;
- if (typeof options.failure === 'function') {
- showError = options.failure((data || {}), (xhr.responseText || ''), xhr, options.data);
+ if (typeof options.failure === "function") {
+ showError = options.failure(data || {}, xhr.responseText || "", xhr, options.data);
}
if (options.ignoreError !== true && showError) {
const html = this.getErrorHtml(data, xhr);
if (html) {
- new Promise((resolve_2, reject_2) => { require(['../Ui/Dialog'], resolve_2, reject_2); }).then(tslib_1.__importStar).then(UiDialog => {
+ new Promise((resolve_2, reject_2) => { require(["../Ui/Dialog"], resolve_2, reject_2); }).then(tslib_1.__importStar).then((UiDialog) => {
UiDialog.openStatic(Util_1.default.getUniqueId(), html, {
- title: Language.get('wcf.global.error.title'),
+ title: Language.get("wcf.global.error.title"),
});
});
}
* Returns the inner HTML for an error/exception display.
*/
getErrorHtml(data, xhr) {
- let details = '';
+ let details = "";
let message;
if (data !== null) {
if (data.returnValues && data.returnValues.description) {
- details += '<br><p>Description:</p><p>' + data.returnValues.description + '</p>';
+ details += "<br><p>Description:</p><p>" + data.returnValues.description + "</p>";
}
if (data.file && data.line) {
- details += '<br><p>File:</p><p>' + data.file + ' in line ' + data.line + '</p>';
+ details += "<br><p>File:</p><p>" + data.file + " in line " + data.line + "</p>";
}
if (data.stacktrace)
- details += '<br><p>Stacktrace:</p><p>' + data.stacktrace + '</p>';
+ details += "<br><p>Stacktrace:</p><p>" + data.stacktrace + "</p>";
else if (data.exceptionID)
- details += '<br><p>Exception ID: <code>' + data.exceptionID + '</code></p>';
+ details += "<br><p>Exception ID: <code>" + data.exceptionID + "</code></p>";
message = data.message;
data.previous.forEach(function (previous) {
- details += '<hr><p>' + previous.message + '</p>';
- details += '<br><p>Stacktrace</p><p>' + previous.stacktrace + '</p>';
+ details += "<hr><p>" + previous.message + "</p>";
+ details += "<br><p>Stacktrace</p><p>" + previous.stacktrace + "</p>";
});
}
else {
message = xhr.responseText;
}
- if (!message || message === 'undefined') {
+ if (!message || message === "undefined") {
if (!window.ENABLE_DEBUG_MODE)
return null;
- message = 'XMLHttpRequest failed without a responseText. Check your browser console.';
+ message = "XMLHttpRequest failed without a responseText. Check your browser console.";
}
- return '<div class="ajaxDebugMessage"><p>' + message + '</p>' + details + '</div>';
+ return '<div class="ajaxDebugMessage"><p>' + message + "</p>" + details + "</div>";
}
/**
* Finalizes a request.
* @param {Object} options request options
*/
_finalize(options) {
- if (typeof options.finalize === 'function') {
+ if (typeof options.finalize === "function") {
options.finalize(this._xhr);
}
this._previousXhr = undefined;
// fix anchor tags generated through WCF::getAnchor()
document.querySelectorAll('a[href*="#"]').forEach((link) => {
let href = link.href;
- if (href.indexOf('AJAXProxy') !== -1 || href.indexOf('ajax-proxy') !== -1) {
- href = href.substr(href.indexOf('#'));
- link.href = document.location.toString().replace(/#.*/, '') + href;
+ if (href.indexOf("AJAXProxy") !== -1 || href.indexOf("ajax-proxy") !== -1) {
+ href = href.substr(href.indexOf("#"));
+ link.href = document.location.toString().replace(/#.*/, "") + href;
}
});
}
constructor() {
this._activeRequests = 0;
this._timer = null;
- this._overlay = document.createElement('div');
- this._overlay.classList.add('spinner');
- this._overlay.setAttribute('role', 'status');
- const icon = document.createElement('span');
- icon.className = 'icon icon48 fa-spinner';
+ this._overlay = document.createElement("div");
+ this._overlay.classList.add("spinner");
+ this._overlay.setAttribute("role", "status");
+ const icon = document.createElement("span");
+ icon.className = "icon icon48 fa-spinner";
this._overlay.appendChild(icon);
- const title = document.createElement('span');
- title.textContent = Language.get('wcf.global.loading');
+ const title = document.createElement("span");
+ title.textContent = Language.get("wcf.global.loading");
this._overlay.appendChild(title);
document.body.appendChild(this._overlay);
}
if (this._timer === null) {
this._timer = window.setTimeout(() => {
if (this._activeRequests) {
- this._overlay.classList.add('active');
+ this._overlay.classList.add("active");
}
this._timer = null;
}, 250);
if (this._timer !== null) {
window.clearTimeout(this._timer);
}
- this._overlay.classList.remove('active');
+ this._overlay.classList.remove("active");
}
}
}
*/
function invoke() {
if (!queue) {
- console.error('The background queue has not been initialized yet.');
+ console.error("The background queue has not been initialized yet.");
return;
}
queue.invoke();
* Adds a callback for given identifier.
*/
add(identifier, callback) {
- if (typeof callback !== 'function') {
- throw new TypeError('Expected a valid callback as second argument for identifier \'' + identifier + '\'.');
+ if (typeof callback !== "function") {
+ throw new TypeError("Expected a valid callback as second argument for identifier '" + identifier + "'.");
}
if (!this._callbacks.has(identifier)) {
this._callbacks.set(identifier, []);
function hexToRgb(hex) {
if (/^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(hex)) {
// only convert #abc and #abcdef
- const parts = hex.split('');
+ const parts = hex.split("");
// drop the hashtag
- if (parts[0] === '#') {
+ if (parts[0] === "#") {
parts.shift();
}
// parse shorthand #xyz
if (parts.length === 3) {
return {
- r: parseInt(parts[0] + '' + parts[0], 16),
- g: parseInt(parts[1] + '' + parts[1], 16),
- b: parseInt(parts[2] + '' + parts[2], 16),
+ r: parseInt(parts[0] + "" + parts[0], 16),
+ g: parseInt(parts[1] + "" + parts[1], 16),
+ b: parseInt(parts[2] + "" + parts[2], 16),
};
}
else {
return {
- r: parseInt(parts[0] + '' + parts[1], 16),
- g: parseInt(parts[2] + '' + parts[3], 16),
- b: parseInt(parts[4] + '' + parts[5], 16),
+ r: parseInt(parts[0] + "" + parts[1], 16),
+ g: parseInt(parts[2] + "" + parts[3], 16),
+ b: parseInt(parts[4] + "" + parts[5], 16),
};
}
}
* @see http://www.linuxtopia.org/online_books/javascript_guides/javascript_faq/rgbtohex.htm
*/
function rgbToHex(r, g, b) {
- const charList = '0123456789ABCDEF';
+ const charList = "0123456789ABCDEF";
if (g === undefined) {
if (r.toString().match(/^rgba?\((\d+), ?(\d+), ?(\d+)(?:, ?[0-9.]+)?\)$/)) {
r = +RegExp.$1;
b = +RegExp.$3;
}
}
- return (charList.charAt((r - r % 16) / 16) + '' + charList.charAt(r % 16)) + '' + (charList.charAt((g - g % 16) / 16) + '' + charList.charAt(g % 16)) + '' + (charList.charAt((b - b % 16) / 16) + '' + charList.charAt(b % 16));
+ return (charList.charAt((r - (r % 16)) / 16) +
+ "" +
+ charList.charAt(r % 16) +
+ "" +
+ (charList.charAt((g - (g % 16)) / 16) + "" + charList.charAt(g % 16)) +
+ "" +
+ (charList.charAt((b - (b % 16)) / 16) + "" + charList.charAt(b % 16)));
}
exports.rgbToHex = rgbToHex;
// WCF.ColorPicker compatibility (color format conversion)
Object.defineProperty(exports, "__esModule", { value: true });
exports.debounce = exports.stringToBool = exports.getStoragePrefix = exports.triggerEvent = exports.serialize = exports.getUuid = exports.getType = exports.isPlainObject = exports.inherit = exports.extend = exports.convertLegacyUrl = exports.clone = void 0;
const _clone = function (variable) {
- if (typeof variable === 'object' && (Array.isArray(variable) || isPlainObject(variable))) {
+ if (typeof variable === "object" && (Array.isArray(variable) || isPlainObject(variable))) {
return _cloneObject(variable);
}
return variable;
return obj.slice();
}
const newObj = {};
- Object.keys(obj).forEach(key => newObj[key] = _clone(obj[key]));
+ Object.keys(obj).forEach((key) => (newObj[key] = _clone(obj[key])));
return newObj;
};
- const _prefix = 'wsc' + window.WCF_PATH.hashCode() + '-';
+ const _prefix = "wsc" + window.WCF_PATH.hashCode() + "-";
/**
* Deep clones an object.
*/
function convertLegacyUrl(url) {
return url.replace(/^index\.php\/(.*?)\/\?/, (match, controller) => {
const parts = controller.split(/([A-Z][a-z0-9]+)/);
- controller = '';
+ controller = "";
for (let i = 0, length = parts.length; i < length; i++) {
const part = parts[i].trim();
if (part.length) {
if (controller.length)
- controller += '-';
+ controller += "-";
controller += part.toLowerCase();
}
}
continue;
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
- if (!Array.isArray(obj[key]) && typeof obj[key] === 'object') {
+ if (!Array.isArray(obj[key]) && typeof obj[key] === "object") {
if (isPlainObject(obj[key])) {
// object literals have the prototype of Object which in return has no parent prototype
newObj[key] = extend(out[key], obj[key]);
*/
function inherit(constructor, superConstructor, propertiesObject) {
if (constructor === undefined || constructor === null) {
- throw new TypeError('The constructor must not be undefined or null.');
+ throw new TypeError("The constructor must not be undefined or null.");
}
if (superConstructor === undefined || superConstructor === null) {
- throw new TypeError('The super constructor must not be undefined or null.');
+ throw new TypeError("The super constructor must not be undefined or null.");
}
if (superConstructor.prototype === undefined) {
- throw new TypeError('The super constructor must have a prototype.');
+ throw new TypeError("The super constructor must have a prototype.");
}
constructor._super = superConstructor;
constructor.prototype = extend(Object.create(superConstructor.prototype, {
* Returns true if `obj` is an object literal.
*/
function isPlainObject(obj) {
- if (typeof obj !== 'object' || obj === null || obj.nodeType) {
+ if (typeof obj !== "object" || obj === null || obj.nodeType) {
return false;
}
- return (Object.getPrototypeOf(obj) === Object.prototype);
+ return Object.getPrototypeOf(obj) === Object.prototype;
}
exports.isPlainObject = isPlainObject;
/**
* Returns the object's class name.
*/
function getType(obj) {
- return Object.prototype.toString.call(obj).replace(/^\[object (.+)]$/, '$1');
+ return Object.prototype.toString.call(obj).replace(/^\[object (.+)]$/, "$1");
}
exports.getType = getType;
/**
* @see http://stackoverflow.com/a/2117523
*/
function getUuid() {
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
- const r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
+ const r = (Math.random() * 16) | 0, v = c == "x" ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}
let parameters = [];
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
- const parameterKey = (prefix) ? prefix + '[' + key + ']' : key;
+ const parameterKey = prefix ? prefix + "[" + key + "]" : key;
const value = obj[key];
- if (typeof value === 'object') {
+ if (typeof value === "object") {
parameters.push(serialize(value, parameterKey));
}
else {
- parameters.push(encodeURIComponent(parameterKey) + '=' + encodeURIComponent(value));
+ parameters.push(encodeURIComponent(parameterKey) + "=" + encodeURIComponent(value));
}
}
}
- return parameters.join('&');
+ return parameters.join("&");
}
exports.serialize = serialize;
/**
* legacy functions `elAttrBool()` and `elDataBool()`.
*/
function stringToBool(value) {
- return value === '1' || value === 'true';
+ return value === "1" || value === "true";
}
exports.stringToBool = stringToBool;
/**
if (_datePicker !== null) {
return;
}
- _datePicker = document.createElement('div');
- _datePicker.className = 'datePicker';
- _datePicker.addEventListener('click', event => {
+ _datePicker = document.createElement("div");
+ _datePicker.className = "datePicker";
+ _datePicker.addEventListener("click", (event) => {
event.stopPropagation();
});
- const header = document.createElement('header');
+ const header = document.createElement("header");
_datePicker.appendChild(header);
- _dateMonthPrevious = document.createElement('a');
- _dateMonthPrevious.className = 'previous jsTooltip';
- _dateMonthPrevious.href = '#';
- _dateMonthPrevious.setAttribute('role', 'button');
+ _dateMonthPrevious = document.createElement("a");
+ _dateMonthPrevious.className = "previous jsTooltip";
+ _dateMonthPrevious.href = "#";
+ _dateMonthPrevious.setAttribute("role", "button");
_dateMonthPrevious.tabIndex = 0;
- _dateMonthPrevious.title = Language.get('wcf.date.datePicker.previousMonth');
- _dateMonthPrevious.setAttribute('aria-label', Language.get('wcf.date.datePicker.previousMonth'));
+ _dateMonthPrevious.title = Language.get("wcf.date.datePicker.previousMonth");
+ _dateMonthPrevious.setAttribute("aria-label", Language.get("wcf.date.datePicker.previousMonth"));
_dateMonthPrevious.innerHTML = '<span class="icon icon16 fa-arrow-left"></span>';
- _dateMonthPrevious.addEventListener('click', DatePicker.previousMonth);
+ _dateMonthPrevious.addEventListener("click", DatePicker.previousMonth);
header.appendChild(_dateMonthPrevious);
- const monthYearContainer = document.createElement('span');
+ const monthYearContainer = document.createElement("span");
header.appendChild(monthYearContainer);
- _dateMonth = document.createElement('select');
- _dateMonth.className = 'month jsTooltip';
- _dateMonth.title = Language.get('wcf.date.datePicker.month');
- _dateMonth.setAttribute('aria-label', Language.get('wcf.date.datePicker.month'));
- _dateMonth.addEventListener('change', changeMonth);
+ _dateMonth = document.createElement("select");
+ _dateMonth.className = "month jsTooltip";
+ _dateMonth.title = Language.get("wcf.date.datePicker.month");
+ _dateMonth.setAttribute("aria-label", Language.get("wcf.date.datePicker.month"));
+ _dateMonth.addEventListener("change", changeMonth);
monthYearContainer.appendChild(_dateMonth);
- let months = '';
- const monthNames = Language.get('__monthsShort');
+ let months = "";
+ const monthNames = Language.get("__monthsShort");
for (let i = 0; i < 12; i++) {
- months += '<option value="' + i + '">' + monthNames[i] + '</option>';
+ months += '<option value="' + i + '">' + monthNames[i] + "</option>";
}
_dateMonth.innerHTML = months;
- _dateYear = document.createElement('select');
- _dateYear.className = 'year jsTooltip';
- _dateYear.title = Language.get('wcf.date.datePicker.year');
- _dateYear.setAttribute('aria-label', Language.get('wcf.date.datePicker.year'));
- _dateYear.addEventListener('change', changeYear);
+ _dateYear = document.createElement("select");
+ _dateYear.className = "year jsTooltip";
+ _dateYear.title = Language.get("wcf.date.datePicker.year");
+ _dateYear.setAttribute("aria-label", Language.get("wcf.date.datePicker.year"));
+ _dateYear.addEventListener("change", changeYear);
monthYearContainer.appendChild(_dateYear);
- _dateMonthNext = document.createElement('a');
- _dateMonthNext.className = 'next jsTooltip';
- _dateMonthNext.href = '#';
- _dateMonthNext.setAttribute('role', 'button');
+ _dateMonthNext = document.createElement("a");
+ _dateMonthNext.className = "next jsTooltip";
+ _dateMonthNext.href = "#";
+ _dateMonthNext.setAttribute("role", "button");
_dateMonthNext.tabIndex = 0;
- _dateMonthNext.title = Language.get('wcf.date.datePicker.nextMonth');
- _dateMonthNext.setAttribute('aria-label', Language.get('wcf.date.datePicker.nextMonth'));
+ _dateMonthNext.title = Language.get("wcf.date.datePicker.nextMonth");
+ _dateMonthNext.setAttribute("aria-label", Language.get("wcf.date.datePicker.nextMonth"));
_dateMonthNext.innerHTML = '<span class="icon icon16 fa-arrow-right"></span>';
- _dateMonthNext.addEventListener('click', DatePicker.nextMonth);
+ _dateMonthNext.addEventListener("click", DatePicker.nextMonth);
header.appendChild(_dateMonthNext);
- _dateGrid = document.createElement('ul');
+ _dateGrid = document.createElement("ul");
_datePicker.appendChild(_dateGrid);
- const item = document.createElement('li');
- item.className = 'weekdays';
+ const item = document.createElement("li");
+ item.className = "weekdays";
_dateGrid.appendChild(item);
- const weekdays = Language.get('__daysShort');
+ const weekdays = Language.get("__daysShort");
for (let i = 0; i < 7; i++) {
let day = i + _firstDayOfWeek;
if (day > 6)
day -= 7;
- const span = document.createElement('span');
+ const span = document.createElement("span");
span.textContent = weekdays[day];
item.appendChild(span);
}
// create date grid
for (let i = 0; i < 6; i++) {
- const row = document.createElement('li');
+ const row = document.createElement("li");
_dateGrid.appendChild(row);
for (let j = 0; j < 7; j++) {
- const cell = document.createElement('a');
- cell.addEventListener('click', click);
+ const cell = document.createElement("a");
+ cell.addEventListener("click", click);
_dateCells.push(cell);
row.appendChild(cell);
}
}
- _dateTime = document.createElement('footer');
+ _dateTime = document.createElement("footer");
_datePicker.appendChild(_dateTime);
- _dateHour = document.createElement('select');
- _dateHour.className = 'hour';
- _dateHour.title = Language.get('wcf.date.datePicker.hour');
- _dateHour.setAttribute('aria-label', Language.get('wcf.date.datePicker.hour'));
- _dateHour.addEventListener('change', formatValue);
+ _dateHour = document.createElement("select");
+ _dateHour.className = "hour";
+ _dateHour.title = Language.get("wcf.date.datePicker.hour");
+ _dateHour.setAttribute("aria-label", Language.get("wcf.date.datePicker.hour"));
+ _dateHour.addEventListener("change", formatValue);
const date = new Date(2000, 0, 1);
- const timeFormat = Language.get('wcf.date.timeFormat').replace(/:/, '').replace(/[isu]/g, '');
- let tmp = '';
+ const timeFormat = Language.get("wcf.date.timeFormat").replace(/:/, "").replace(/[isu]/g, "");
+ let tmp = "";
for (let i = 0; i < 24; i++) {
date.setHours(i);
tmp += '<option value="' + i + '">' + DateUtil.format(date, timeFormat) + "</option>";
}
_dateHour.innerHTML = tmp;
_dateTime.appendChild(_dateHour);
- _dateTime.appendChild(document.createTextNode('\u00A0:\u00A0'));
- _dateMinute = document.createElement('select');
- _dateMinute.className = 'minute';
- _dateMinute.title = Language.get('wcf.date.datePicker.minute');
- _dateMinute.setAttribute('aria-label', Language.get('wcf.date.datePicker.minute'));
- _dateMinute.addEventListener('change', formatValue);
- tmp = '';
+ _dateTime.appendChild(document.createTextNode("\u00A0:\u00A0"));
+ _dateMinute = document.createElement("select");
+ _dateMinute.className = "minute";
+ _dateMinute.title = Language.get("wcf.date.datePicker.minute");
+ _dateMinute.setAttribute("aria-label", Language.get("wcf.date.datePicker.minute"));
+ _dateMinute.addEventListener("change", formatValue);
+ tmp = "";
for (let i = 0; i < 60; i++) {
- tmp += '<option value="' + i + '">' + (i < 10 ? '0' + i.toString() : i) + '</option>';
+ tmp += '<option value="' + i + '">' + (i < 10 ? "0" + i.toString() : i) + "</option>";
}
_dateMinute.innerHTML = tmp;
_dateTime.appendChild(_dateMinute);
document.body.appendChild(_datePicker);
- document.body.addEventListener('focus', maintainFocus, { capture: true });
+ document.body.addEventListener("focus", maintainFocus, { capture: true });
}
/**
* Initializes the minimum/maximum date range.
*/
function initDateRange(element, now, isMinDate) {
- const name = isMinDate ? 'minDate' : 'maxDate';
- let value = (element.dataset[name] || '').trim();
+ const name = isMinDate ? "minDate" : "maxDate";
+ let value = (element.dataset[name] || "").trim();
if (value.match(/^(\d{4})-(\d{2})-(\d{2})$/)) {
// YYYY-mm-dd
value = new Date(value).getTime().toString();
}
- else if (value === 'now') {
+ else if (value === "now") {
value = now.getTime().toString();
}
else if (value.match(/^\d{1,3}$/)) {
value = new Date(value).getTime().toString();
}
else {
- value = new Date((isMinDate ? 1902 : 2038), 0, 1).getTime().toString();
+ value = new Date(isMinDate ? 1902 : 2038, 0, 1).getTime().toString();
}
element.dataset[name] = value;
}
if (_didInit)
return;
_didInit = true;
- _firstDayOfWeek = parseInt(Language.get('wcf.date.firstDayOfTheWeek'), 10);
- Listener_1.default.add('WoltLabSuite/Core/Date/Picker', DatePicker.init);
- CloseOverlay_1.default.add('WoltLabSuite/Core/Date/Picker', close);
+ _firstDayOfWeek = parseInt(Language.get("wcf.date.firstDayOfTheWeek"), 10);
+ Listener_1.default.add("WoltLabSuite/Core/Date/Picker", DatePicker.init);
+ CloseOverlay_1.default.add("WoltLabSuite/Core/Date/Picker", close);
}
function getDateValue(attributeName) {
- let date = _input.dataset[attributeName] || '';
+ let date = _input.dataset[attributeName] || "";
if (date.match(/^datePicker-(.+)$/)) {
const referenceElement = document.getElementById(RegExp.$1);
if (referenceElement === null) {
throw new Error(`Unable to find an element with the id '${RegExp.$1}'.`);
}
- date = referenceElement.dataset.value || '';
+ date = referenceElement.dataset.value || "";
}
return new Date(parseInt(date, 10));
}
event.stopPropagation();
createPicker();
const target = event.currentTarget;
- const input = (target.nodeName === 'INPUT') ? target : target.previousElementSibling;
+ const input = target.nodeName === "INPUT" ? target : target.previousElementSibling;
if (input === _input) {
close();
return;
}
- const dialogContent = input.closest('.dialogContent');
+ const dialogContent = input.closest(".dialogContent");
if (dialogContent !== null) {
- if (!Core.stringToBool(dialogContent.dataset.hasDatepickerScrollListener || '')) {
- dialogContent.addEventListener('scroll', onDialogScroll);
- dialogContent.dataset.hasDatepickerScrollListener = '1';
+ if (!Core.stringToBool(dialogContent.dataset.hasDatepickerScrollListener || "")) {
+ dialogContent.addEventListener("scroll", onDialogScroll);
+ dialogContent.dataset.hasDatepickerScrollListener = "1";
}
}
_input = input;
let date;
if (value) {
date = new Date(parseInt(value, 10));
- if (date.toString() === 'Invalid Date') {
+ if (date.toString() === "Invalid Date") {
date = new Date();
}
}
date = new Date();
}
// set min/max date
- _minDate = getDateValue('minDate');
+ _minDate = getDateValue("minDate");
if (_minDate.getTime() > date.getTime()) {
date = _minDate;
}
- _maxDate = getDateValue('maxDate');
+ _maxDate = getDateValue("maxDate");
if (data.isDateTime) {
_dateHour.value = date.getHours().toString();
_dateMinute.value = date.getMinutes().toString();
- _datePicker.classList.add('datePickerTime');
+ _datePicker.classList.add("datePickerTime");
}
else {
- _datePicker.classList.remove('datePickerTime');
+ _datePicker.classList.remove("datePickerTime");
}
- _datePicker.classList[(data.isTimeOnly) ? 'add' : 'remove']('datePickerTimeOnly');
+ _datePicker.classList[data.isTimeOnly ? "add" : "remove"]("datePickerTimeOnly");
renderPicker(date.getDate(), date.getMonth(), date.getFullYear());
UiAlignment.set(_datePicker, _input);
- _input.nextElementSibling.setAttribute('aria-expanded', 'true');
+ _input.nextElementSibling.setAttribute("aria-expanded", "true");
_wasInsidePicker = false;
}
/**
* Closes the date picker.
*/
function close() {
- if (_datePicker === null || !_datePicker.classList.contains('active')) {
+ if (_datePicker === null || !_datePicker.classList.contains("active")) {
return;
}
- _datePicker.classList.remove('active');
+ _datePicker.classList.remove("active");
const data = _data.get(_input);
- if (typeof data.onClose === 'function') {
+ if (typeof data.onClose === "function") {
data.onClose();
}
- EventHandler.fire('WoltLabSuite/Core/Date/Picker', 'close', { element: _input });
+ EventHandler.fire("WoltLabSuite/Core/Date/Picker", "close", { element: _input });
const sibling = _input.nextElementSibling;
- sibling.setAttribute('aria-expanded', 'false');
+ sibling.setAttribute("aria-expanded", "false");
_input = null;
}
/**
function renderPicker(day, month, year) {
renderGrid(day, month, year);
// create options for month and year
- let years = '';
+ let years = "";
for (let i = _minDate.getFullYear(), last = _maxDate.getFullYear(); i <= last; i++) {
- years += '<option value="' + i + '">' + i + '</option>';
+ years += '<option value="' + i + '">' + i + "</option>";
}
_dateYear.innerHTML = years;
_dateYear.value = year.toString();
_dateMonth.value = month.toString();
- _datePicker.classList.add('active');
+ _datePicker.classList.add("active");
}
/**
* Updates the date grid.
*/
function renderGrid(day, month, year) {
- const hasDay = (day !== undefined);
- const hasMonth = (month !== undefined);
- if (typeof day !== 'number') {
- day = parseInt(day || _dateGrid.dataset.day || '0', 10);
+ const hasDay = day !== undefined;
+ const hasMonth = month !== undefined;
+ if (typeof day !== "number") {
+ day = parseInt(day || _dateGrid.dataset.day || "0", 10);
}
- if (typeof month !== 'number') {
- month = parseInt(month || '0', 10);
+ if (typeof month !== "number") {
+ month = parseInt(month || "0", 10);
}
- if (typeof year !== 'number') {
- year = parseInt(year || '0', 10);
+ if (typeof year !== "number") {
+ year = parseInt(year || "0", 10);
}
// rebuild cells
if (hasMonth || year) {
- let rebuildMonths = (year !== 0);
+ let rebuildMonths = year !== 0;
// rebuild grid
const fragment = document.createDocumentFragment();
fragment.appendChild(_dateGrid);
year = parseInt(_dateGrid.dataset.year, 10);
}
// check if current selection exceeds min/max date
- let date = new Date(year + '-' + ('0' + (month + 1).toString()).slice(-2) + '-' + ('0' + day.toString()).slice(-2));
+ let date = new Date(year + "-" + ("0" + (month + 1).toString()).slice(-2) + "-" + ("0" + day.toString()).slice(-2));
if (date < _minDate) {
year = _minDate.getFullYear();
month = _minDate.getMonth();
_dateYear.value = year.toString();
rebuildMonths = true;
}
- date = new Date(year + '-' + ('0' + (month + 1).toString()).slice(-2) + '-01');
+ date = new Date(year + "-" + ("0" + (month + 1).toString()).slice(-2) + "-01");
// shift until first displayed day equals first day of week
while (date.getDay() !== _firstDayOfWeek) {
date.setDate(date.getDate() - 1);
}
const cell = _dateCells[i];
cell.textContent = date.getDate().toString();
- selectable = (date.getMonth() === month);
+ selectable = date.getMonth() === month;
if (selectable) {
if (date < comparableMinDate)
selectable = false;
else if (date > _maxDate)
selectable = false;
}
- cell.classList[selectable ? 'remove' : 'add']('otherMonth');
+ cell.classList[selectable ? "remove" : "add"]("otherMonth");
if (selectable) {
- cell.href = '#';
- cell.setAttribute('role', 'button');
+ cell.href = "#";
+ cell.setAttribute("role", "button");
cell.tabIndex = 0;
cell.title = DateUtil.formatDate(date);
- cell.setAttribute('aria-label', DateUtil.formatDate(date));
+ cell.setAttribute("aria-label", DateUtil.formatDate(date));
}
date.setDate(date.getDate() + 1);
}
if (rebuildMonths) {
for (let i = 0; i < 12; i++) {
const currentMonth = _dateMonth.children[i];
- currentMonth.disabled = (year === _minDate.getFullYear() && +currentMonth.value < _minDate.getMonth()) || (year === _maxDate.getFullYear() && +currentMonth.value > _maxDate.getMonth());
+ currentMonth.disabled =
+ (year === _minDate.getFullYear() && +currentMonth.value < _minDate.getMonth()) ||
+ (year === _maxDate.getFullYear() && +currentMonth.value > _maxDate.getMonth());
}
- const nextMonth = new Date(year + '-' + ('0' + (month + 1).toString()).slice(-2) + '-01');
+ const nextMonth = new Date(year + "-" + ("0" + (month + 1).toString()).slice(-2) + "-01");
nextMonth.setMonth(nextMonth.getMonth() + 1);
- _dateMonthNext.classList[(nextMonth < _maxDate) ? 'add' : 'remove']('active');
- const previousMonth = new Date(year + '-' + ('0' + (month + 1).toString()).slice(-2) + '-01');
+ _dateMonthNext.classList[nextMonth < _maxDate ? "add" : "remove"]("active");
+ const previousMonth = new Date(year + "-" + ("0" + (month + 1).toString()).slice(-2) + "-01");
previousMonth.setDate(previousMonth.getDate() - 1);
- _dateMonthPrevious.classList[(previousMonth > _minDate) ? 'add' : 'remove']('active');
+ _dateMonthPrevious.classList[previousMonth > _minDate ? "add" : "remove"]("active");
}
}
// update active day
if (day) {
for (let i = 0; i < 35; i++) {
const cell = _dateCells[i];
- cell.classList[(!cell.classList.contains('otherMonth') && +cell.textContent === day) ? 'add' : 'remove']('active');
+ cell.classList[!cell.classList.contains("otherMonth") && +cell.textContent === day ? "add" : "remove"]("active");
}
_dateGrid.dataset.day = day.toString();
}
function formatValue() {
const data = _data.get(_input);
let date;
- if (Core.stringToBool(_input.dataset.empty || '')) {
+ if (Core.stringToBool(_input.dataset.empty || "")) {
return;
}
if (data.isDateTime) {
function click(event) {
event.preventDefault();
const target = event.currentTarget;
- if (target.classList.contains('otherMonth')) {
+ if (target.classList.contains("otherMonth")) {
return;
}
- _input.dataset.empty = 'false';
+ _input.dataset.empty = "false";
renderGrid(+target.textContent);
const data = _data.get(_input);
if (!data.isDateTime) {
* Validates given element or id if it represents an active date picker.
*/
function getElement(element) {
- if (typeof element === 'string') {
+ if (typeof element === "string") {
element = document.getElementById(element);
}
- if (!(element instanceof HTMLInputElement) || !element.classList.contains('inputDatePicker') || !_data.has(element)) {
+ if (!(element instanceof HTMLInputElement) || !element.classList.contains("inputDatePicker") || !_data.has(element)) {
throw new Error("Expected a valid date picker input element or id.");
}
return element;
}
function maintainFocus(event) {
- if (_datePicker === null || !_datePicker.classList.contains('active')) {
+ if (_datePicker === null || !_datePicker.classList.contains("active")) {
return;
}
if (!_datePicker.contains(event.target)) {
_wasInsidePicker = false;
}
else {
- _datePicker.querySelector('.previous').focus();
+ _datePicker.querySelector(".previous").focus();
}
}
else {
init() {
setup();
const now = new Date();
- document.querySelectorAll('input[type="date"]:not(.inputDatePicker), input[type="datetime"]:not(.inputDatePicker)').forEach(element => {
- element.classList.add('inputDatePicker');
+ document
+ .querySelectorAll('input[type="date"]:not(.inputDatePicker), input[type="datetime"]:not(.inputDatePicker)')
+ .forEach((element) => {
+ element.classList.add("inputDatePicker");
element.readOnly = true;
- const isDateTime = (element.type === 'datetime');
- const isTimeOnly = isDateTime && Core.stringToBool(element.dataset.timeOnly || '');
- const disableClear = Core.stringToBool(element.dataset.disableClear || '');
- const ignoreTimezone = isDateTime && Core.stringToBool(element.dataset.ignoreTimezone || '');
- const isBirthday = element.classList.contains('birthday');
- element.dataset.isDateTime = isDateTime ? 'true' : 'false';
- element.dataset.isTimeOnly = isTimeOnly ? 'true' : 'false';
+ const isDateTime = element.type === "datetime";
+ const isTimeOnly = isDateTime && Core.stringToBool(element.dataset.timeOnly || "");
+ const disableClear = Core.stringToBool(element.dataset.disableClear || "");
+ const ignoreTimezone = isDateTime && Core.stringToBool(element.dataset.ignoreTimezone || "");
+ const isBirthday = element.classList.contains("birthday");
+ element.dataset.isDateTime = isDateTime ? "true" : "false";
+ element.dataset.isTimeOnly = isTimeOnly ? "true" : "false";
// convert value
let date = null;
let value = element.value;
if (value) {
if (isTimeOnly) {
date = new Date();
- const tmp = value.split(':');
+ const tmp = value.split(":");
date.setHours(+tmp[0], +tmp[1]);
}
else {
if (ignoreTimezone || isBirthday || isDateOnly) {
let timezoneOffset = new Date(value).getTimezoneOffset();
- let timezone = (timezoneOffset > 0) ? '-' : '+'; // -120 equals GMT+0200
+ let timezone = timezoneOffset > 0 ? "-" : "+"; // -120 equals GMT+0200
timezoneOffset = Math.abs(timezoneOffset);
- const hours = (Math.floor(timezoneOffset / 60)).toString();
+ const hours = Math.floor(timezoneOffset / 60).toString();
const minutes = (timezoneOffset % 60).toString();
- timezone += (hours.length === 2) ? hours : '0' + hours;
- timezone += ':';
- timezone += (minutes.length === 2) ? minutes : '0' + minutes;
+ timezone += hours.length === 2 ? hours : "0" + hours;
+ timezone += ":";
+ timezone += minutes.length === 2 ? minutes : "0" + minutes;
if (isBirthday || isDateOnly) {
- value += 'T00:00:00' + timezone;
+ value += "T00:00:00" + timezone;
}
else {
value = value.replace(/[+-][0-9]{2}:[0-9]{2}$/, timezone);
const time = date.getTime();
// check for invalid dates
if (isNaN(time)) {
- value = '';
+ value = "";
}
else {
element.dataset.value = time.toString();
- const format = (isTimeOnly) ? 'formatTime' : ('formatDate' + (isDateTime ? 'Time' : ''));
+ const format = isTimeOnly ? "formatTime" : "formatDate" + (isDateTime ? "Time" : "");
value = DateUtil[format](date);
}
}
- const isEmpty = (value.length === 0);
+ const isEmpty = value.length === 0;
// handle birthday input
if (isBirthday) {
- element.dataset.minDate = '120';
- // do not use 'now' here, all though it makes sense, it causes bad UX
- element.dataset.maxDate = new Date().getFullYear() + '-12-31';
+ element.dataset.minDate = "120";
+ // do not use 'now' here, all though it makes sense, it causes bad UX
+ element.dataset.maxDate = new Date().getFullYear() + "-12-31";
}
else {
if (element.min) {
}
initDateRange(element, now, true);
initDateRange(element, now, false);
- if ((element.dataset.minDate || '') === (element.dataset.maxDate || '')) {
+ if ((element.dataset.minDate || "") === (element.dataset.maxDate || "")) {
throw new Error("Minimum and maximum date cannot be the same (element id '" + element.id + "').");
}
// change type to prevent browser's datepicker to trigger
- element.type = 'text';
+ element.type = "text";
element.value = value;
- element.dataset.empty = isEmpty ? 'true' : 'false';
- const placeholder = element.dataset.placeholder || '';
+ element.dataset.empty = isEmpty ? "true" : "false";
+ const placeholder = element.dataset.placeholder || "";
if (placeholder) {
element.placeholder = placeholder;
}
// add a hidden element to hold the actual date
- const shadowElement = document.createElement('input');
- shadowElement.id = element.id + 'DatePicker';
+ const shadowElement = document.createElement("input");
+ shadowElement.id = element.id + "DatePicker";
shadowElement.name = element.name;
- shadowElement.type = 'hidden';
+ shadowElement.type = "hidden";
if (date !== null) {
if (isTimeOnly) {
- shadowElement.value = DateUtil.format(date, 'H:i');
+ shadowElement.value = DateUtil.format(date, "H:i");
}
else if (ignoreTimezone) {
- shadowElement.value = DateUtil.format(date, 'Y-m-dTH:i:s');
+ shadowElement.value = DateUtil.format(date, "Y-m-dTH:i:s");
}
else {
- shadowElement.value = DateUtil.format(date, (isDateTime) ? 'c' : 'Y-m-d');
+ shadowElement.value = DateUtil.format(date, isDateTime ? "c" : "Y-m-d");
}
}
element.parentNode.insertBefore(shadowElement, element);
- element.removeAttribute('name');
- element.addEventListener('click', open);
+ element.removeAttribute("name");
+ element.addEventListener("click", open);
let clearButton = null;
if (!element.disabled) {
// create input addon
- const container = document.createElement('div');
- container.className = 'inputAddon';
- clearButton = document.createElement('a');
- clearButton.className = 'inputSuffix button jsTooltip';
- clearButton.href = '#';
- clearButton.setAttribute('role', 'button');
+ const container = document.createElement("div");
+ container.className = "inputAddon";
+ clearButton = document.createElement("a");
+ clearButton.className = "inputSuffix button jsTooltip";
+ clearButton.href = "#";
+ clearButton.setAttribute("role", "button");
clearButton.tabIndex = 0;
- clearButton.title = Language.get('wcf.date.datePicker');
- clearButton.setAttribute('aria-label', Language.get('wcf.date.datePicker'));
- clearButton.setAttribute('aria-haspopup', 'true');
- clearButton.setAttribute('aria-expanded', 'false');
- clearButton.addEventListener('click', open);
+ clearButton.title = Language.get("wcf.date.datePicker");
+ clearButton.setAttribute("aria-label", Language.get("wcf.date.datePicker"));
+ clearButton.setAttribute("aria-haspopup", "true");
+ clearButton.setAttribute("aria-expanded", "false");
+ clearButton.addEventListener("click", open);
container.appendChild(clearButton);
- let icon = document.createElement('span');
- icon.className = 'icon icon16 fa-calendar';
+ let icon = document.createElement("span");
+ icon.className = "icon icon16 fa-calendar";
clearButton.appendChild(icon);
element.parentNode.insertBefore(container, element);
container.insertBefore(element, clearButton);
if (!disableClear) {
- const button = document.createElement('a');
- button.className = 'inputSuffix button';
- button.addEventListener('click', this.clear.bind(this, element));
+ const button = document.createElement("a");
+ button.className = "inputSuffix button";
+ button.addEventListener("click", this.clear.bind(this, element));
if (isEmpty)
- button.style.setProperty('visibility', 'hidden', '');
+ button.style.setProperty("visibility", "hidden", "");
container.appendChild(button);
- icon = document.createElement('span');
- icon.className = 'icon icon16 fa-times';
+ icon = document.createElement("span");
+ icon.className = "icon icon16 fa-times";
button.appendChild(icon);
}
}
// check if the date input has one of the following classes set otherwise default to 'short'
- const knownClasses = ['tiny', 'short', 'medium', 'long'];
+ const knownClasses = ["tiny", "short", "medium", "long"];
let hasClass = false;
for (let j = 0; j < 4; j++) {
if (element.classList.contains(knownClasses[j])) {
}
}
if (!hasClass) {
- element.classList.add('short');
+ element.classList.add("short");
}
_data.set(element, {
clearButton,
*/
previousMonth(event) {
event.preventDefault();
- if (_dateMonth.value === '0') {
- _dateMonth.value = '11';
+ if (_dateMonth.value === "0") {
+ _dateMonth.value = "11";
_dateYear.value = (+_dateYear.value - 1).toString();
}
else {
*/
nextMonth(event) {
event.preventDefault();
- if (_dateMonth.value === '11') {
- _dateMonth.value = '0';
+ if (_dateMonth.value === "11") {
+ _dateMonth.value = "0";
_dateYear.value = (+_dateYear.value + 1).toString();
}
else {
*/
getDate(element) {
element = getElement(element);
- const value = element.dataset.value || '';
+ const value = element.dataset.value || "";
if (value) {
return new Date(+value);
}
element = getElement(element);
const data = _data.get(element);
element.dataset.value = date.getTime().toString();
- let format = '';
+ let format = "";
let value;
if (data.isDateTime) {
if (data.isTimeOnly) {
value = DateUtil.formatTime(date);
- format = 'H:i';
+ format = "H:i";
}
else if (data.ignoreTimezone) {
value = DateUtil.formatDateTime(date);
- format = 'Y-m-dTH:i:s';
+ format = "Y-m-dTH:i:s";
}
else {
value = DateUtil.formatDateTime(date);
- format = 'c';
+ format = "c";
}
}
else {
value = DateUtil.formatDate(date);
- format = 'Y-m-d';
+ format = "Y-m-d";
}
element.value = value;
data.shadow.value = DateUtil.format(date, format);
// show clear button
if (!data.disableClear) {
- data.clearButton.style.removeProperty('visibility');
+ data.clearButton.style.removeProperty("visibility");
}
},
/**
if (data) {
return data.shadow.value;
}
- return '';
+ return "";
},
/**
* Clears the date value of given element.
clear(element) {
element = getElement(element);
const data = _data.get(element);
- element.removeAttribute('data-value');
- element.value = '';
+ element.removeAttribute("data-value");
+ element.value = "";
if (!data.disableClear) {
- data.clearButton.style.setProperty('visibility', 'hidden', '');
+ data.clearButton.style.setProperty("visibility", "hidden", "");
}
data.isEmpty = true;
- data.shadow.value = '';
+ data.shadow.value = "";
},
/**
* Reverts the date picker into a normal input field.
const container = element.parentNode;
container.parentNode.insertBefore(element, container);
container.remove();
- element.type = 'date' + (data.isDateTime ? 'time' : '');
+ element.type = "date" + (data.isDateTime ? "time" : "");
element.name = data.shadow.name;
element.value = data.shadow.value;
- element.removeAttribute('data-value');
- element.removeEventListener('click', open);
+ element.removeAttribute("data-value");
+ element.removeEventListener("click", open);
data.shadow.remove();
- element.classList.remove('inputDatePicker');
+ element.classList.remove("inputDatePicker");
element.readOnly = false;
_data.delete(element);
},
const timestamp = (date.getTime() - date.getMilliseconds()) / 1000;
if (_offset === null)
_offset = timestamp - window.TIME_NOW;
- document.querySelectorAll('time').forEach(element => {
+ document.querySelectorAll("time").forEach((element) => {
rebuild(element, date, timestamp);
});
}
function rebuild(element, date, timestamp) {
- if (!element.classList.contains('datetime') || Core.stringToBool(element.dataset.isFutureDate || '')) {
+ if (!element.classList.contains("datetime") || Core.stringToBool(element.dataset.isFutureDate || "")) {
return;
}
const elTimestamp = parseInt(element.dataset.timestamp, 10) + _offset;
const elTime = element.dataset.time;
const elOffset = element.dataset.offset;
if (!element.title) {
- element.title = Language.get('wcf.date.dateTimeFormat').replace(/%date%/, elDate).replace(/%time%/, elTime);
+ element.title = Language.get("wcf.date.dateTimeFormat")
+ .replace(/%date%/, elDate)
+ .replace(/%time%/, elTime);
}
// timestamp is less than 60 seconds ago
- if (elTimestamp >= timestamp || timestamp < (elTimestamp + 60)) {
- element.textContent = Language.get('wcf.date.relative.now');
+ if (elTimestamp >= timestamp || timestamp < elTimestamp + 60) {
+ element.textContent = Language.get("wcf.date.relative.now");
}
// timestamp is less than 60 minutes ago (display 1 hour ago rather than 60 minutes ago)
- else if (timestamp < (elTimestamp + 3540)) {
+ else if (timestamp < elTimestamp + 3540) {
const minutes = Math.max(Math.round((timestamp - elTimestamp) / 60), 1);
- element.textContent = Language.get('wcf.date.relative.minutes', { minutes: minutes });
+ element.textContent = Language.get("wcf.date.relative.minutes", { minutes: minutes });
}
// timestamp is less than 24 hours ago
- else if (timestamp < (elTimestamp + 86400)) {
+ else if (timestamp < elTimestamp + 86400) {
const hours = Math.round((timestamp - elTimestamp) / 3600);
- element.textContent = Language.get('wcf.date.relative.hours', { hours: hours });
+ element.textContent = Language.get("wcf.date.relative.hours", { hours: hours });
}
// timestamp is less than 6 days ago
- else if (timestamp < (elTimestamp + 518400)) {
+ else if (timestamp < elTimestamp + 518400) {
const midnight = new Date(date.getFullYear(), date.getMonth(), date.getDate());
const days = Math.ceil((midnight.getTime() / 1000 - elTimestamp) / 86400);
// get day of week
- const dateObj = DateUtil.getTimezoneDate((elTimestamp * 1000), parseInt(elOffset, 10) * 1000);
+ const dateObj = DateUtil.getTimezoneDate(elTimestamp * 1000, parseInt(elOffset, 10) * 1000);
const dow = dateObj.getDay();
- const day = Language.get('__days')[dow];
- element.textContent = Language.get('wcf.date.relative.pastDays', { days: days, day: day, time: elTime });
+ const day = Language.get("__days")[dow];
+ element.textContent = Language.get("wcf.date.relative.pastDays", { days: days, day: day, time: elTime });
}
// timestamp is between ~700 million years BC and last week
else {
- element.textContent = Language.get('wcf.date.shortDateTimeFormat').replace(/%date%/, elDate).replace(/%time%/, elTime);
+ element.textContent = Language.get("wcf.date.shortDateTimeFormat")
+ .replace(/%date%/, elDate)
+ .replace(/%time%/, elTime);
}
}
/**
*/
function setup() {
new Repeating_1.default(refresh, 60000);
- Listener_1.default.add('WoltLabSuite/Core/Date/Time/Relative', refresh);
- document.addEventListener('visibilitychange', onVisibilityChange);
+ Listener_1.default.add("WoltLabSuite/Core/Date/Time/Relative", refresh);
+ document.addEventListener("visibilitychange", onVisibilityChange);
}
exports.setup = setup;
});
* Returns the formatted date.
*/
function formatDate(date) {
- return format(date, Language.get('wcf.date.dateFormat'));
+ return format(date, Language.get("wcf.date.dateFormat"));
}
exports.formatDate = formatDate;
/**
* Returns the formatted time.
*/
function formatTime(date) {
- return format(date, Language.get('wcf.date.timeFormat'));
+ return format(date, Language.get("wcf.date.timeFormat"));
}
exports.formatTime = formatTime;
/**
* Returns the formatted date time.
*/
function formatDateTime(date) {
- const dateTimeFormat = Language.get('wcf.date.dateTimeFormat');
- const dateFormat = Language.get('wcf.date.dateFormat');
- const timeFormat = Language.get('wcf.date.timeFormat');
+ const dateTimeFormat = Language.get("wcf.date.dateTimeFormat");
+ const dateFormat = Language.get("wcf.date.dateFormat");
+ const timeFormat = Language.get("wcf.date.timeFormat");
return format(date, dateTimeFormat.replace(/%date%/, dateFormat).replace(/%time%/, timeFormat));
}
exports.formatDateTime = formatDateTime;
*/
function format(date, format) {
let char;
- let out = '';
+ let out = "";
// ISO 8601 date, best recognition by PHP's strtotime()
- if (format === 'c') {
- format = 'Y-m-dTH:i:sP';
+ if (format === "c") {
+ format = "Y-m-dTH:i:sP";
}
for (let i = 0, length = format.length; i < length; i++) {
let hours;
switch (format[i]) {
// seconds
- case 's':
+ case "s":
// `00` through `59`
- char = ('0' + date.getSeconds().toString()).slice(-2);
+ char = ("0" + date.getSeconds().toString()).slice(-2);
break;
// minutes
- case 'i':
+ case "i":
// `00` through `59`
- char = date.getMinutes().toString().padStart(2, '0');
+ char = date.getMinutes().toString().padStart(2, "0");
break;
// hours
- case 'a':
+ case "a":
// `am` or `pm`
- char = (date.getHours() > 11) ? 'pm' : 'am';
+ char = date.getHours() > 11 ? "pm" : "am";
break;
- case 'g':
+ case "g":
// `1` through `12`
hours = date.getHours();
if (hours === 0)
- char = '12';
+ char = "12";
else if (hours > 12)
char = (hours - 12).toString();
else
char = hours.toString();
break;
- case 'h':
+ case "h":
// `01` through `12`
hours = date.getHours();
if (hours === 0)
- char = '12';
+ char = "12";
else if (hours > 12)
char = (hours - 12).toString();
else
char = hours.toString();
- char = char.padStart(2, '0');
+ char = char.padStart(2, "0");
break;
- case 'A':
+ case "A":
// `AM` or `PM`
- char = (date.getHours() > 11) ? 'PM' : 'AM';
+ char = date.getHours() > 11 ? "PM" : "AM";
break;
- case 'G':
+ case "G":
// `0` through `23`
char = date.getHours().toString();
break;
- case 'H':
+ case "H":
// `00` through `23`
- char = date.getHours().toString().padStart(2, '0');
+ char = date.getHours().toString().padStart(2, "0");
break;
// day
- case 'd':
+ case "d":
// `01` through `31`
- char = date.getDate().toString().padStart(2, '0');
+ char = date.getDate().toString().padStart(2, "0");
break;
- case 'j':
+ case "j":
// `1` through `31`
char = date.getDate().toString();
break;
- case 'l':
+ case "l":
// `Monday` through `Sunday` (localized)
- char = Language.get('__days')[date.getDay()];
+ char = Language.get("__days")[date.getDay()];
break;
- case 'D':
+ case "D":
// `Mon` through `Sun` (localized)
- char = Language.get('__daysShort')[date.getDay()];
+ char = Language.get("__daysShort")[date.getDay()];
break;
- case 'S':
+ case "S":
// ignore english ordinal suffix
- char = '';
+ char = "";
break;
// month
- case 'm':
+ case "m":
// `01` through `12`
- char = (date.getMonth() + 1).toString().padStart(2, '0');
+ char = (date.getMonth() + 1).toString().padStart(2, "0");
break;
- case 'n':
+ case "n":
// `1` through `12`
char = (date.getMonth() + 1).toString();
break;
- case 'F':
+ case "F":
// `January` through `December` (localized)
- char = Language.get('__months')[date.getMonth()];
+ char = Language.get("__months")[date.getMonth()];
break;
- case 'M':
+ case "M":
// `Jan` through `Dec` (localized)
- char = Language.get('__monthsShort')[date.getMonth()];
+ char = Language.get("__monthsShort")[date.getMonth()];
break;
// year
- case 'y':
+ case "y":
// `00` through `99`
char = date.getFullYear().toString().substr(2);
break;
- case 'Y':
+ case "Y":
// Examples: `1988` or `2015`
char = date.getFullYear().toString();
break;
// timezone
- case 'P':
+ case "P":
let offset = date.getTimezoneOffset();
- char = (offset > 0) ? '-' : '+';
+ char = offset > 0 ? "-" : "+";
offset = Math.abs(offset);
- char += ('0' + (~~(offset / 60)).toString()).slice(-2);
- char += ':';
- char += ('0' + (offset % 60).toString()).slice(-2);
+ char += ("0" + (~~(offset / 60)).toString()).slice(-2);
+ char += ":";
+ char += ("0" + (offset % 60).toString()).slice(-2);
break;
// specials
- case 'r':
+ case "r":
char = date.toString();
break;
- case 'U':
+ case "U":
char = Math.round(date.getTime() / 1000).toString();
break;
// escape sequence
- case '\\':
- char = '';
+ case "\\":
+ char = "";
if (i + 1 < length) {
char = format[++i];
}
* (for dates not in the future) after the DOM change listener has been triggered.
*/
function getTimeElement(date) {
- const time = document.createElement('time');
- time.className = 'datetime';
+ const time = document.createElement("time");
+ time.className = "datetime";
const formattedDate = formatDate(date);
const formattedTime = formatTime(date);
- time.setAttribute('datetime', format(date, 'c'));
+ time.setAttribute("datetime", format(date, "c"));
time.dataset.timestamp = ((date.getTime() - date.getMilliseconds()) / 1000).toString();
time.dataset.date = formattedDate;
time.dataset.time = formattedTime;
time.dataset.offset = (date.getTimezoneOffset() * 60).toString(); // PHP returns minutes, JavaScript returns seconds
if (date.getTime() > Date.now()) {
- time.dataset.isFutureDate = 'true';
- time.textContent = Language.get('wcf.date.dateTimeFormat')
- .replace('%time%', formattedTime)
- .replace('%date%', formattedDate);
+ time.dataset.isFutureDate = "true";
+ time.textContent = Language.get("wcf.date.dateTimeFormat")
+ .replace("%time%", formattedTime)
+ .replace("%date%", formattedDate);
}
return time;
}
function getTimezoneDate(timestamp, offset) {
const date = new Date(timestamp);
const localOffset = date.getTimezoneOffset() * 60000;
- return new Date((timestamp + localOffset + offset));
+ return new Date(timestamp + localOffset + offset);
}
exports.getTimezoneDate = getTimezoneDate;
});
};
function _updateConfig() {
if (window.sessionStorage) {
- window.sessionStorage.setItem('__wsc_devtools_config', JSON.stringify(_settings));
+ window.sessionStorage.setItem("__wsc_devtools_config", JSON.stringify(_settings));
}
}
const Devtools = {
* Prints the list of available commands.
*/
help() {
- window.console.log('');
- window.console.log('%cAvailable commands:', 'text-decoration: underline');
+ window.console.log("");
+ window.console.log("%cAvailable commands:", "text-decoration: underline");
const commands = [];
for (const cmd in Devtools) {
- if (cmd !== '_internal_' && Devtools.hasOwnProperty(cmd)) {
+ if (cmd !== "_internal_" && Devtools.hasOwnProperty(cmd)) {
commands.push(cmd);
}
}
commands.sort().forEach(function (cmd) {
- window.console.log('\tDevtools.' + cmd + '()');
+ window.console.log("\tDevtools." + cmd + "()");
});
- window.console.log('');
+ window.console.log("");
},
/**
* Disables/re-enables the editor autosave feature.
toggleEditorAutosave(forceDisable) {
_settings.editorAutosave = forceDisable ? false : !_settings.editorAutosave;
_updateConfig();
- window.console.log('%c\tEditor autosave ' + (_settings.editorAutosave ? 'enabled' : 'disabled'), 'font-style: italic');
+ window.console.log("%c\tEditor autosave " + (_settings.editorAutosave ? "enabled" : "disabled"), "font-style: italic");
},
/**
* Enables/disables logging for fired event listener events.
toggleEventLogging(forceEnable) {
_settings.eventLogging = forceEnable ? true : !_settings.eventLogging;
_updateConfig();
- window.console.log('%c\tEvent logging ' + (_settings.eventLogging ? 'enabled' : 'disabled'), 'font-style: italic');
+ window.console.log("%c\tEvent logging " + (_settings.eventLogging ? "enabled" : "disabled"), "font-style: italic");
},
/**
* Internal methods not meant to be called directly.
_internal_: {
enable() {
window.Devtools = Devtools;
- window.console.log('%cDevtools for WoltLab Suite loaded', 'font-weight: bold');
+ window.console.log("%cDevtools for WoltLab Suite loaded", "font-weight: bold");
if (window.sessionStorage) {
- const settings = window.sessionStorage.getItem('__wsc_devtools_config');
+ const settings = window.sessionStorage.getItem("__wsc_devtools_config");
try {
if (settings !== null) {
_settings = JSON.parse(settings);
}
}
- catch (e) {
- }
+ catch (e) { }
if (!_settings.editorAutosave)
Devtools.toggleEditorAutosave(true);
if (_settings.eventLogging)
Devtools.toggleEventLogging(true);
}
- window.console.log('Settings are saved per browser session, enter `Devtools.help()` to learn more.');
- window.console.log('');
+ window.console.log("Settings are saved per browser session, enter `Devtools.help()` to learn more.");
+ window.console.log("");
},
editorAutosave() {
return _settings.editorAutosave;
},
eventLog(identifier, action) {
if (_settings.eventLogging) {
- window.console.log('[Devtools.EventLogging] Firing event: ' + action + ' @ ' + identifier);
+ window.console.log("[Devtools.EventLogging] Firing event: " + action + " @ " + identifier);
}
},
},
* value as first parameter and the key name second.
*/
forEach(callback) {
- if (typeof callback !== 'function') {
- throw new TypeError('forEach() expects a callback as first parameter.');
+ if (typeof callback !== "function") {
+ throw new TypeError("forEach() expects a callback as first parameter.");
}
this._dictionary.forEach(callback);
}
*/
toObject() {
const object = {};
- this._dictionary.forEach((value, key) => object[key] = value);
+ this._dictionary.forEach((value, key) => (object[key] = value));
return object;
}
/**
return;
try {
_hot = true;
- _callbackList.forEach(null, callback => callback());
+ _callbackList.forEach(null, (callback) => callback());
}
finally {
_hot = false;
]);
function _getChildren(element, type, value) {
if (!(element instanceof Element)) {
- throw new TypeError('Expected a valid element as first argument.');
+ throw new TypeError("Expected a valid element as first argument.");
}
const children = [];
for (let i = 0; i < element.childElementCount; i++) {
}
function _getParent(element, type, value, untilElement) {
if (!(element instanceof Element)) {
- throw new TypeError('Expected a valid element as first argument.');
+ throw new TypeError("Expected a valid element as first argument.");
}
let target = element.parentNode;
while (target instanceof Element) {
}
function _getSibling(element, siblingType, type, value) {
if (!(element instanceof Element)) {
- throw new TypeError('Expected a valid element as first argument.');
+ throw new TypeError("Expected a valid element as first argument.");
}
if (element instanceof Element) {
if (element[siblingType] !== null && _test.get(type)(element[siblingType], value)) {
* @deprecated 5.4 Use `element.nextElementSibling` instead.
*/
function next(element) {
- return _getSibling(element, 'nextElementSibling', 0 /* None */, '');
+ return _getSibling(element, "nextElementSibling", 0 /* None */, "");
}
exports.next = next;
/**
* Returns the next element sibling that matches the given selector.
*/
function nextBySel(element, selector) {
- return _getSibling(element, 'nextElementSibling', 1 /* Selector */, selector);
+ return _getSibling(element, "nextElementSibling", 1 /* Selector */, selector);
}
exports.nextBySel = nextBySel;
/**
* Returns the next element sibling with given CSS class.
*/
function nextByClass(element, className) {
- return _getSibling(element, 'nextElementSibling', 2 /* ClassName */, className);
+ return _getSibling(element, "nextElementSibling", 2 /* ClassName */, className);
}
exports.nextByClass = nextByClass;
/**
* Returns the next element sibling with given CSS class.
*/
function nextByTag(element, tagName) {
- return _getSibling(element, 'nextElementSibling', 3 /* TagName */, tagName);
+ return _getSibling(element, "nextElementSibling", 3 /* TagName */, tagName);
}
exports.nextByTag = nextByTag;
/**
* @deprecated 5.4 Use `element.previousElementSibling` instead.
*/
function prev(element) {
- return _getSibling(element, 'previousElementSibling', 0 /* None */, '');
+ return _getSibling(element, "previousElementSibling", 0 /* None */, "");
}
exports.prev = prev;
/**
* Returns the previous element sibling that matches the given selector.
*/
function prevBySel(element, selector) {
- return _getSibling(element, 'previousElementSibling', 1 /* Selector */, selector);
+ return _getSibling(element, "previousElementSibling", 1 /* Selector */, selector);
}
exports.prevBySel = prevBySel;
/**
* Returns the previous element sibling with given CSS class.
*/
function prevByClass(element, className) {
- return _getSibling(element, 'previousElementSibling', 2 /* ClassName */, className);
+ return _getSibling(element, "previousElementSibling", 2 /* ClassName */, className);
}
exports.prevByClass = prevByClass;
/**
* Returns the previous element sibling with given CSS class.
*/
function prevByTag(element, tagName) {
- return _getSibling(element, 'previousElementSibling', 3 /* TagName */, tagName);
+ return _getSibling(element, "previousElementSibling", 3 /* TagName */, tagName);
}
exports.prevByTag = prevByTag;
});
StringUtil = tslib_1.__importStar(StringUtil);
function _isBoundaryNode(element, ancestor, position) {
if (!ancestor.contains(element)) {
- throw new Error('Ancestor element does not contain target element.');
+ throw new Error("Ancestor element does not contain target element.");
}
let node;
let target = element;
- const whichSibling = position + 'Sibling';
+ const whichSibling = position + "Sibling";
while (target !== null && target !== ancestor) {
- if (target[position + 'ElementSibling'] !== null) {
+ if (target[position + "ElementSibling"] !== null) {
return false;
}
else if (target[whichSibling]) {
node = target[whichSibling];
while (node) {
- if (node.textContent.trim() !== '') {
+ if (node.textContent.trim() !== "") {
return false;
}
node = node[whichSibling];
* Returns a DocumentFragment containing the provided HTML string as DOM nodes.
*/
createFragmentFromHtml(html) {
- const tmp = document.createElement('div');
+ const tmp = document.createElement("div");
this.setInnerHtml(tmp, html);
const fragment = document.createDocumentFragment();
while (tmp.childNodes.length) {
getUniqueId() {
let elementId;
do {
- elementId = 'wcf' + _idCounter++;
+ elementId = "wcf" + _idCounter++;
} while (document.getElementById(elementId) !== null);
return elementId;
},
*/
identify(element) {
if (!(element instanceof Element)) {
- throw new TypeError('Expected a valid DOM element as argument.');
+ throw new TypeError("Expected a valid DOM element as argument.");
}
let id = element.id;
if (!id) {
* @deprecated 5.3 Use `parent.insertAdjacentElement('afterbegin', element)` instead.
*/
prepend(element, parent) {
- parent.insertAdjacentElement('afterbegin', element);
+ parent.insertAdjacentElement("afterbegin", element);
},
/**
* Inserts an element after an existing element.
* @deprecated 5.3 Use `element.insertAdjacentElement('afterend', newElement)` instead.
*/
insertAfter(newElement, element) {
- element.insertAdjacentElement('afterend', newElement);
+ element.insertAdjacentElement("afterend", newElement);
},
/**
* Applies a list of CSS properties to an element.
if (styles.hasOwnProperty(property)) {
if (/ !important$/.test(styles[property])) {
important = true;
- styles[property] = styles[property].replace(/ !important$/, '');
+ styles[property] = styles[property].replace(/ !important$/, "");
}
else {
important = false;
// for a set style property with priority = important, some browsers are
// not able to overwrite it with a property != important; removing the
// property first solves this issue
- if (element.style.getPropertyPriority(property) === 'important' && !important) {
+ if (element.style.getPropertyPriority(property) === "important" && !important) {
element.style.removeProperty(property);
}
- element.style.setProperty(property, styles[property], (important ? 'important' : ''));
+ element.style.setProperty(property, styles[property], important ? "important" : "");
}
}
},
*/
setInnerHtml(element, innerHtml) {
element.innerHTML = innerHtml;
- const scripts = element.querySelectorAll('script');
+ const scripts = element.querySelectorAll("script");
for (let i = 0, length = scripts.length; i < length; i++) {
const script = scripts[i];
- const newScript = document.createElement('script');
+ const newScript = document.createElement("script");
if (script.src) {
newScript.src = script.src;
}
* @param insertMethod
*/
insertHtml(html, referenceElement, insertMethod) {
- const element = document.createElement('div');
+ const element = document.createElement("div");
this.setInnerHtml(element, html);
if (!element.childNodes.length) {
return;
}
let node = element.childNodes[0];
switch (insertMethod) {
- case 'append':
+ case "append":
referenceElement.appendChild(node);
break;
- case 'after':
+ case "after":
this.insertAfter(node, referenceElement);
break;
- case 'prepend':
+ case "prepend":
this.prepend(node, referenceElement);
break;
- case 'before':
+ case "before":
if (referenceElement.parentNode === null) {
- throw new Error('The reference element has no parent, but the insert position was set to \'before\'.');
+ throw new Error("The reference element has no parent, but the insert position was set to 'before'.");
}
referenceElement.parentNode.insertBefore(node, referenceElement);
break;
default:
- throw new Error('Unknown insert method \'' + insertMethod + '\'.');
+ throw new Error("Unknown insert method '" + insertMethod + "'.");
}
let tmp;
while (element.childNodes.length) {
* @deprecated 5.4 Use `element.dataset` instead.
*/
getDataAttributes(element, prefix, camelCaseName, idToUpperCase) {
- prefix = prefix || '';
- if (prefix.indexOf('data-') !== 0)
- prefix = 'data-' + prefix;
- camelCaseName = (camelCaseName === true);
- idToUpperCase = (idToUpperCase === true);
+ prefix = prefix || "";
+ if (prefix.indexOf("data-") !== 0)
+ prefix = "data-" + prefix;
+ camelCaseName = camelCaseName === true;
+ idToUpperCase = idToUpperCase === true;
const attributes = {};
for (let i = 0, length = element.attributes.length; i < length; i++) {
const attribute = element.attributes[i];
if (attribute.name.indexOf(prefix) === 0) {
- let name = attribute.name.replace(new RegExp('^' + prefix), '');
+ let name = attribute.name.replace(new RegExp("^" + prefix), "");
if (camelCaseName) {
- let tmp = name.split('-');
- name = '';
+ let tmp = name.split("-");
+ name = "";
for (let j = 0, innerLength = tmp.length; j < innerLength; j++) {
if (name.length) {
- if (idToUpperCase && tmp[j] === 'id') {
- tmp[j] = 'ID';
+ if (idToUpperCase && tmp[j] === "id") {
+ tmp[j] = "ID";
}
else {
tmp[j] = StringUtil.ucfirst(tmp[j]);
*/
unwrapChildNodes(element) {
if (element.parentNode === null) {
- throw new Error('The element has no parent.');
+ throw new Error("The element has no parent.");
}
let parent = element.parentNode;
while (element.childNodes.length) {
*/
replaceElement(oldElement, newElement) {
if (oldElement.parentNode === null) {
- throw new Error('The old element has no parent.');
+ throw new Error("The old element has no parent.");
}
while (oldElement.childNodes.length) {
newElement.appendChild(oldElement.childNodes[0]);
* a node without any content nor elements before it or its parent nodes.
*/
isAtNodeStart(element, ancestor) {
- return _isBoundaryNode(element, ancestor, 'previous');
+ return _isBoundaryNode(element, ancestor, "previous");
},
/**
* Returns true if given element is the most right node of the ancestor, that is
* a node without any content nor elements after it or its parent nodes.
*/
isAtNodeEnd(element, ancestor) {
- return _isBoundaryNode(element, ancestor, 'next');
+ return _isBoundaryNode(element, ancestor, "next");
},
/**
* Returns the first ancestor element with position fixed or null.
*/
getFixedParent(element) {
while (element && element !== document.body) {
- if (window.getComputedStyle(element).getPropertyValue('position') === 'fixed') {
+ if (window.getComputedStyle(element).getPropertyValue("position") === "fixed") {
return element;
}
element = element.offsetParent;
* Shorthand function to hide an element by setting its 'display' value to 'none'.
*/
hide(element) {
- element.style.setProperty('display', 'none', '');
+ element.style.setProperty("display", "none", "");
},
/**
* Shorthand function to show an element previously hidden by using `hide()`.
*/
show(element) {
- element.style.removeProperty('display');
+ element.style.removeProperty("display");
},
/**
* Shorthand function to check if given element is hidden by setting its 'display'
* value to 'none'.
*/
isHidden(element) {
- return element.style.getPropertyValue('display') === 'none';
+ return element.style.getPropertyValue("display") === "none";
},
/**
* Displays or removes an error message below the provided element.
innerError(element, errorMessage, isHtml) {
const parent = element.parentNode;
if (parent === null) {
- throw new Error('Only elements that have a parent element or document are valid.');
+ throw new Error("Only elements that have a parent element or document are valid.");
}
- if (typeof errorMessage !== 'string') {
+ if (typeof errorMessage !== "string") {
if (!errorMessage) {
- errorMessage = '';
+ errorMessage = "";
}
else {
- throw new TypeError('The error message must be a string; `false`, `null` or `undefined` can be used as a substitute for an empty string.');
+ throw new TypeError("The error message must be a string; `false`, `null` or `undefined` can be used as a substitute for an empty string.");
}
}
let innerError = element.nextElementSibling;
- if (innerError === null || innerError.nodeName !== 'SMALL' || !innerError.classList.contains('innerError')) {
- if (errorMessage === '') {
+ if (innerError === null || innerError.nodeName !== "SMALL" || !innerError.classList.contains("innerError")) {
+ if (errorMessage === "") {
innerError = null;
}
else {
- innerError = document.createElement('small');
- innerError.className = 'innerError';
+ innerError = document.createElement("small");
+ innerError.className = "innerError";
parent.insertBefore(innerError, element.nextSibling);
}
}
- if (errorMessage === '') {
+ if (errorMessage === "") {
if (innerError !== null) {
innerError.remove();
innerError = null;
}
}
else {
- innerError[isHtml ? 'innerHTML' : 'textContent'] = errorMessage;
+ innerError[isHtml ? "innerHTML" : "textContent"] = errorMessage;
}
return innerError;
},
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.touch = exports.platform = exports.editor = exports.browser = exports.setup = void 0;
- let _browser = 'other';
- let _editor = 'none';
- let _platform = 'desktop';
+ let _browser = "other";
+ let _editor = "none";
+ let _platform = "desktop";
let _touch = false;
/**
* Determines environment variables.
*/
function setup() {
- if (typeof window.chrome === 'object') {
+ if (typeof window.chrome === "object") {
// this detects Opera as well, we could check for window.opr if we need to
- _browser = 'chrome';
+ _browser = "chrome";
}
else {
const styles = window.getComputedStyle(document.documentElement);
for (let i = 0, length = styles.length; i < length; i++) {
const property = styles[i];
- if (property.indexOf('-ms-') === 0) {
+ if (property.indexOf("-ms-") === 0) {
// it is tempting to use 'msie', but it wouldn't really represent 'Edge'
- _browser = 'microsoft';
+ _browser = "microsoft";
}
- else if (property.indexOf('-moz-') === 0) {
- _browser = 'firefox';
+ else if (property.indexOf("-moz-") === 0) {
+ _browser = "firefox";
}
- else if (_browser !== 'firefox' && property.indexOf('-webkit-') === 0) {
- _browser = 'safari';
+ else if (_browser !== "firefox" && property.indexOf("-webkit-") === 0) {
+ _browser = "safari";
}
}
}
const ua = window.navigator.userAgent.toLowerCase();
- if (ua.indexOf('crios') !== -1) {
- _browser = 'chrome';
- _platform = 'ios';
+ if (ua.indexOf("crios") !== -1) {
+ _browser = "chrome";
+ _platform = "ios";
}
else if (/(?:iphone|ipad|ipod)/.test(ua)) {
- _browser = 'safari';
- _platform = 'ios';
+ _browser = "safari";
+ _platform = "ios";
}
- else if (ua.indexOf('android') !== -1) {
- _platform = 'android';
+ else if (ua.indexOf("android") !== -1) {
+ _platform = "android";
}
- else if (ua.indexOf('iemobile') !== -1) {
- _browser = 'microsoft';
- _platform = 'windows';
+ else if (ua.indexOf("iemobile") !== -1) {
+ _browser = "microsoft";
+ _platform = "windows";
}
- if (_platform === 'desktop' && (ua.indexOf('mobile') !== -1 || ua.indexOf('tablet') !== -1)) {
- _platform = 'mobile';
+ if (_platform === "desktop" && (ua.indexOf("mobile") !== -1 || ua.indexOf("tablet") !== -1)) {
+ _platform = "mobile";
}
- _editor = 'redactor';
- _touch = (('ontouchstart' in window) || (('msMaxTouchPoints' in window.navigator) && window.navigator.msMaxTouchPoints > 0) || window.DocumentTouch && document instanceof window.DocumentTouch);
+ _editor = "redactor";
+ _touch =
+ "ontouchstart" in window ||
+ ("msMaxTouchPoints" in window.navigator && window.navigator.msMaxTouchPoints > 0) ||
+ (window.DocumentTouch && document instanceof window.DocumentTouch);
// The iPad Pro 12.9" masquerades as a desktop browser.
- if (window.navigator.platform === 'MacIntel' && window.navigator.maxTouchPoints > 1) {
- _browser = 'safari';
- _platform = 'ios';
+ if (window.navigator.platform === "MacIntel" && window.navigator.maxTouchPoints > 1) {
+ _browser = "safari";
+ _platform = "ios";
}
}
exports.setup = setup;
* Registers an event listener.
*/
function add(identifier, action, callback) {
- if (typeof callback !== 'function') {
+ if (typeof callback !== "function") {
throw new TypeError(`Expected a valid callback for '${action}'@'${identifier}'.`);
}
let actions = _listeners.get(identifier);
var _a, _b;
Devtools_1.default._internal_.eventLog(identifier, action);
data = data || {};
- (_b = (_a = _listeners.get(identifier)) === null || _a === void 0 ? void 0 : _a.get(action)) === null || _b === void 0 ? void 0 : _b.forEach(callback => callback(data));
+ (_b = (_a = _listeners
+ .get(identifier)) === null || _a === void 0 ? void 0 : _a.get(action)) === null || _b === void 0 ? void 0 : _b.forEach((callback) => callback(data));
}
exports.fire = fire;
/**
* remove all listeners for this identifier.
*/
function removeAll(identifier, action) {
- if (typeof action !== 'string')
+ if (typeof action !== "string")
action = undefined;
const actions = _listeners.get(identifier);
if (actions === undefined) {
if (actions === undefined) {
return;
}
- suffix = '_' + suffix;
+ suffix = "_" + suffix;
const length = suffix.length * -1;
actions.forEach((callbacks, action) => {
if (action.substr(length) === suffix) {
* @deprecated 5.4 Use `event.key === "ArrowDown"` instead.
*/
function ArrowDown(event) {
- return _test(event, 'ArrowDown', 40);
+ return _test(event, "ArrowDown", 40);
}
exports.ArrowDown = ArrowDown;
/**
* @deprecated 5.4 Use `event.key === "ArrowLeft"` instead.
*/
function ArrowLeft(event) {
- return _test(event, 'ArrowLeft', 37);
+ return _test(event, "ArrowLeft", 37);
}
exports.ArrowLeft = ArrowLeft;
/**
* @deprecated 5.4 Use `event.key === "ArrowRight"` instead.
*/
function ArrowRight(event) {
- return _test(event, 'ArrowRight', 39);
+ return _test(event, "ArrowRight", 39);
}
exports.ArrowRight = ArrowRight;
/**
* @deprecated 5.4 Use `event.key === "ArrowUp"` instead.
*/
function ArrowUp(event) {
- return _test(event, 'ArrowUp', 38);
+ return _test(event, "ArrowUp", 38);
}
exports.ArrowUp = ArrowUp;
/**
* @deprecated 5.4 Use `event.key === ","` instead.
*/
function Comma(event) {
- return _test(event, ',', 44);
+ return _test(event, ",", 44);
}
exports.Comma = Comma;
/**
* @deprecated 5.4 Use `event.key === "End"` instead.
*/
function End(event) {
- return _test(event, 'End', 35);
+ return _test(event, "End", 35);
}
exports.End = End;
/**
* @deprecated 5.4 Use `event.key === "Enter"` instead.
*/
function Enter(event) {
- return _test(event, 'Enter', 13);
+ return _test(event, "Enter", 13);
}
exports.Enter = Enter;
/**
* @deprecated 5.4 Use `event.key === "Escape"` instead.
*/
function Escape(event) {
- return _test(event, 'Escape', 27);
+ return _test(event, "Escape", 27);
}
exports.Escape = Escape;
/**
* @deprecated 5.4 Use `event.key === "Home"` instead.
*/
function Home(event) {
- return _test(event, 'Home', 36);
+ return _test(event, "Home", 36);
}
exports.Home = Home;
/**
* @deprecated 5.4 Use `event.key === "Space"` instead.
*/
function Space(event) {
- return _test(event, 'Space', 32);
+ return _test(event, "Space", 32);
}
exports.Space = Space;
/**
* @deprecated 5.4 Use `event.key === "Tab"` instead.
*/
function Tab(event) {
- return _test(event, 'Tab', 9);
+ return _test(event, "Tab", 9);
}
exports.Tab = Tab;
});
StringUtil = tslib_1.__importStar(StringUtil);
const _fileExtensionIconMapping = new Map(Object.entries({
// archive
- zip: 'archive',
- rar: 'archive',
- tar: 'archive',
- gz: 'archive',
+ zip: "archive",
+ rar: "archive",
+ tar: "archive",
+ gz: "archive",
// audio
- mp3: 'audio',
- ogg: 'audio',
- wav: 'audio',
+ mp3: "audio",
+ ogg: "audio",
+ wav: "audio",
// code
- php: 'code',
- html: 'code',
- htm: 'code',
- tpl: 'code',
- js: 'code',
+ php: "code",
+ html: "code",
+ htm: "code",
+ tpl: "code",
+ js: "code",
// excel
- xls: 'excel',
- ods: 'excel',
- xlsx: 'excel',
+ xls: "excel",
+ ods: "excel",
+ xlsx: "excel",
// image
- gif: 'image',
- jpg: 'image',
- jpeg: 'image',
- png: 'image',
- bmp: 'image',
- webp: 'image',
+ gif: "image",
+ jpg: "image",
+ jpeg: "image",
+ png: "image",
+ bmp: "image",
+ webp: "image",
// video
- avi: 'video',
- wmv: 'video',
- mov: 'video',
- mp4: 'video',
- mpg: 'video',
- mpeg: 'video',
- flv: 'video',
+ avi: "video",
+ wmv: "video",
+ mov: "video",
+ mp4: "video",
+ mpg: "video",
+ mpeg: "video",
+ flv: "video",
// pdf
- pdf: 'pdf',
+ pdf: "pdf",
// powerpoint
- ppt: 'powerpoint',
- pptx: 'powerpoint',
+ ppt: "powerpoint",
+ pptx: "powerpoint",
// text
- txt: 'text',
+ txt: "text",
// word
- doc: 'word',
- docx: 'word',
- odt: 'word',
+ doc: "word",
+ docx: "word",
+ odt: "word",
}));
const _mimeTypeExtensionMapping = new Map(Object.entries({
// archive
- 'application/zip': 'zip',
- 'application/x-zip-compressed': 'zip',
- 'application/rar': 'rar',
- 'application/vnd.rar': 'rar',
- 'application/x-rar-compressed': 'rar',
- 'application/x-tar': 'tar',
- 'application/x-gzip': 'gz',
- 'application/gzip': 'gz',
+ "application/zip": "zip",
+ "application/x-zip-compressed": "zip",
+ "application/rar": "rar",
+ "application/vnd.rar": "rar",
+ "application/x-rar-compressed": "rar",
+ "application/x-tar": "tar",
+ "application/x-gzip": "gz",
+ "application/gzip": "gz",
// audio
- 'audio/mpeg': 'mp3',
- 'audio/mp3': 'mp3',
- 'audio/ogg': 'ogg',
- 'audio/x-wav': 'wav',
+ "audio/mpeg": "mp3",
+ "audio/mp3": "mp3",
+ "audio/ogg": "ogg",
+ "audio/x-wav": "wav",
// code
- 'application/x-php': 'php',
- 'text/html': 'html',
- 'application/javascript': 'js',
+ "application/x-php": "php",
+ "text/html": "html",
+ "application/javascript": "js",
// excel
- 'application/vnd.ms-excel': 'xls',
- 'application/vnd.oasis.opendocument.spreadsheet': 'ods',
- 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',
+ "application/vnd.ms-excel": "xls",
+ "application/vnd.oasis.opendocument.spreadsheet": "ods",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlsx",
// image
- 'image/gif': 'gif',
- 'image/jpeg': 'jpg',
- 'image/png': 'png',
- 'image/x-ms-bmp': 'bmp',
- 'image/bmp': 'bmp',
- 'image/webp': 'webp',
+ "image/gif": "gif",
+ "image/jpeg": "jpg",
+ "image/png": "png",
+ "image/x-ms-bmp": "bmp",
+ "image/bmp": "bmp",
+ "image/webp": "webp",
// video
- 'video/x-msvideo': 'avi',
- 'video/x-ms-wmv': 'wmv',
- 'video/quicktime': 'mov',
- 'video/mp4': 'mp4',
- 'video/mpeg': 'mpg',
- 'video/x-flv': 'flv',
+ "video/x-msvideo": "avi",
+ "video/x-ms-wmv": "wmv",
+ "video/quicktime": "mov",
+ "video/mp4": "mp4",
+ "video/mpeg": "mpg",
+ "video/x-flv": "flv",
// pdf
- 'application/pdf': 'pdf',
+ "application/pdf": "pdf",
// powerpoint
- 'application/vnd.ms-powerpoint': 'ppt',
- 'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'pptx',
+ "application/vnd.ms-powerpoint": "ppt",
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation": "pptx",
// text
- 'text/plain': 'txt',
+ "text/plain": "txt",
// word
- 'application/msword': 'doc',
- 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
- 'application/vnd.oasis.opendocument.text': 'odt',
+ "application/msword": "doc",
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "docx",
+ "application/vnd.oasis.opendocument.text": "odt",
}));
/**
* Formats the given filesize.
if (precision === undefined) {
precision = 2;
}
- let symbol = 'Byte';
+ let symbol = "Byte";
if (byte >= 1000) {
byte /= 1000;
- symbol = 'kB';
+ symbol = "kB";
}
if (byte >= 1000) {
byte /= 1000;
- symbol = 'MB';
+ symbol = "MB";
}
if (byte >= 1000) {
byte /= 1000;
- symbol = 'GB';
+ symbol = "GB";
}
if (byte >= 1000) {
byte /= 1000;
- symbol = 'TB';
+ symbol = "TB";
}
- return StringUtil.formatNumeric(byte, -precision) + ' ' + symbol;
+ return StringUtil.formatNumeric(byte, -precision) + " " + symbol;
}
exports.formatFilesize = formatFilesize;
/**
* will be returned by this method.
*/
function getIconNameByFilename(filename) {
- const lastDotPosition = filename.lastIndexOf('.');
+ const lastDotPosition = filename.lastIndexOf(".");
if (lastDotPosition !== -1) {
const extension = filename.substr(lastDotPosition + 1);
if (_fileExtensionIconMapping.has(extension)) {
return _fileExtensionIconMapping.get(extension);
}
}
- return '';
+ return "";
}
exports.getIconNameByFilename = getIconNameByFilename;
/**
*/
function getExtensionByMimeType(mimetype) {
if (_mimeTypeExtensionMapping.has(mimetype)) {
- return '.' + _mimeTypeExtensionMapping.get(mimetype);
+ return "." + _mimeTypeExtensionMapping.get(mimetype);
}
- return '';
+ return "";
}
exports.getExtensionByMimeType = getExtensionByMimeType;
/**
define(["require", "exports", "tslib", "../StringUtil"], function (require, exports, tslib_1, StringUtil) {
"use strict";
StringUtil = tslib_1.__importStar(StringUtil);
- const PLURAL_FEW = 'few';
- const PLURAL_MANY = 'many';
- const PLURAL_ONE = 'one';
- const PLURAL_OTHER = 'other';
- const PLURAL_TWO = 'two';
- const PLURAL_ZERO = 'zero';
+ const PLURAL_FEW = "few";
+ const PLURAL_MANY = "many";
+ const PLURAL_ONE = "one";
+ const PLURAL_OTHER = "other";
+ const PLURAL_TWO = "two";
+ const PLURAL_ZERO = "zero";
const Plural = {
/**
* Returns the plural category for the given value.
languageCode = document.documentElement.lang;
}
// Fallback: handle unknown languages as English
- if (typeof Plural[languageCode] !== 'function') {
- languageCode = 'en';
+ if (typeof Plural[languageCode] !== "function") {
+ languageCode = "en";
}
const category = Plural[languageCode](value);
if (category) {
* @see wcf\system\template\plugin\PluralFunctionTemplatePlugin::execute()
*/
getCategoryFromTemplateParameters(parameters) {
- if (!parameters['value']) {
- throw new Error('Missing parameter value');
+ if (!parameters["value"]) {
+ throw new Error("Missing parameter value");
}
- if (!parameters['other']) {
- throw new Error('Missing parameter other');
+ if (!parameters["other"]) {
+ throw new Error("Missing parameter other");
}
- let value = parameters['value'];
+ let value = parameters["value"];
if (Array.isArray(value)) {
value = value.length;
}
category = PLURAL_OTHER;
}
const string = parameters[category];
- if (string.indexOf('#') !== -1) {
- return string.replace('#', StringUtil.formatNumeric(value));
+ if (string.indexOf("#") !== -1) {
+ return string.replace("#", StringUtil.formatNumeric(value));
}
return string;
},
*/
getF(n) {
const tmp = n.toString();
- const pos = tmp.indexOf('.');
+ const pos = tmp.indexOf(".");
if (pos === -1) {
return 0;
}
* `v` represents the number of digits of the fractional part (1.234 yields 3)
*/
getV(n) {
- return n.toString().replace(/^[^.]*\.?/, '').length;
+ return n.toString().replace(/^[^.]*\.?/, "").length;
},
// Afrikaans
af(n) {
return PLURAL_ONE;
},
// Tibetan
- bo(n) {
- },
+ bo(n) { },
// Bosnian
bs(n) {
const v = Plural.getV(n);
const fMod100 = f % 100;
if ((v == 0 && mod10 == 1 && mod100 != 11) || (fMod10 == 1 && fMod100 != 11))
return PLURAL_ONE;
- if ((v == 0 && mod10 >= 2 && mod10 <= 4 && mod100 >= 12 && mod100 <= 14)
- || (fMod10 >= 2 && fMod10 <= 4 && fMod100 >= 12 && fMod100 <= 14))
+ if ((v == 0 && mod10 >= 2 && mod10 <= 4 && mod100 >= 12 && mod100 <= 14) ||
+ (fMod10 >= 2 && fMod10 <= 4 && fMod100 >= 12 && fMod100 <= 14))
return PLURAL_FEW;
},
// Czech
return PLURAL_ONE;
},
// Indonesian
- id(n) {
- },
+ id(n) { },
// Icelandic
is(n) {
const f = Plural.getF(n);
- if (f === 0 && n % 10 === 1 && !(n % 100 === 11) || !(f === 0))
+ if ((f === 0 && n % 10 === 1 && !(n % 100 === 11)) || !(f === 0))
return PLURAL_ONE;
},
// Japanese
- ja(n) {
- },
+ ja(n) { },
// Javanese
- jv(n) {
- },
+ jv(n) { },
// Georgian
ka(n) {
if (n == 1)
return PLURAL_ONE;
},
// Khmer
- km(n) {
- },
+ km(n) { },
// Kannada
kn(n) {
if (n >= 0 && n <= 1)
return PLURAL_ONE;
},
// Korean
- ko(n) {
- },
+ ko(n) { },
// Kurdish
ku(n) {
if (n == 1)
return PLURAL_ONE;
},
// Lao
- lo(n) {
- },
+ lo(n) { },
// Lithuanian
lt(n) {
const mod10 = n % 10;
if (n == 1)
return PLURAL_ONE;
},
- // Mongolian
+ // Mongolian
mn(n) {
if (n == 1)
return PLURAL_ONE;
},
- // Marathi
+ // Marathi
mr(n) {
if (n == 1)
return PLURAL_ONE;
},
- // Malay
- ms(n) {
- },
- // Maltese
+ // Malay
+ ms(n) { },
+ // Maltese
mt(n) {
const mod100 = n % 100;
if (n == 1)
return PLURAL_MANY;
},
// Burmese
- my(n) {
- },
+ my(n) { },
// Norwegian
no(n) {
if (n == 1)
return PLURAL_ONE;
if (v == 0 && mod10 >= 2 && mod10 <= 4 && !(mod100 >= 12 && mod100 <= 14))
return PLURAL_FEW;
- if (v == 0 && ((n != 1 && mod10 >= 0 && mod10 <= 1) || (mod10 >= 5 && mod10 <= 9) || (mod100 >= 12 && mod100 <= 14)))
+ if (v == 0 &&
+ ((n != 1 && mod10 >= 0 && mod10 <= 1) || (mod10 >= 5 && mod10 <= 9) || (mod100 >= 12 && mod100 <= 14)))
return PLURAL_MANY;
},
// Pashto
return PLURAL_ONE;
},
// Tajik
- tg(n) {
- },
+ tg(n) { },
// Thai
- th(n) {
- },
+ th(n) { },
// Turkmen
tk(n) {
if (n == 1)
return PLURAL_ONE;
},
// Vietnamese
- vi(n) {
- },
+ vi(n) { },
// Chinese
- zh(n) {
- },
+ zh(n) { },
};
return Plural;
});
* Adds all the language items in the given object to the store.
*/
function addObject(object) {
- Object.keys(object).forEach(key => {
+ Object.keys(object).forEach((key) => {
_languageItems.set(key, object[key]);
});
}
return key;
}
// fetch Template, as it cannot be provided because of a circular dependency
- if (Template_1.default === undefined) { //@ts-ignore
- Template_1.default = require('./Template');
+ if (Template_1.default === undefined) {
+ //@ts-ignore
+ Template_1.default = require("./Template");
}
- if (typeof value === 'string') {
+ if (typeof value === "string") {
// lazily convert to WCF.Template
try {
_languageItems.set(key, new Template_1.default(value));
}
catch (e) {
- _languageItems.set(key, new Template_1.default('{literal}' + value.replace(/{\/literal}/g, '{/literal}{ldelim}/literal}{literal}') + '{/literal}'));
+ _languageItems.set(key, new Template_1.default("{literal}" + value.replace(/{\/literal}/g, "{/literal}{ldelim}/literal}{literal}") + "{/literal}"));
}
value = _languageItems.get(key);
}
*/
function round(value, exp) {
// If the exp is undefined or zero...
- if (typeof exp === 'undefined' || +exp === 0) {
+ if (typeof exp === "undefined" || +exp === 0) {
return Math.round(value);
}
value = +value;
exp = +exp;
// If the value is not a number or the exp is not an integer...
- if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) {
+ if (isNaN(value) || !(typeof exp === "number" && exp % 1 === 0)) {
return NaN;
}
// Shift
- let tmp = value.toString().split('e');
- value = Math.round(+(tmp[0] + 'e' + (tmp[1] ? (+tmp[1] - exp) : -exp)));
+ let tmp = value.toString().split("e");
+ value = Math.round(+(tmp[0] + "e" + (tmp[1] ? +tmp[1] - exp : -exp)));
// Shift back
- tmp = value.toString().split('e');
- return +(tmp[0] + 'e' + (tmp[1] ? (+tmp[1] + exp) : exp));
+ tmp = value.toString().split("e");
+ return +(tmp[0] + "e" + (tmp[1] ? +tmp[1] + exp : exp));
}
exports.round = round;
});
* Sets a new key with given value, will overwrite an existing key.
*/
set(key, value) {
- if (typeof key !== 'object' || key === null) {
- throw new TypeError('Only objects can be used as key');
+ if (typeof key !== "object" || key === null) {
+ throw new TypeError("Only objects can be used as key");
}
- if (typeof value !== 'object' || value === null) {
- throw new TypeError('Only objects can be used as value');
+ if (typeof value !== "object" || value === null) {
+ throw new TypeError("Only objects can be used as value");
}
this._map.set(key, value);
}
* Adds a single permission to the store.
*/
function add(permission, value) {
- if (typeof value !== 'boolean') {
- throw new TypeError('The permission value has to be boolean.');
+ if (typeof value !== "boolean") {
+ throw new TypeError("The permission value has to be boolean.");
}
_permissions.set(permission, value);
}
*/
function addThousandsSeparator(number) {
// Fetch Language, as it cannot be provided because of a circular dependency
- if (Language === undefined) { //@ts-ignore
- Language = require('./Language');
+ if (Language === undefined) {
+ //@ts-ignore
+ Language = require("./Language");
}
- return String(number).replace(/(^-?\d{1,3}|\d{3})(?=(?:\d{3})+(?:$|\.))/g, '$1' + Language.get('wcf.global.thousandsSeparator'));
+ return String(number).replace(/(^-?\d{1,3}|\d{3})(?=(?:\d{3})+(?:$|\.))/g, "$1" + Language.get("wcf.global.thousandsSeparator"));
}
exports.addThousandsSeparator = addThousandsSeparator;
/**
* Escapes special HTML-characters within a string
*/
function escapeHTML(string) {
- return String(string).replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
+ return String(string).replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
}
exports.escapeHTML = escapeHTML;
/**
* @see https://github.com/sstephenson/prototype/blob/master/src/prototype/lang/regexp.js#L25
*/
function escapeRegExp(string) {
- return String(string).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
+ return String(string).replace(/([.*+?^=!:${}()|[\]\/\\])/g, "\\$1");
}
exports.escapeRegExp = escapeRegExp;
/**
*/
function formatNumeric(number, decimalPlaces) {
// Fetch Language, as it cannot be provided because of a circular dependency
- if (Language === undefined) { //@ts-ignore
- Language = require('./Language');
+ if (Language === undefined) {
+ //@ts-ignore
+ Language = require("./Language");
}
let tmp = NumberUtil.round(number, decimalPlaces || -2).toString();
- const numberParts = tmp.split('.');
+ const numberParts = tmp.split(".");
tmp = addThousandsSeparator(+numberParts[0]);
if (numberParts.length > 1)
- tmp += Language.get('wcf.global.decimalPoint') + numberParts[1];
- tmp = tmp.replace('-', '\u2212');
+ tmp += Language.get("wcf.global.decimalPoint") + numberParts[1];
+ tmp = tmp.replace("-", "\u2212");
return tmp;
}
exports.formatNumeric = formatNumeric;
* Unescapes special HTML-characters within a string.
*/
function unescapeHTML(string) {
- return String(string).replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
+ return String(string)
+ .replace(/&/g, "&")
+ .replace(/"/g, '"')
+ .replace(/</g, "<")
+ .replace(/>/g, ">");
}
exports.unescapeHTML = unescapeHTML;
/**
* Shortens numbers larger than 1000 by using unit suffixes.
*/
function shortUnit(number) {
- let unitSuffix = '';
+ let unitSuffix = "";
if (number >= 1000000) {
number /= 1000000;
if (number > 10) {
else {
number = NumberUtil.round(number, -1);
}
- unitSuffix = 'M';
+ unitSuffix = "M";
}
else if (number >= 1000) {
number /= 1000;
else {
number = NumberUtil.round(number, -1);
}
- unitSuffix = 'k';
+ unitSuffix = "k";
}
return formatNumeric(number) + unitSuffix;
}
class Template {
constructor(template) {
// Fetch Language/StringUtil, as it cannot be provided because of a circular dependency
- if (Language === undefined) { //@ts-ignore
- Language = require('./Language');
+ if (Language === undefined) {
+ //@ts-ignore
+ Language = require("./Language");
}
- if (StringUtil === undefined) { //@ts-ignore
- StringUtil = require('./StringUtil');
+ if (StringUtil === undefined) {
+ //@ts-ignore
+ StringUtil = require("./StringUtil");
}
try {
template = parser.parse(template);
- template = 'var tmp = {};\n'
- + 'for (var key in v) tmp[key] = v[key];\n'
- + 'v = tmp;\n'
- + 'v.__wcf = window.WCF; v.__window = window;\n'
- + 'return ' + template;
- this.fetch = new Function('StringUtil', 'Language', 'I18nPlural', 'v', template).bind(undefined, StringUtil, Language, I18nPlural);
+ template =
+ "var tmp = {};\n" +
+ "for (var key in v) tmp[key] = v[key];\n" +
+ "v = tmp;\n" +
+ "v.__wcf = window.WCF; v.__window = window;\n" +
+ "return " +
+ template;
+ this.fetch = new Function("StringUtil", "Language", "I18nPlural", "v", template).bind(undefined, StringUtil, Language, I18nPlural);
}
catch (e) {
console.debug(e.message);
*/
fetch(v) {
// this will be replaced in the init function
- throw new Error('This Template is not initialized.');
+ throw new Error("This Template is not initialized.");
}
}
- Object.defineProperty(Template, 'callbacks', {
+ Object.defineProperty(Template, "callbacks", {
enumerable: false,
configurable: false,
get: function () {
- throw new Error('WCF.Template.callbacks is no longer supported');
+ throw new Error("WCF.Template.callbacks is no longer supported");
},
set: function (value) {
- throw new Error('WCF.Template.callbacks is no longer supported');
+ throw new Error("WCF.Template.callbacks is no longer supported");
},
});
return Template;
* The `callback` will be passed the owning instance of `Repeating`.
*/
constructor(callback, delta) {
- if (typeof callback !== 'function') {
+ if (typeof callback !== "function") {
throw new TypeError("Expected a valid callback as first argument.");
}
if (delta < 0 || delta > 86400 * 1000) {
Input_1 = tslib_1.__importDefault(Input_1);
class UiAclSimple {
constructor(prefix, inputName) {
- this.prefix = prefix || '';
- this.inputName = inputName || 'aclValues';
- const container = document.getElementById(this.prefix + 'aclInputContainer');
- const allowAll = document.getElementById(this.prefix + 'aclAllowAll');
- allowAll.addEventListener('change', () => {
+ this.prefix = prefix || "";
+ this.inputName = inputName || "aclValues";
+ const container = document.getElementById(this.prefix + "aclInputContainer");
+ const allowAll = document.getElementById(this.prefix + "aclAllowAll");
+ allowAll.addEventListener("change", () => {
Util_1.default.hide(container);
});
- const denyAll = document.getElementById(this.prefix + 'aclAllowAll_no');
- denyAll.addEventListener('change', () => {
+ const denyAll = document.getElementById(this.prefix + "aclAllowAll_no");
+ denyAll.addEventListener("change", () => {
Util_1.default.show(container);
});
- this.list = document.getElementById(this.prefix + 'aclAccessList');
- this.list.addEventListener('click', this.removeItem.bind(this));
+ this.list = document.getElementById(this.prefix + "aclAccessList");
+ this.list.addEventListener("click", this.removeItem.bind(this));
const excludedSearchValues = [];
- this.list.querySelectorAll('.aclLabel').forEach(label => {
+ this.list.querySelectorAll(".aclLabel").forEach((label) => {
excludedSearchValues.push(label.textContent);
});
- this.searchInput = new Input_1.default(document.getElementById(this.prefix + 'aclSearchInput'), {
+ this.searchInput = new Input_1.default(document.getElementById(this.prefix + "aclSearchInput"), {
callbackSelect: this.select.bind(this),
includeUserGroups: true,
excludedSearchValues: excludedSearchValues,
preventSubmit: true,
});
- this.aclListContainer = document.getElementById(this.prefix + 'aclListContainer');
+ this.aclListContainer = document.getElementById(this.prefix + "aclListContainer");
Listener_1.default.trigger();
}
select(listItem) {
const type = listItem.dataset.type;
const label = listItem.dataset.label;
const objectId = listItem.dataset.objectId;
- const iconName = type === 'group' ? 'users' : 'user';
+ const iconName = type === "group" ? "users" : "user";
const html = `<span class="icon icon16 fa-${iconName}"></span>
<span class="aclLabel">${StringUtil.escapeHTML(label)}</span>
- <span class="icon icon16 fa-times pointer jsTooltip" title="${Language.get('wcf.global.button.delete')}"></span>
+ <span class="icon icon16 fa-times pointer jsTooltip" title="${Language.get("wcf.global.button.delete")}"></span>
<input type="hidden" name="${this.inputName}[${type}][]" value="${objectId}">`;
- const item = document.createElement('li');
+ const item = document.createElement("li");
item.innerHTML = html;
- const firstUser = this.list.querySelector('.fa-user');
+ const firstUser = this.list.querySelector(".fa-user");
if (firstUser === null) {
this.list.appendChild(item);
}
}
removeItem(event) {
const target = event.target;
- if (target.classList.contains('fa-times')) {
+ if (target.classList.contains("fa-times")) {
const parent = target.parentElement;
- const label = parent.querySelector('.aclLabel');
+ const label = parent.querySelector(".aclLabel");
this.searchInput.removeExcludedSearchValues(label.textContent);
parent.remove();
if (this.list.childElementCount === 0) {
* @returns {Object<string, *>} calculation results
*/
function tryAlignmentHorizontal(alignment, elDimensions, refDimensions, refOffsets, windowWidth) {
- let left = 'auto';
- let right = 'auto';
+ let left = "auto";
+ let right = "auto";
let result = true;
- if (alignment === 'left') {
+ if (alignment === "left") {
left = refOffsets.left;
if (left + elDimensions.width > windowWidth) {
result = false;
}
}
- else if (alignment === 'right') {
+ else if (alignment === "right") {
if (refOffsets.left + refDimensions.width < elDimensions.width) {
result = false;
}
}
}
else {
- left = refOffsets.left + (refDimensions.width / 2) - (elDimensions.width / 2);
+ left = refOffsets.left + refDimensions.width / 2 - elDimensions.width / 2;
left = ~~left;
if (left < 0 || left + elDimensions.width > windowWidth) {
result = false;
* @returns {object<string, *>} calculation results
*/
function tryAlignmentVertical(alignment, elDimensions, refDimensions, refOffsets, windowHeight, verticalOffset) {
- let bottom = 'auto';
- let top = 'auto';
+ let bottom = "auto";
+ let top = "auto";
let result = true;
let pageHeaderOffset = 50;
- const pageHeaderPanel = document.getElementById('pageHeaderPanel');
+ const pageHeaderPanel = document.getElementById("pageHeaderPanel");
if (pageHeaderPanel !== null) {
const position = window.getComputedStyle(pageHeaderPanel).position;
- if (position === 'fixed' || position === 'static') {
+ if (position === "fixed" || position === "static") {
pageHeaderOffset = pageHeaderPanel.offsetHeight;
}
else {
pageHeaderOffset = 0;
}
}
- if (alignment === 'top') {
+ if (alignment === "top") {
const bodyHeight = document.body.clientHeight;
- bottom = (bodyHeight - refOffsets.top) + verticalOffset;
+ bottom = bodyHeight - refOffsets.top + verticalOffset;
if (bodyHeight - (bottom + elDimensions.height) < (window.scrollY || window.pageYOffset) + pageHeaderOffset) {
result = false;
}
// alternate element used to calculate dimensions
refDimensionsElement: null,
// preferred alignment, possible values: left/right/center and top/bottom
- horizontal: 'left',
- vertical: 'bottom',
+ horizontal: "left",
+ vertical: "bottom",
// allow flipping over axis, possible values: both, horizontal, vertical and none
- allowFlip: 'both',
+ allowFlip: "both",
}, options || {});
if (!Array.isArray(options.pointerClassNames) || options.pointerClassNames.length !== (options.pointer ? 1 : 2)) {
options.pointerClassNames = [];
}
- if (['left', 'right', 'center'].indexOf(options.horizontal) === -1) {
- options.horizontal = 'left';
+ if (["left", "right", "center"].indexOf(options.horizontal) === -1) {
+ options.horizontal = "left";
}
- if (options.vertical !== 'bottom') {
- options.vertical = 'top';
+ if (options.vertical !== "bottom") {
+ options.vertical = "top";
}
- if (['both', 'horizontal', 'vertical', 'none'].indexOf(options.allowFlip) === -1) {
- options.allowFlip = 'both';
+ if (["both", "horizontal", "vertical", "none"].indexOf(options.allowFlip) === -1) {
+ options.allowFlip = "both";
}
// Place the element in the upper left corner to prevent calculation issues due to possible scrollbars.
Util_1.default.setStyles(element, {
- bottom: 'auto !important',
- left: '0 !important',
- right: 'auto !important',
- top: '0 !important',
- visibility: 'hidden !important',
+ bottom: "auto !important",
+ left: "0 !important",
+ right: "auto !important",
+ top: "0 !important",
+ visibility: "hidden !important",
});
const elDimensions = Util_1.default.outerDimensions(element);
const refDimensions = Util_1.default.outerDimensions(options.refDimensionsElement instanceof HTMLElement ? options.refDimensionsElement : referenceElement);
const windowWidth = document.body.clientWidth;
let horizontal = null;
let alignCenter = false;
- if (options.horizontal === 'center') {
+ if (options.horizontal === "center") {
alignCenter = true;
horizontal = tryAlignmentHorizontal(options.horizontal, elDimensions, refDimensions, refOffsets, windowWidth);
if (!horizontal.result) {
- if (options.allowFlip === 'both' || options.allowFlip === 'horizontal') {
- options.horizontal = 'left';
+ if (options.allowFlip === "both" || options.allowFlip === "horizontal") {
+ options.horizontal = "left";
}
else {
horizontal.result = true;
}
}
// in rtl languages we simply swap the value for 'horizontal'
- if (Language.get('wcf.global.pageDirection') === 'rtl') {
- options.horizontal = (options.horizontal === 'left') ? 'right' : 'left';
+ if (Language.get("wcf.global.pageDirection") === "rtl") {
+ options.horizontal = options.horizontal === "left" ? "right" : "left";
}
if (horizontal === null || !horizontal.result) {
const horizontalCenter = horizontal;
horizontal = tryAlignmentHorizontal(options.horizontal, elDimensions, refDimensions, refOffsets, windowWidth);
- if (!horizontal.result && (options.allowFlip === 'both' || options.allowFlip === 'horizontal')) {
- const horizontalFlipped = tryAlignmentHorizontal((options.horizontal === 'left' ? 'right' : 'left'), elDimensions, refDimensions, refOffsets, windowWidth);
+ if (!horizontal.result && (options.allowFlip === "both" || options.allowFlip === "horizontal")) {
+ const horizontalFlipped = tryAlignmentHorizontal(options.horizontal === "left" ? "right" : "left", elDimensions, refDimensions, refOffsets, windowWidth);
// only use these results if it fits into the boundaries, otherwise both directions exceed and we honor the demanded direction
if (horizontalFlipped.result) {
horizontal = horizontalFlipped;
const left = horizontal.left;
const right = horizontal.right;
let vertical = tryAlignmentVertical(options.vertical, elDimensions, refDimensions, refOffsets, windowHeight, options.verticalOffset);
- if (!vertical.result && (options.allowFlip === 'both' || options.allowFlip === 'vertical')) {
- const verticalFlipped = tryAlignmentVertical((options.vertical === 'top' ? 'bottom' : 'top'), elDimensions, refDimensions, refOffsets, windowHeight, options.verticalOffset);
+ if (!vertical.result && (options.allowFlip === "both" || options.allowFlip === "vertical")) {
+ const verticalFlipped = tryAlignmentVertical(options.vertical === "top" ? "bottom" : "top", elDimensions, refDimensions, refOffsets, windowHeight, options.verticalOffset);
// only use these results if it fits into the boundaries, otherwise both directions exceed and we honor the demanded direction
if (verticalFlipped.result) {
vertical = verticalFlipped;
const top = vertical.top;
// set pointer position
if (options.pointer) {
- const pointers = DomTraverse.childrenByClass(element, 'elementPointer');
+ const pointers = DomTraverse.childrenByClass(element, "elementPointer");
const pointer = pointers[0] || null;
if (pointer === null) {
throw new Error("Expected the .elementPointer element to be a direct children.");
}
- if (horizontal.align === 'center') {
- pointer.classList.add('center');
- pointer.classList.remove('left', 'right');
+ if (horizontal.align === "center") {
+ pointer.classList.add("center");
+ pointer.classList.remove("left", "right");
}
else {
pointer.classList.add(horizontal.align);
- pointer.classList.remove('center');
- pointer.classList.remove(horizontal.align === 'left' ? 'right' : 'left');
+ pointer.classList.remove("center");
+ pointer.classList.remove(horizontal.align === "left" ? "right" : "left");
}
- if (vertical.align === 'top') {
- pointer.classList.add('flipVertical');
+ if (vertical.align === "top") {
+ pointer.classList.add("flipVertical");
}
else {
- pointer.classList.remove('flipVertical');
+ pointer.classList.remove("flipVertical");
}
}
else if (options.pointerClassNames.length === 2) {
- element.classList[(top === 'auto' ? 'add' : 'remove')](options.pointerClassNames[0 /* Bottom */]);
- element.classList[(left === 'auto' ? 'add' : 'remove')](options.pointerClassNames[1 /* Right */]);
+ element.classList[top === "auto" ? "add" : "remove"](options.pointerClassNames[0 /* Bottom */]);
+ element.classList[left === "auto" ? "add" : "remove"](options.pointerClassNames[1 /* Right */]);
}
Util_1.default.setStyles(element, {
- bottom: bottom === 'auto' ? bottom : Math.round(bottom) + 'px',
- left: left === 'auto' ? left : Math.ceil(left) + 'px',
- right: right === 'auto' ? right : Math.floor(right) + 'px',
- top: top === 'auto' ? top : Math.round(top) + 'px',
+ bottom: bottom === "auto" ? bottom : Math.round(bottom) + "px",
+ left: left === "auto" ? left : Math.ceil(left) + "px",
+ right: right === "auto" ? right : Math.floor(right) + "px",
+ top: top === "auto" ? top : Math.round(top) + "px",
});
Util_1.default.show(element);
- element.style.removeProperty('visibility');
+ element.style.removeProperty("visibility");
}
exports.set = set;
});
Ajax = tslib_1.__importStar(Ajax);
class UiArticleMarkAllAsRead {
constructor() {
- document.querySelectorAll('.markAllAsReadButton').forEach(button => {
- button.addEventListener('click', this.click.bind(this));
+ document.querySelectorAll(".markAllAsReadButton").forEach((button) => {
+ button.addEventListener("click", this.click.bind(this));
});
}
click(event) {
_ajaxSuccess() {
/* remove obsolete badges */
// main menu
- const badge = document.querySelector('.mainMenu .active .badge');
+ const badge = document.querySelector(".mainMenu .active .badge");
if (badge)
badge.remove();
// article list
- document.querySelectorAll('.articleList .newMessageBadge').forEach(el => el.remove());
+ document.querySelectorAll(".articleList .newMessageBadge").forEach((el) => el.remove());
}
_ajaxSetup() {
return {
data: {
- actionName: 'markAllAsRead',
- className: 'wcf\\data\\article\\ArticleAction',
+ actionName: "markAllAsRead",
+ className: "wcf\\data\\article\\ArticleAction",
},
};
}
const inputContainer = this.searchInput.parentElement;
const value = this.searchInput.value.trim();
if (value.length < 3) {
- Util_1.default.innerError(inputContainer, Language.get('wcf.article.search.error.tooShort'));
+ Util_1.default.innerError(inputContainer, Language.get("wcf.article.search.error.tooShort"));
return;
}
else {
}
_ajaxSuccess(data) {
let html = data.returnValues
- .map(article => {
+ .map((article) => {
return `<li>
<div class="containerHeadline pointer" data-article-id="${article.articleID}">
<h3>${StringUtil.escapeHTML(article.name)}</h3>
</div>
</li>`;
})
- .join('');
+ .join("");
this.resultList.innerHTML = html;
- Util_1.default[html ? 'show' : 'hide'](this.resultList);
+ Util_1.default[html ? "show" : "hide"](this.resultList);
if (html) {
- this.resultList.querySelectorAll('.containerHeadline').forEach(item => {
- item.addEventListener('click', this.click.bind(this));
+ this.resultList.querySelectorAll(".containerHeadline").forEach((item) => {
+ item.addEventListener("click", this.click.bind(this));
});
}
else {
const parent = this.searchInput.parentElement;
- Util_1.default.innerError(parent, Language.get('wcf.article.search.error.noResults'));
+ Util_1.default.innerError(parent, Language.get("wcf.article.search.error.noResults"));
}
}
_ajaxSetup() {
return {
data: {
- actionName: 'search',
- className: 'wcf\\data\\article\\ArticleAction',
+ actionName: "search",
+ className: "wcf\\data\\article\\ArticleAction",
},
};
}
_dialogSetup() {
return {
- id: 'wcfUiArticleSearch',
+ id: "wcfUiArticleSearch",
options: {
onSetup: () => {
- this.searchInput = document.getElementById('wcfUiArticleSearchInput');
- this.searchInput.addEventListener('keydown', event => {
- if (event.key === 'Enter') {
+ this.searchInput = document.getElementById("wcfUiArticleSearchInput");
+ this.searchInput.addEventListener("keydown", (event) => {
+ if (event.key === "Enter") {
this.search(event);
}
});
const button = this.searchInput.nextElementSibling;
- button.addEventListener('click', this.search.bind(this));
- this.resultContainer = document.getElementById('wcfUiArticleSearchResultContainer');
- this.resultList = document.getElementById('wcfUiArticleSearchResultList');
+ button.addEventListener("click", this.search.bind(this));
+ this.resultContainer = document.getElementById("wcfUiArticleSearchResultContainer");
+ this.resultList = document.getElementById("wcfUiArticleSearchResultList");
},
onShow: () => {
this.searchInput.focus();
},
- title: Language.get('wcf.article.search'),
+ title: Language.get("wcf.article.search"),
},
source: `<div class="section">
<dl>
<dt>
- <label for="wcfUiArticleSearchInput">${Language.get('wcf.article.search.name')}</label>
+ <label for="wcfUiArticleSearchInput">${Language.get("wcf.article.search.name")}</label>
</dt>
<dd>
<div class="inputAddon">
</div>
<section id="wcfUiArticleSearchResultContainer" class="section" style="display: none;">
<header class="sectionHeader">
- <h2 class="sectionTitle">${Language.get('wcf.article.search.results')}</h2>
+ <h2 class="sectionTitle">${Language.get("wcf.article.search.results")}</h2>
</header>
<ol id="wcfUiArticleSearchResultList" class="containerList"></ol>
</section>`,
* Invokes all registered callbacks.
*/
execute() {
- _callbackList.forEach(null, callback => callback());
+ _callbackList.forEach(null, (callback) => callback());
},
};
- document.body.addEventListener('click', UiCloseOverlay.execute);
+ document.body.addEventListener("click", UiCloseOverlay.execute);
return UiCloseOverlay;
});
class UiConfirmation {
constructor() {
this._active = false;
- this.dialog = document.createElement('div');
- this.dialog.id = 'wcfSystemConfirmation';
- this.dialog.classList.add('systemConfirmation');
- this.text = document.createElement('p');
+ this.dialog = document.createElement("div");
+ this.dialog.id = "wcfSystemConfirmation";
+ this.dialog.classList.add("systemConfirmation");
+ this.text = document.createElement("p");
this.dialog.appendChild(this.text);
- this._content = document.createElement('div');
- this._content.id = 'wcfSystemConfirmationContent';
+ this._content = document.createElement("div");
+ this._content.id = "wcfSystemConfirmationContent";
this.dialog.appendChild(this._content);
- const formSubmit = document.createElement('div');
- formSubmit.classList.add('formSubmit');
+ const formSubmit = document.createElement("div");
+ formSubmit.classList.add("formSubmit");
this.dialog.appendChild(formSubmit);
- this.confirmButton = document.createElement('button');
- this.confirmButton.classList.add('buttonPrimary');
- this.confirmButton.textContent = Language.get('wcf.global.confirmation.confirm');
- this.confirmButton.addEventListener('click', (ev) => this._confirm());
+ this.confirmButton = document.createElement("button");
+ this.confirmButton.classList.add("buttonPrimary");
+ this.confirmButton.textContent = Language.get("wcf.global.confirmation.confirm");
+ this.confirmButton.addEventListener("click", (ev) => this._confirm());
formSubmit.appendChild(this.confirmButton);
- const cancelButton = document.createElement('button');
- cancelButton.textContent = Language.get('wcf.global.confirmation.cancel');
- cancelButton.addEventListener('click', () => {
+ const cancelButton = document.createElement("button");
+ cancelButton.textContent = Language.get("wcf.global.confirmation.cancel");
+ cancelButton.addEventListener("click", () => {
Dialog_1.default.close(this);
});
formSubmit.appendChild(cancelButton);
}
open(options) {
this.parameters = options.parameters || {};
- this._content.innerHTML = (typeof options.template === 'string') ? options.template.trim() : '';
- this.text[options.messageIsHtml ? 'innerHTML' : 'textContent'] = options.message;
- if (typeof options.legacyCallback === 'function') {
- this.callbackCancel = parameters => {
- options.legacyCallback('cancel', parameters, this.content);
+ this._content.innerHTML = typeof options.template === "string" ? options.template.trim() : "";
+ this.text[options.messageIsHtml ? "innerHTML" : "textContent"] = options.message;
+ if (typeof options.legacyCallback === "function") {
+ this.callbackCancel = (parameters) => {
+ options.legacyCallback("cancel", parameters, this.content);
};
- this.callbackConfirm = parameters => {
- options.legacyCallback('confirm', parameters, this.content);
+ this.callbackConfirm = (parameters) => {
+ options.legacyCallback("confirm", parameters, this.content);
};
}
else {
- if (typeof options.cancel !== 'function') {
- options.cancel = () => {
- };
+ if (typeof options.cancel !== "function") {
+ options.cancel = () => { };
}
this.callbackCancel = options.cancel;
this.callbackConfirm = options.confirm;
_confirm() {
this.callbackConfirm(this.parameters, this.content);
this._active = false;
- Dialog_1.default.close('wcfSystemConfirmation');
+ Dialog_1.default.close("wcfSystemConfirmation");
}
/**
* Invoked on dialog close or if user cancels the dialog.
}
_dialogSetup() {
return {
- id: 'wcfSystemConfirmation',
+ id: "wcfSystemConfirmation",
options: {
onClose: this._onClose.bind(this),
onShow: this._onShow.bind(this),
- title: Language.get('wcf.global.confirmation.title'),
+ title: Language.get("wcf.global.confirmation.title"),
},
};
}
cancel: null,
confirm: null,
legacyCallback: null,
- message: '',
+ message: "",
messageIsHtml: false,
parameters: {},
- template: '',
+ template: "",
}, options);
- options.message = (typeof options.message === 'string') ? options.message.trim() : '';
+ options.message = typeof options.message === "string" ? options.message.trim() : "";
if (!options.message) {
throw new Error("Expected a non-empty string for option 'message'.");
}
- if (typeof options.confirm !== 'function' && typeof options.legacyCallback !== 'function') {
+ if (typeof options.confirm !== "function" && typeof options.legacyCallback !== "function") {
throw new TypeError("Expected a valid callback for option 'confirm'.");
}
getConfirmation().open(options);
const _dialogToObject = new Map();
let _focusedBeforeDialog;
let _keyupListener;
- const _validCallbacks = ['onBeforeClose', 'onClose', 'onShow'];
+ const _validCallbacks = ["onBeforeClose", "onClose", "onShow"];
// list of supported `input[type]` values for dialog submit
- const _validInputTypes = ['number', 'password', 'search', 'tel', 'text', 'url'];
+ const _validInputTypes = ["number", "password", "search", "tel", "text", "url"];
const _focusableElements = [
'a[href]:not([tabindex^="-"]):not([inert])',
'area[href]:not([tabindex^="-"]):not([inert])',
- 'input:not([disabled]):not([inert])',
- 'select:not([disabled]):not([inert])',
- 'textarea:not([disabled]):not([inert])',
- 'button:not([disabled]):not([inert])',
+ "input:not([disabled]):not([inert])",
+ "select:not([disabled]):not([inert])",
+ "textarea:not([disabled]):not([inert])",
+ "button:not([disabled]):not([inert])",
'iframe:not([tabindex^="-"]):not([inert])',
'audio:not([tabindex^="-"]):not([inert])',
'video:not([tabindex^="-"]):not([inert])',
* Sets up global container and internal variables.
*/
setup() {
- _container = document.createElement('div');
- _container.classList.add('dialogOverlay');
- _container.setAttribute('aria-hidden', 'true');
- _container.addEventListener('mousedown', (ev) => this._closeOnBackdrop(ev));
- _container.addEventListener('wheel', event => {
+ _container = document.createElement("div");
+ _container.classList.add("dialogOverlay");
+ _container.setAttribute("aria-hidden", "true");
+ _container.addEventListener("mousedown", (ev) => this._closeOnBackdrop(ev));
+ _container.addEventListener("wheel", (event) => {
if (event.target === _container) {
event.preventDefault();
}
}, { passive: false });
- document.getElementById('content').appendChild(_container);
+ document.getElementById("content").appendChild(_container);
_keyupListener = (event) => {
if (event.key === "Escape") {
const target = event.target;
- if (target.nodeName !== 'INPUT' && target.nodeName !== 'TEXTAREA') {
+ if (target.nodeName !== "INPUT" && target.nodeName !== "TEXTAREA") {
this.close(_activeDialog);
return false;
}
}
return true;
};
- UiScreen.on('screen-xs', {
+ UiScreen.on("screen-xs", {
match() {
_dialogFullHeight = true;
},
},
});
this._initStaticDialogs();
- Listener_1.default.add('Ui/Dialog', () => {
+ Listener_1.default.add("Ui/Dialog", () => {
this._initStaticDialogs();
});
UiScreen.setDialogContainer(_container);
- window.addEventListener('resize', () => {
- _dialogs.forEach(dialog => {
- if (!Core.stringToBool(dialog.dialog.getAttribute('aria-hidden'))) {
- this.rebuild(dialog.dialog.dataset.id || '');
+ window.addEventListener("resize", () => {
+ _dialogs.forEach((dialog) => {
+ if (!Core.stringToBool(dialog.dialog.getAttribute("aria-hidden"))) {
+ this.rebuild(dialog.dialog.dataset.id || "");
}
});
});
},
_initStaticDialogs() {
- document.querySelectorAll('.jsStaticDialog').forEach((button) => {
- button.classList.remove('jsStaticDialog');
- const id = button.dataset.dialogId || '';
+ document.querySelectorAll(".jsStaticDialog").forEach((button) => {
+ button.classList.remove("jsStaticDialog");
+ const id = button.dataset.dialogId || "";
if (id) {
const container = document.getElementById(id);
if (container !== null) {
- container.classList.remove('jsStaticDialogContent');
- container.dataset.isStaticDialog = 'true';
+ container.classList.remove("jsStaticDialogContent");
+ container.dataset.isStaticDialog = "true";
Util_1.default.hide(container);
- button.addEventListener('click', event => {
+ button.addEventListener("click", (event) => {
event.preventDefault();
- this.openStatic(container.id, null, { title: container.dataset.title || '' });
+ this.openStatic(container.id, null, { title: container.dataset.title || "" });
});
}
}
let dialogData = _dialogObjects.get(callbackObject);
if (dialogData && Core.isPlainObject(dialogData)) {
// dialog already exists
- return this.openStatic(dialogData.id, typeof html === 'undefined' ? null : html);
+ return this.openStatic(dialogData.id, typeof html === "undefined" ? null : html);
}
// initialize a new dialog
- if (typeof callbackObject._dialogSetup !== 'function') {
+ if (typeof callbackObject._dialogSetup !== "function") {
throw new Error("Callback object does not implement the method '_dialogSetup()'.");
}
const setupData = callbackObject._dialogSetup();
if (setupData.source === undefined) {
dialogElement = document.getElementById(id);
if (dialogElement === null) {
- throw new Error("Element id '" + id + "' is invalid and no source attribute was given. If you want to use the `html` argument instead, please add `source: null` to your dialog configuration.");
+ throw new Error("Element id '" +
+ id +
+ "' is invalid and no source attribute was given. If you want to use the `html` argument instead, please add `source: null` to your dialog configuration.");
}
setupData.source = document.createDocumentFragment();
setupData.source.appendChild(dialogElement);
- dialogElement.removeAttribute('id');
+ dialogElement.removeAttribute("id");
Util_1.default.show(dialogElement);
}
else if (setupData.source === null) {
// `null` means there is no static markup and `html` should be used instead
setupData.source = html;
}
- else if (typeof setupData.source === 'function') {
+ else if (typeof setupData.source === "function") {
setupData.source();
}
else if (Core.isPlainObject(setupData.source)) {
- if (typeof html === 'string' && html.trim() !== '') {
+ if (typeof html === "string" && html.trim() !== "") {
setupData.source = html;
}
else {
- new Promise((resolve_1, reject_1) => { require(['../Ajax'], resolve_1, reject_1); }).then(tslib_1.__importStar).then(Ajax => {
+ new Promise((resolve_1, reject_1) => { require(["../Ajax"], resolve_1, reject_1); }).then(tslib_1.__importStar).then((Ajax) => {
const source = setupData.source;
- Ajax.api(this, source.data, data => {
- if (data.returnValues && typeof data.returnValues.template === 'string') {
+ Ajax.api(this, source.data, (data) => {
+ if (data.returnValues && typeof data.returnValues.template === "string") {
this.open(callbackObject, data.returnValues.template);
- if (typeof source.after === 'function') {
+ if (typeof source.after === "function") {
source.after(_dialogs.get(id).content, data);
}
}
}
}
else {
- if (typeof setupData.source === 'string') {
- dialogElement = document.createElement('div');
+ if (typeof setupData.source === "string") {
+ dialogElement = document.createElement("div");
dialogElement.id = id;
Util_1.default.setInnerHtml(dialogElement, setupData.source);
setupData.source = document.createDocumentFragment();
*/
openStatic(id, html, options) {
UiScreen.pageOverlayOpen();
- if (Environment.platform() !== 'desktop') {
+ if (Environment.platform() !== "desktop") {
if (!this.isOpen(id)) {
UiScreen.scrollDisable();
}
options = Core.extend({
backdropCloseOnClick: true,
closable: true,
- closeButtonLabel: Language.get('wcf.global.button.close'),
- closeConfirmMessage: '',
+ closeButtonLabel: Language.get("wcf.global.button.close"),
+ closeConfirmMessage: "",
disableContentPadding: false,
- title: '',
+ title: "",
onBeforeClose: null,
onClose: null,
onShow: null,
if (!options.closable)
options.backdropCloseOnClick = false;
if (options.closeConfirmMessage) {
- options.onBeforeClose = id => {
- new Promise((resolve_2, reject_2) => { require(['./Confirmation'], resolve_2, reject_2); }).then(tslib_1.__importStar).then(UiConfirmation => {
+ options.onBeforeClose = (id) => {
+ new Promise((resolve_2, reject_2) => { require(["./Confirmation"], resolve_2, reject_2); }).then(tslib_1.__importStar).then((UiConfirmation) => {
UiConfirmation.show({
confirm: this.close.bind(this, id),
- message: options.closeConfirmMessage || '',
+ message: options.closeConfirmMessage || "",
});
});
};
// iOS breaks `position: fixed` when input elements or `contenteditable`
// are focused, this will freeze the screen and force Safari to scroll
// to the input field
- if (Environment.platform() === 'ios') {
+ if (Environment.platform() === "ios") {
window.setTimeout(() => {
var _a;
- (_a = data.content.querySelector('input, textarea')) === null || _a === void 0 ? void 0 : _a.focus();
+ (_a = data.content.querySelector("input, textarea")) === null || _a === void 0 ? void 0 : _a.focus();
}, 200);
}
return data;
if (data === undefined) {
throw new Error("Expected a valid dialog id, '" + id + "' does not match any active dialog.");
}
- const dialogTitle = data.dialog.querySelector('.dialogTitle');
+ const dialogTitle = data.dialog.querySelector(".dialogTitle");
if (dialogTitle) {
dialogTitle.textContent = title;
}
* Sets a callback function on runtime.
*/
setCallback(id, key, value) {
- if (typeof id === 'object') {
+ if (typeof id === "object") {
const dialogData = _dialogObjects.get(id);
if (dialogData !== undefined) {
id = dialogData.id;
if (_validCallbacks.indexOf(key) === -1) {
throw new Error("Invalid callback identifier, '" + key + "' is not recognized.");
}
- if (typeof value !== 'function' && value !== null) {
+ if (typeof value !== "function" && value !== null) {
throw new Error("Only functions or the 'null' value are acceptable callback values ('" + typeof value + "' given).");
}
data[key] = value;
throw new Error("Expected either a HTML string or an existing element id.");
}
}
- const dialog = document.createElement('div');
- dialog.classList.add('dialogContainer');
- dialog.setAttribute('aria-hidden', 'true');
- dialog.setAttribute('role', 'dialog');
+ const dialog = document.createElement("div");
+ dialog.classList.add("dialogContainer");
+ dialog.setAttribute("aria-hidden", "true");
+ dialog.setAttribute("role", "dialog");
dialog.id = id;
- const header = document.createElement('header');
+ const header = document.createElement("header");
dialog.appendChild(header);
const titleId = Util_1.default.getUniqueId();
- dialog.setAttribute('aria-labelledby', titleId);
- const title = document.createElement('span');
- title.classList.add('dialogTitle');
+ dialog.setAttribute("aria-labelledby", titleId);
+ const title = document.createElement("span");
+ title.classList.add("dialogTitle");
title.textContent = options.title;
title.id = titleId;
header.appendChild(title);
if (options.closable) {
- const closeButton = document.createElement('a');
- closeButton.className = 'dialogCloseButton jsTooltip';
- closeButton.href = '#';
- closeButton.setAttribute('role', 'button');
+ const closeButton = document.createElement("a");
+ closeButton.className = "dialogCloseButton jsTooltip";
+ closeButton.href = "#";
+ closeButton.setAttribute("role", "button");
closeButton.tabIndex = 0;
closeButton.title = options.closeButtonLabel;
- closeButton.setAttribute('aria-label', options.closeButtonLabel);
- closeButton.addEventListener('click', (ev) => this._close(ev));
+ closeButton.setAttribute("aria-label", options.closeButtonLabel);
+ closeButton.addEventListener("click", (ev) => this._close(ev));
header.appendChild(closeButton);
- const span = document.createElement('span');
- span.className = 'icon icon24 fa-times';
+ const span = document.createElement("span");
+ span.className = "icon icon24 fa-times";
closeButton.appendChild(span);
}
- const contentContainer = document.createElement('div');
- contentContainer.classList.add('dialogContent');
+ const contentContainer = document.createElement("div");
+ contentContainer.classList.add("dialogContent");
if (options.disableContentPadding)
- contentContainer.classList.add('dialogContentNoPadding');
+ contentContainer.classList.add("dialogContentNoPadding");
dialog.appendChild(contentContainer);
- contentContainer.addEventListener('wheel', event => {
+ contentContainer.addEventListener("wheel", (event) => {
let allowScroll = false;
let element = event.target;
let clientHeight, scrollHeight, scrollTop;
allowScroll = true;
break;
}
- else if (event.deltaY > 0 && (scrollTop + clientHeight < scrollHeight)) {
+ else if (event.deltaY > 0 && scrollTop + clientHeight < scrollHeight) {
allowScroll = true;
break;
}
}, { passive: false });
let content;
if (element === null) {
- if (typeof html === 'string') {
- content = document.createElement('div');
+ if (typeof html === "string") {
+ content = document.createElement("div");
content.id = id;
Util_1.default.setInnerHtml(content, html);
}
children.push(node);
}
}
- if (children[0].nodeName !== 'DIV' || children.length > 1) {
- content = document.createElement('div');
+ if (children[0].nodeName !== "DIV" || children.length > 1) {
+ content = document.createElement("div");
content.id = id;
content.appendChild(html);
}
content = element;
}
contentContainer.appendChild(content);
- if (content.style.getPropertyValue('display') === 'none') {
+ if (content.style.getPropertyValue("display") === "none") {
Util_1.default.show(content);
}
_dialogs.set(id, {
inputFields: new Set(),
});
_container.insertBefore(dialog, _container.firstChild);
- if (typeof options.onSetup === 'function') {
+ if (typeof options.onSetup === "function") {
options.onSetup(content);
}
this._updateDialog(id, null);
if (data === undefined) {
throw new Error("Expected a valid dialog id, '" + id + "' does not match any active dialog.");
}
- if (typeof html === 'string') {
+ if (typeof html === "string") {
Util_1.default.setInnerHtml(data.content, html);
}
- if (Core.stringToBool(data.dialog.getAttribute('aria-hidden'))) {
+ if (Core.stringToBool(data.dialog.getAttribute("aria-hidden"))) {
// close existing dropdowns
Simple_1.default.closeAll();
window.WCF.Dropdown.Interactive.Handler.closeAll();
if (_callbackFocus === null) {
_callbackFocus = this._maintainFocus.bind(this);
- document.body.addEventListener('focus', _callbackFocus, { capture: true });
+ document.body.addEventListener("focus", _callbackFocus, { capture: true });
}
- if (data.closable && Core.stringToBool(_container.getAttribute('aria-hidden'))) {
- window.addEventListener('keyup', _keyupListener);
+ if (data.closable && Core.stringToBool(_container.getAttribute("aria-hidden"))) {
+ window.addEventListener("keyup", _keyupListener);
}
// Move the dialog to the front to prevent it being hidden behind already open dialogs
// if it was previously visible.
data.dialog.parentNode.insertBefore(data.dialog, data.dialog.parentNode.firstChild);
- data.dialog.setAttribute('aria-hidden', 'false');
- _container.setAttribute('aria-hidden', 'false');
- _container.setAttribute('close-on-click', (data.backdropCloseOnClick ? 'true' : 'false'));
+ data.dialog.setAttribute("aria-hidden", "false");
+ _container.setAttribute("aria-hidden", "false");
+ _container.setAttribute("close-on-click", data.backdropCloseOnClick ? "true" : "false");
_activeDialog = id;
// Keep a reference to the currently focused element to be able to restore it later.
_focusedBeforeDialog = document.activeElement;
// Set the focus to the first focusable child of the dialog element.
- const closeButton = data.header.querySelector('.dialogCloseButton');
+ const closeButton = data.header.querySelector(".dialogCloseButton");
if (closeButton)
- closeButton.setAttribute('inert', 'true');
+ closeButton.setAttribute("inert", "true");
this._setFocusToFirstItem(data.dialog, false);
if (closeButton)
- closeButton.removeAttribute('inert');
- if (typeof data.onShow === 'function') {
+ closeButton.removeAttribute("inert");
+ if (typeof data.onShow === "function") {
data.onShow(data.content);
}
- if (Core.stringToBool(data.content.dataset.isStaticDialog || '')) {
- EventHandler.fire('com.woltlab.wcf.dialog', 'openStatic', {
+ if (Core.stringToBool(data.content.dataset.isStaticDialog || "")) {
+ EventHandler.fire("com.woltlab.wcf.dialog", "openStatic", {
content: data.content,
id: id,
});
if (_activeDialog) {
const data = _dialogs.get(_activeDialog);
const target = event.target;
- if (!data.dialog.contains(target) && !target.closest('.dropdownMenuContainer') && !target.closest('.datePicker')) {
+ if (!data.dialog.contains(target) &&
+ !target.closest(".dropdownMenuContainer") &&
+ !target.closest(".datePicker")) {
this._setFocusToFirstItem(data.dialog, true);
}
}
let focusElement = this._getFirstFocusableChild(dialog);
if (focusElement !== null) {
if (maintain) {
- if (focusElement.id === 'username' || focusElement.name === 'username') {
- if (Environment.browser() === 'safari' && Environment.platform() === 'ios') {
- // iOS Safari's username/password autofill breaks if the input field is focused
+ if (focusElement.id === "username" || focusElement.name === "username") {
+ if (Environment.browser() === "safari" && Environment.platform() === "ios") {
+ // iOS Safari's username/password autofill breaks if the input field is focused
focusElement = null;
}
}
// Setting the focus to a select element in iOS is pretty strange, because
// it focuses it, but also displays the keyboard for a fraction of a second,
// causing it to pop out from below and immediately vanish.
- //
+ //
// iOS will only show the keyboard if an input element is focused *and* the
// focus is an immediate result of a user interaction. This method must be
// assumed to be called from within a click event, but we want to set the
// focus without triggering the keyboard.
- //
+ //
// We can break the condition by wrapping it in a setTimeout() call,
// effectively tricking iOS into focusing the element without showing the
// keyboard.
}
},
_getFirstFocusableChild(element) {
- const nodeList = element.querySelectorAll(_focusableElements.join(','));
+ const nodeList = element.querySelectorAll(_focusableElements.join(","));
for (let i = 0, length = nodeList.length; i < length; i++) {
if (nodeList[i].offsetWidth && nodeList[i].offsetHeight && nodeList[i].getClientRects().length) {
return nodeList[i];
throw new Error("Expected a valid dialog id, '" + id + "' does not match any active dialog.");
}
// ignore non-active dialogs
- if (Core.stringToBool(data.dialog.getAttribute('aria-hidden'))) {
+ if (Core.stringToBool(data.dialog.getAttribute("aria-hidden"))) {
return;
}
const contentContainer = data.content.parentNode;
- const formSubmit = data.content.querySelector('.formSubmit');
+ const formSubmit = data.content.querySelector(".formSubmit");
let unavailableHeight = 0;
if (formSubmit !== null) {
- contentContainer.classList.add('dialogForm');
- formSubmit.classList.add('dialogFormSubmit');
+ contentContainer.classList.add("dialogForm");
+ formSubmit.classList.add("dialogFormSubmit");
unavailableHeight += Util_1.default.outerHeight(formSubmit);
// Calculated height can be a fractional value and depending on the
// browser the results can vary. By subtracting a single pixel we're
// working around fractional values, without visually changing anything.
unavailableHeight -= 1;
- contentContainer.style.setProperty('margin-bottom', unavailableHeight + 'px', '');
+ contentContainer.style.setProperty("margin-bottom", unavailableHeight + "px", "");
}
else {
- contentContainer.classList.remove('dialogForm');
- contentContainer.style.removeProperty('margin-bottom');
+ contentContainer.classList.remove("dialogForm");
+ contentContainer.style.removeProperty("margin-bottom");
}
unavailableHeight += Util_1.default.outerHeight(data.header);
- const maximumHeight = (window.innerHeight * (_dialogFullHeight ? 1 : 0.8)) - unavailableHeight;
- contentContainer.style.setProperty('max-height', ~~maximumHeight + 'px', '');
+ const maximumHeight = window.innerHeight * (_dialogFullHeight ? 1 : 0.8) - unavailableHeight;
+ contentContainer.style.setProperty("max-height", ~~maximumHeight + "px", "");
// fix for a calculation bug in Chrome causing the scrollbar to overlap the border
- if (Environment.browser() === 'chrome') {
+ if (Environment.browser() === "chrome") {
if (data.content.scrollHeight > maximumHeight) {
- data.content.style.setProperty('margin-right', '-1px', '');
+ data.content.style.setProperty("margin-right", "-1px", "");
}
else {
- data.content.style.removeProperty('margin-right');
+ data.content.style.removeProperty("margin-right");
}
}
// Chrome and Safari use heavy anti-aliasing when the dialog's width
// cannot be evenly divided, causing the whole text to become blurry
- if (Environment.browser() === 'chrome' || Environment.browser() === 'safari') {
+ if (Environment.browser() === "chrome" || Environment.browser() === "safari") {
// The new Microsoft Edge is detected as "chrome", because effectively we're detecting
// Chromium rather than Chrome specifically. The workaround for fractional pixels does
// not work well in Edge, there seems to be a different logic for fractional positions,
// causing the text to be blurry.
- //
+ //
// We can use `backface-visibility: hidden` to prevent the anti aliasing artifacts in
// WebKit/Blink, which will also prevent some weird font rendering issues when resizing.
- contentContainer.classList.add('jsWebKitFractionalPixelFix');
+ contentContainer.classList.add("jsWebKitFractionalPixelFix");
}
const callbackObject = _dialogToObject.get(id);
//noinspection JSUnresolvedVariable
- if (callbackObject !== undefined && typeof callbackObject._dialogSubmit === 'function') {
+ if (callbackObject !== undefined && typeof callbackObject._dialogSubmit === "function") {
const inputFields = data.content.querySelectorAll('input[data-dialog-submit-on-enter="true"]');
const submitButton = data.content.querySelector('.formSubmit > input[type="submit"], .formSubmit > button[data-type="submit"]');
if (submitButton === null) {
}
if (data.submitButton !== submitButton) {
data.submitButton = submitButton;
- submitButton.addEventListener('click', event => {
+ submitButton.addEventListener("click", (event) => {
event.preventDefault();
this._submit(id);
});
const _callbackKeydown = (event) => {
- if (event.key === 'Enter') {
+ if (event.key === "Enter") {
event.preventDefault();
this._submit(id);
}
continue;
}
data.inputFields.add(inputField);
- inputField.addEventListener('keydown', _callbackKeydown);
+ inputField.addEventListener("keydown", _callbackKeydown);
}
}
}
_submit(id) {
const data = _dialogs.get(id);
let isValid = true;
- data.inputFields.forEach(inputField => {
+ data.inputFields.forEach((inputField) => {
if (inputField.required) {
- if (inputField.value.trim() === '') {
- Util_1.default.innerError(inputField, Language.get('wcf.global.form.error.empty'));
+ if (inputField.value.trim() === "") {
+ Util_1.default.innerError(inputField, Language.get("wcf.global.form.error.empty"));
isValid = false;
}
else {
});
if (isValid) {
const callbackObject = _dialogToObject.get(id);
- if (typeof callbackObject._dialogSubmit === 'function') {
+ if (typeof callbackObject._dialogSubmit === "function") {
callbackObject._dialogSubmit();
}
}
_close(event) {
event.preventDefault();
const data = _dialogs.get(_activeDialog);
- if (typeof data.onBeforeClose === 'function') {
+ if (typeof data.onBeforeClose === "function") {
data.onBeforeClose(_activeDialog);
return false;
}
if (event.target !== _container) {
return;
}
- if (Core.stringToBool(_container.getAttribute('close-on-click'))) {
+ if (Core.stringToBool(_container.getAttribute("close-on-click"))) {
this._close(event);
}
else {
if (data === undefined) {
throw new Error("Expected a valid dialog id, '" + id + "' does not match any active dialog.");
}
- data.dialog.setAttribute('aria-hidden', 'true');
+ data.dialog.setAttribute("aria-hidden", "true");
// Move the keyboard focus away from a now hidden element.
const activeElement = document.activeElement;
- if (activeElement.closest('.dialogContainer') === data.dialog) {
+ if (activeElement.closest(".dialogContainer") === data.dialog) {
activeElement.blur();
}
- if (typeof data.onClose === 'function') {
+ if (typeof data.onClose === "function") {
data.onClose(id);
}
// get next active dialog
_activeDialog = null;
for (let i = 0; i < _container.childElementCount; i++) {
const child = _container.children[i];
- if (!Core.stringToBool(child.getAttribute('aria-hidden'))) {
- _activeDialog = child.dataset.id || '';
+ if (!Core.stringToBool(child.getAttribute("aria-hidden"))) {
+ _activeDialog = child.dataset.id || "";
break;
}
}
UiScreen.pageOverlayClose();
if (_activeDialog === null) {
- _container.setAttribute('aria-hidden', 'true');
- _container.dataset.closeOnClick = 'false';
+ _container.setAttribute("aria-hidden", "true");
+ _container.dataset.closeOnClick = "false";
if (data.closable) {
- window.removeEventListener('keyup', _keyupListener);
+ window.removeEventListener("keyup", _keyupListener);
}
}
else {
data = _dialogs.get(_activeDialog);
- _container.dataset.closeOnClick = data.backdropCloseOnClick ? 'true' : 'false';
+ _container.dataset.closeOnClick = data.backdropCloseOnClick ? "true" : "false";
}
- if (Environment.platform() !== 'desktop') {
+ if (Environment.platform() !== "desktop") {
UiScreen.scrollEnable();
}
},
*/
isOpen(id) {
const data = this.getDialog(id);
- return data !== undefined && data.dialog.getAttribute('aria-hidden') === 'false';
+ return data !== undefined && data.dialog.getAttribute("aria-hidden") === "false";
},
/**
* Destroys a dialog instance.
* @param {Object} callbackObject the same object that was used to invoke `_dialogSetup()` on first call
*/
destroy(callbackObject) {
- if (typeof callbackObject !== 'object') {
+ if (typeof callbackObject !== "object") {
throw new TypeError("Expected the callback object as parameter.");
}
if (_dialogObjects.has(callbackObject)) {
* @protected
*/
_getDialogId(id) {
- if (typeof id === 'object') {
+ if (typeof id === "object") {
const dialogData = _dialogObjects.get(id);
if (dialogData !== undefined) {
return dialogData.id;
const _validIconSizes = [16, 24, 32, 48, 64, 96, 144];
function validateList(list) {
if (!(list instanceof HTMLUListElement)) {
- throw new TypeError('Expected a reference to an <ul> element.');
+ throw new TypeError("Expected a reference to an <ul> element.");
}
- if (!list.classList.contains('dropdownMenu')) {
- throw new Error('List does not appear to be a dropdown menu.');
+ if (!list.classList.contains("dropdownMenu")) {
+ throw new Error("List does not appear to be a dropdown menu.");
}
}
function buildItemFromData(data) {
- const item = document.createElement('li');
+ const item = document.createElement("li");
// handle special `divider` type
- if (data === 'divider') {
- item.className = 'dropdownDivider';
+ if (data === "divider") {
+ item.className = "dropdownDivider";
return item;
}
- if (typeof data.identifier === 'string') {
+ if (typeof data.identifier === "string") {
item.dataset.identifier = data.identifier;
}
- const link = document.createElement('a');
- link.href = (typeof data.href === 'string') ? data.href : '#';
- if (typeof data.callback === 'function') {
- link.addEventListener('click', event => {
+ const link = document.createElement("a");
+ link.href = typeof data.href === "string" ? data.href : "#";
+ if (typeof data.callback === "function") {
+ link.addEventListener("click", (event) => {
event.preventDefault();
data.callback(link);
});
}
- else if (link.href === '#') {
- throw new Error('Expected either a `href` value or a `callback`.');
+ else if (link.href === "#") {
+ throw new Error("Expected either a `href` value or a `callback`.");
}
if (data.attributes && Core.isPlainObject(data.attributes)) {
- Object.keys(data.attributes).forEach(key => {
+ Object.keys(data.attributes).forEach((key) => {
const value = data.attributes[key];
- if (typeof value !== 'string') {
- throw new Error('Expected only string values.');
+ if (typeof value !== "string") {
+ throw new Error("Expected only string values.");
}
// Support the dash notation for backwards compatibility.
- if (key.indexOf('-') !== -1) {
+ if (key.indexOf("-") !== -1) {
link.setAttribute(`data-${key}`, value);
}
else {
});
}
item.appendChild(link);
- if (typeof data.icon !== 'undefined' && Core.isPlainObject(data.icon)) {
- if (typeof data.icon.name !== 'string') {
- throw new TypeError('Expected a valid icon name.');
+ if (typeof data.icon !== "undefined" && Core.isPlainObject(data.icon)) {
+ if (typeof data.icon.name !== "string") {
+ throw new TypeError("Expected a valid icon name.");
}
let size = 16;
- if (typeof data.icon.size === 'number' && _validIconSizes.indexOf(~~data.icon.size) !== -1) {
+ if (typeof data.icon.size === "number" && _validIconSizes.indexOf(~~data.icon.size) !== -1) {
size = ~~data.icon.size;
}
- const icon = document.createElement('span');
- icon.className = 'icon icon' + size + ' fa-' + data.icon.name;
+ const icon = document.createElement("span");
+ icon.className = "icon icon" + size + " fa-" + data.icon.name;
link.appendChild(icon);
}
- const label = (typeof data.label === 'string') ? data.label.trim() : '';
- const labelHtml = (typeof data.labelHtml === 'string') ? data.labelHtml.trim() : '';
- if (label === '' && labelHtml === '') {
- throw new TypeError('Expected either a label or a `labelHtml`.');
+ const label = typeof data.label === "string" ? data.label.trim() : "";
+ const labelHtml = typeof data.labelHtml === "string" ? data.labelHtml.trim() : "";
+ if (label === "" && labelHtml === "") {
+ throw new TypeError("Expected either a label or a `labelHtml`.");
}
- const span = document.createElement('span');
- span[label ? 'textContent' : 'innerHTML'] = (label) ? label : labelHtml;
- link.appendChild(document.createTextNode(' '));
+ const span = document.createElement("span");
+ span[label ? "textContent" : "innerHTML"] = label ? label : labelHtml;
+ link.appendChild(document.createTextNode(" "));
link.appendChild(span);
return item;
}
* into the DOM by the callee.
*/
function create(items, identifier) {
- const list = document.createElement('ul');
- list.className = 'dropdownMenu';
- if (typeof identifier === 'string') {
+ const list = document.createElement("ul");
+ list.className = "dropdownMenu";
+ if (typeof identifier === "string") {
list.dataset.identifier = identifier;
}
if (Array.isArray(items) && items.length > 0) {
function appendItems(list, items) {
validateList(list);
if (!Array.isArray(items)) {
- throw new TypeError('Expected an array of items.');
+ throw new TypeError("Expected an array of items.");
}
const length = items.length;
if (length === 0) {
- throw new Error('Expected a non-empty list of items.');
+ throw new Error("Expected a non-empty list of items.");
}
if (length === 1) {
appendItem(list, items[0]);
}
else {
const fragment = document.createDocumentFragment();
- items.forEach(item => {
+ items.forEach((item) => {
fragment.appendChild(buildItemFromData(item));
});
list.appendChild(fragment);
*/
function setItems(list, items) {
validateList(list);
- list.innerHTML = '';
+ list.innerHTML = "";
appendItems(list, items);
}
exports.setItems = setItems;
function attach(list, button) {
validateList(list);
Simple_1.default.initFragment(button, list);
- button.addEventListener('click', event => {
+ button.addEventListener("click", (event) => {
event.preventDefault();
event.stopPropagation();
Simple_1.default.toggleDropdown(button.id);
* be created.
*/
function divider() {
- return 'divider';
+ return "divider";
}
exports.divider = divider;
});
if (_dropdowns.has(identifier)) {
return;
}
- const ghostElement = document.createElement('div');
- ghostElement.id = 'reusableDropdownGhost' + _ghostElementId++;
+ const ghostElement = document.createElement("div");
+ ghostElement.id = "reusableDropdownGhost" + _ghostElementId++;
Simple_1.default.initFragment(ghostElement, menu);
_dropdowns.set(identifier, ghostElement.id);
}
const _dropdowns = new Map();
const _menus = new Map();
let _menuContainer;
- let _activeTargetId = '';
+ let _activeTargetId = "";
/**
* Handles drop-down positions in overlays when scrolling in the overlay.
*/
function onDialogScroll(event) {
const dialogContent = event.currentTarget;
- const dropdowns = dialogContent.querySelectorAll('.dropdown.dropdownOpen');
+ const dropdowns = dialogContent.querySelectorAll(".dropdown.dropdownOpen");
for (let i = 0, length = dropdowns.length; i < length; i++) {
const dropdown = dropdowns[i];
const containerId = Util_1.default.identify(dropdown);
*/
function onScroll() {
_dropdowns.forEach((dropdown, containerId) => {
- if (dropdown.classList.contains('dropdownOpen')) {
- if (Core.stringToBool(dropdown.dataset.isOverlayDropdownButton || '')) {
+ if (dropdown.classList.contains("dropdownOpen")) {
+ if (Core.stringToBool(dropdown.dataset.isOverlayDropdownButton || "")) {
UiDropdownSimple.setAlignment(dropdown, _menus.get(containerId));
}
else {
const menu = _menus.get(dropdown.id);
- if (!Core.stringToBool(menu.dataset.dropdownIgnorePageScroll || '')) {
+ if (!Core.stringToBool(menu.dataset.dropdownIgnorePageScroll || "")) {
UiDropdownSimple.close(containerId);
}
}
* Notifies callbacks on status change.
*/
function notifyCallbacks(containerId, action) {
- _callbacks.forEach(containerId, callback => {
+ _callbacks.forEach(containerId, (callback) => {
callback(containerId, action);
});
}
button = event.currentTarget;
parent = button.parentNode;
if (parent !== dropdown) {
- parent.classList.add('dropdown');
+ parent.classList.add("dropdown");
parent.id = dropdown.id;
// remove dropdown class and id from old parent
- dropdown.classList.remove('dropdown');
- dropdown.id = '';
+ dropdown.classList.remove("dropdown");
+ dropdown.id = "";
dropdown = parent;
_dropdowns.set(targetId, parent);
}
}
if (disableAutoFocus === undefined) {
- button = dropdown.closest('.dropdownToggle');
+ button = dropdown.closest(".dropdownToggle");
if (!button) {
- button = dropdown.querySelector('.dropdownToggle');
+ button = dropdown.querySelector(".dropdownToggle");
if (!button && dropdown.id) {
button = document.querySelector('[data-target="' + dropdown.id + '"]');
}
}
- if (button && Core.stringToBool(button.dataset.dropdownLazyInit || '')) {
+ if (button && Core.stringToBool(button.dataset.dropdownLazyInit || "")) {
disableAutoFocus = true;
}
}
// to close it is by clicking somewhere else in the document or on another dropdown
// toggle. This is used with the search bar to prevent the dropdown from closing by
// setting the caret position in the search input field.
- if (Core.stringToBool(dropdown.dataset.dropdownPreventToggle || '') && dropdown.classList.contains('dropdownOpen')) {
+ if (Core.stringToBool(dropdown.dataset.dropdownPreventToggle || "") &&
+ dropdown.classList.contains("dropdownOpen")) {
preventToggle = true;
}
// check if 'isOverlayDropdownButton' is set which indicates that the dropdown toggle is within an overlay
- if (dropdown.dataset.isOverlayDropdownButton === '') {
- const dialogContent = DomTraverse.parentByClass(dropdown, 'dialogContent');
- dropdown.dataset.isOverlayDropdownButton = (dialogContent !== null) ? 'true' : 'false';
+ if (dropdown.dataset.isOverlayDropdownButton === "") {
+ const dialogContent = DomTraverse.parentByClass(dropdown, "dialogContent");
+ dropdown.dataset.isOverlayDropdownButton = dialogContent !== null ? "true" : "false";
if (dialogContent !== null) {
- dialogContent.addEventListener('scroll', onDialogScroll);
+ dialogContent.addEventListener("scroll", onDialogScroll);
}
}
}
// close all dropdowns
- _activeTargetId = '';
+ _activeTargetId = "";
_dropdowns.forEach((dropdown, containerId) => {
const menu = _menus.get(containerId);
let firstListItem = null;
- if (dropdown.classList.contains('dropdownOpen')) {
+ if (dropdown.classList.contains("dropdownOpen")) {
if (!preventToggle) {
- dropdown.classList.remove('dropdownOpen');
- menu.classList.remove('dropdownOpen');
- const button = dropdown.querySelector('.dropdownToggle');
+ dropdown.classList.remove("dropdownOpen");
+ menu.classList.remove("dropdownOpen");
+ const button = dropdown.querySelector(".dropdownToggle");
if (button)
- button.setAttribute('aria-expanded', 'false');
- notifyCallbacks(containerId, 'close');
+ button.setAttribute("aria-expanded", "false");
+ notifyCallbacks(containerId, "close");
}
else {
_activeTargetId = targetId;
}
else if (containerId === targetId && menu.childElementCount > 0) {
_activeTargetId = targetId;
- dropdown.classList.add('dropdownOpen');
- menu.classList.add('dropdownOpen');
- const button = dropdown.querySelector('.dropdownToggle');
+ dropdown.classList.add("dropdownOpen");
+ menu.classList.add("dropdownOpen");
+ const button = dropdown.querySelector(".dropdownToggle");
if (button)
- button.setAttribute('aria-expanded', 'true');
+ button.setAttribute("aria-expanded", "true");
const list = menu.childElementCount > 0 ? menu.children[0] : null;
- if (list && Core.stringToBool(list.dataset.scrollToActive || '')) {
+ if (list && Core.stringToBool(list.dataset.scrollToActive || "")) {
delete list.dataset.scrollToActive;
let active = null;
for (let i = 0, length = list.childElementCount; i < length; i++) {
- if (list.children[i].classList.contains('active')) {
+ if (list.children[i].classList.contains("active")) {
active = list.children[i];
break;
}
}
if (active) {
- list.scrollTop = Math.max((active.offsetTop + active.clientHeight) - menu.clientHeight, 0);
+ list.scrollTop = Math.max(active.offsetTop + active.clientHeight - menu.clientHeight, 0);
}
}
- const itemList = menu.querySelector('.scrollableDropdownMenu');
+ const itemList = menu.querySelector(".scrollableDropdownMenu");
if (itemList !== null) {
- itemList.classList[(itemList.scrollHeight > itemList.clientHeight ? 'add' : 'remove')]('forceScrollbar');
+ itemList.classList[itemList.scrollHeight > itemList.clientHeight ? "add" : "remove"]("forceScrollbar");
}
- notifyCallbacks(containerId, 'open');
+ notifyCallbacks(containerId, "open");
if (!disableAutoFocus) {
- menu.setAttribute('role', 'menu');
+ menu.setAttribute("role", "menu");
menu.tabIndex = -1;
- menu.removeEventListener('keydown', dropdownMenuKeyDown);
- menu.addEventListener('keydown', dropdownMenuKeyDown);
- menu.querySelectorAll('li').forEach(listItem => {
+ menu.removeEventListener("keydown", dropdownMenuKeyDown);
+ menu.addEventListener("keydown", dropdownMenuKeyDown);
+ menu.querySelectorAll("li").forEach((listItem) => {
if (!listItem.clientHeight)
return;
if (firstListItem === null)
firstListItem = listItem;
- else if (listItem.classList.contains('active'))
+ else if (listItem.classList.contains("active"))
firstListItem = listItem;
- listItem.setAttribute('role', 'menuitem');
+ listItem.setAttribute("role", "menuitem");
listItem.tabIndex = -1;
});
}
}
});
window.WCF.Dropdown.Interactive.Handler.closeAll();
- return (event === null);
+ return event === null;
}
function handleKeyDown(event) {
// <input> elements are not valid targets for drop-down menus. However, some developers
// might still decide to combine them, in which case we try not to break things even more.
const target = event.currentTarget;
- if (target.nodeName === 'INPUT') {
+ if (target.nodeName === "INPUT") {
return;
}
- if (event.key === 'Enter' || event.key === 'Space') {
+ if (event.key === "Enter" || event.key === "Space") {
event.preventDefault();
toggle(event);
}
}
function dropdownMenuKeyDown(event) {
const activeItem = document.activeElement;
- if (activeItem.nodeName !== 'LI') {
+ if (activeItem.nodeName !== "LI") {
return;
}
- if (event.key === 'ArrowDown' || event.key === 'ArrowUp' || event.key === 'End' || event.key === 'Home') {
+ if (event.key === "ArrowDown" || event.key === "ArrowUp" || event.key === "End" || event.key === "Home") {
event.preventDefault();
- const listItems = Array.from(activeItem.closest('.dropdownMenu').querySelectorAll('li'));
- if (event.key === 'ArrowUp' || event.key === 'End') {
+ const listItems = Array.from(activeItem.closest(".dropdownMenu").querySelectorAll("li"));
+ if (event.key === "ArrowUp" || event.key === "End") {
listItems.reverse();
}
let newActiveItem = null;
- const isValidItem = listItem => {
- return !listItem.classList.contains('dropdownDivider') && listItem.clientHeight > 0;
+ const isValidItem = (listItem) => {
+ return !listItem.classList.contains("dropdownDivider") && listItem.clientHeight > 0;
};
let activeIndex = listItems.indexOf(activeItem);
- if (event.key === 'End' || event.key === 'Home') {
+ if (event.key === "End" || event.key === "Home") {
activeIndex = -1;
}
for (let i = activeIndex + 1; i < listItems.length; i++) {
newActiveItem.focus();
}
}
- else if (event.key === 'Enter' || event.key === 'Space') {
+ else if (event.key === "Enter" || event.key === "Space") {
event.preventDefault();
let target = activeItem;
- if (target.childElementCount === 1 && (target.children[0].nodeName === 'SPAN' || target.children[0].nodeName === 'A')) {
+ if (target.childElementCount === 1 &&
+ (target.children[0].nodeName === "SPAN" || target.children[0].nodeName === "A")) {
target = target.children[0];
}
const dropdown = _dropdowns.get(_activeTargetId);
- const button = dropdown.querySelector('.dropdownToggle');
- const mouseEvent = dropdown.dataset.a11yMouseEvent || 'click';
+ const button = dropdown.querySelector(".dropdownToggle");
+ const mouseEvent = dropdown.dataset.a11yMouseEvent || "click";
Core.triggerEvent(target, mouseEvent);
if (button) {
button.focus();
}
}
- else if (event.key === 'Escape' || event.key === 'Tab') {
+ else if (event.key === "Escape" || event.key === "Tab") {
event.preventDefault();
const dropdown = _dropdowns.get(_activeTargetId);
- let button = dropdown.querySelector('.dropdownToggle');
+ let button = dropdown.querySelector(".dropdownToggle");
// Remote controlled drop-down menus may not have a dedicated toggle button, instead the
// `dropdown` element itself is the button.
- if (button === null && !dropdown.classList.contains('dropdown')) {
+ if (button === null && !dropdown.classList.contains("dropdown")) {
button = dropdown;
}
toggle(null, _activeTargetId);
if (_didInit)
return;
_didInit = true;
- _menuContainer = document.createElement('div');
- _menuContainer.className = 'dropdownMenuContainer';
+ _menuContainer = document.createElement("div");
+ _menuContainer.className = "dropdownMenuContainer";
document.body.appendChild(_menuContainer);
- _availableDropdowns = document.getElementsByClassName('dropdownToggle');
+ _availableDropdowns = document.getElementsByClassName("dropdownToggle");
UiDropdownSimple.initAll();
- CloseOverlay_1.default.add('WoltLabSuite/Core/Ui/Dropdown/Simple', UiDropdownSimple.closeAll);
- Listener_1.default.add('WoltLabSuite/Core/Ui/Dropdown/Simple', UiDropdownSimple.initAll);
- document.addEventListener('scroll', onScroll);
+ CloseOverlay_1.default.add("WoltLabSuite/Core/Ui/Dropdown/Simple", UiDropdownSimple.closeAll);
+ Listener_1.default.add("WoltLabSuite/Core/Ui/Dropdown/Simple", UiDropdownSimple.initAll);
+ document.addEventListener("scroll", onScroll);
// expose on window object for backward compatibility
window.bc_wcfSimpleDropdown = this;
},
*/
init(button, isLazyInitialization) {
UiDropdownSimple.setup();
- button.setAttribute('role', 'button');
+ button.setAttribute("role", "button");
button.tabIndex = 0;
- button.setAttribute('aria-haspopup', 'true');
- button.setAttribute('aria-expanded', 'false');
- if (button.classList.contains('jsDropdownEnabled') || button.dataset.target) {
+ button.setAttribute("aria-haspopup", "true");
+ button.setAttribute("aria-expanded", "false");
+ if (button.classList.contains("jsDropdownEnabled") || button.dataset.target) {
return false;
}
- const dropdown = DomTraverse.parentByClass(button, 'dropdown');
+ const dropdown = DomTraverse.parentByClass(button, "dropdown");
if (dropdown === null) {
throw new Error("Invalid dropdown passed, button '" + Util_1.default.identify(button) + "' does not have a parent with .dropdown.");
}
- const menu = DomTraverse.nextByClass(button, 'dropdownMenu');
+ const menu = DomTraverse.nextByClass(button, "dropdownMenu");
if (menu === null) {
throw new Error("Invalid dropdown passed, button '" + Util_1.default.identify(button) + "' does not have a menu as next sibling.");
}
_menuContainer.appendChild(menu);
const containerId = Util_1.default.identify(dropdown);
if (!_dropdowns.has(containerId)) {
- button.classList.add('jsDropdownEnabled');
- button.addEventListener('click', toggle);
- button.addEventListener('keydown', handleKeyDown);
+ button.classList.add("jsDropdownEnabled");
+ button.addEventListener("click", toggle);
+ button.addEventListener("keydown", handleKeyDown);
_dropdowns.set(containerId, dropdown);
_menus.set(containerId, menu);
if (!containerId.match(/^wcf\d+$/)) {
menu.dataset.source = containerId;
}
// prevent page scrolling
- if (menu.childElementCount && menu.children[0].classList.contains('scrollableDropdownMenu')) {
+ if (menu.childElementCount && menu.children[0].classList.contains("scrollableDropdownMenu")) {
const child = menu.children[0];
- child.dataset.scrollToActive = 'true';
+ child.dataset.scrollToActive = "true";
let menuHeight = null;
let menuRealHeight = null;
- child.addEventListener('wheel', event => {
+ child.addEventListener("wheel", (event) => {
if (menuHeight === null)
menuHeight = child.clientHeight;
if (menuRealHeight === null)
if (event.deltaY < 0 && child.scrollTop === 0) {
event.preventDefault();
}
- else if (event.deltaY > 0 && (child.scrollTop + menuHeight === menuRealHeight)) {
+ else if (event.deltaY > 0 && child.scrollTop + menuHeight === menuRealHeight) {
event.preventDefault();
}
}, { passive: false });
button.dataset.target = containerId;
if (isLazyInitialization) {
setTimeout(() => {
- button.dataset.dropdownLazyInit = (isLazyInitialization instanceof MouseEvent) ? 'true' : 'false';
- Core.triggerEvent(button, 'click');
+ button.dataset.dropdownLazyInit = isLazyInitialization instanceof MouseEvent ? "true" : "false";
+ Core.triggerEvent(button, "click");
setTimeout(() => {
delete button.dataset.dropdownLazyInit;
}, 10);
*/
setAlignment(dropdown, dropdownMenu, alternateElement) {
// check if button belongs to an i18n textarea
- const button = dropdown.querySelector('.dropdownToggle');
- const parent = (button !== null) ? button.parentNode : null;
+ const button = dropdown.querySelector(".dropdownToggle");
+ const parent = button !== null ? button.parentNode : null;
let refDimensionsElement;
- if (parent && parent.classList.contains('inputAddonTextarea')) {
+ if (parent && parent.classList.contains("inputAddonTextarea")) {
refDimensionsElement = button;
}
UiAlignment.set(dropdownMenu, alternateElement || dropdown, {
- pointerClassNames: ['dropdownArrowBottom', 'dropdownArrowRight'],
+ pointerClassNames: ["dropdownArrowBottom", "dropdownArrowRight"],
refDimensionsElement: refDimensionsElement || null,
// alignment
- horizontal: dropdownMenu.dataset.dropdownAlignmentHorizontal === 'right' ? 'right' : 'left',
- vertical: dropdownMenu.dataset.dropdownAlignmentVertical === 'top' ? 'top' : 'bottom',
- allowFlip: dropdownMenu.dataset.dropdownAllowFlip || 'both',
+ horizontal: dropdownMenu.dataset.dropdownAlignmentHorizontal === "right" ? "right" : "left",
+ vertical: dropdownMenu.dataset.dropdownAlignmentVertical === "top" ? "top" : "bottom",
+ allowFlip: dropdownMenu.dataset.dropdownAllowFlip || "both",
});
},
/**
*/
isOpen(containerId) {
const menu = _menus.get(containerId);
- return (menu !== undefined && menu.classList.contains('dropdownOpen'));
+ return menu !== undefined && menu.classList.contains("dropdownOpen");
},
/**
* Opens the dropdown unless it is already open.
*/
open(containerId, disableAutoFocus) {
const menu = _menus.get(containerId);
- if (menu !== undefined && !menu.classList.contains('dropdownOpen')) {
+ if (menu !== undefined && !menu.classList.contains("dropdownOpen")) {
UiDropdownSimple.toggleDropdown(containerId, undefined, disableAutoFocus);
}
},
close(containerId) {
const dropdown = _dropdowns.get(containerId);
if (dropdown !== undefined) {
- dropdown.classList.remove('dropdownOpen');
- _menus.get(containerId).classList.remove('dropdownOpen');
+ dropdown.classList.remove("dropdownOpen");
+ _menus.get(containerId).classList.remove("dropdownOpen");
}
},
/**
*/
closeAll() {
_dropdowns.forEach((dropdown, containerId) => {
- if (dropdown.classList.contains('dropdownOpen')) {
- dropdown.classList.remove('dropdownOpen');
- _menus.get(containerId).classList.remove('dropdownOpen');
- notifyCallbacks(containerId, 'close');
+ if (dropdown.classList.contains("dropdownOpen")) {
+ dropdown.classList.remove("dropdownOpen");
+ _menus.get(containerId).classList.remove("dropdownOpen");
+ notifyCallbacks(containerId, "close");
}
});
},
*/
createButtons() {
let triggerChange = false;
- this.target.querySelectorAll('li.uploadedFile').forEach((element) => {
+ this.target.querySelectorAll("li.uploadedFile").forEach((element) => {
const uniqueFileId = element.dataset.uniqueFileId;
if (this.containers.has(uniqueFileId)) {
return;
* Init the delete button for a specific element.
*/
initDeleteButton(element, elementData) {
- const buttonGroup = element.querySelector('.buttonGroup');
+ const buttonGroup = element.querySelector(".buttonGroup");
if (buttonGroup === null) {
throw new Error(`Button group in '${this.target.id}' is unknown.`);
}
- const li = document.createElement('li');
- const span = document.createElement('span');
+ const li = document.createElement("li");
+ const span = document.createElement("span");
span.className = "button jsDeleteButton small";
- span.textContent = Language.get('wcf.global.button.delete');
+ span.textContent = Language.get("wcf.global.button.delete");
li.appendChild(span);
buttonGroup.appendChild(li);
- li.addEventListener('click', this.deleteElement.bind(this, elementData.uniqueFileId));
+ li.addEventListener("click", this.deleteElement.bind(this, elementData.uniqueFileId));
}
/**
* Delete a specific file with the given uniqueFileId.
this.createButtons();
return;
}
- const img = this.target.querySelector('img');
+ const img = this.target.querySelector("img");
if (img !== null) {
const uniqueFileId = img.dataset.uniqueFileId;
if (!this.containers.has(uniqueFileId)) {
element: img,
};
this.containers.set(uniqueFileId, elementData);
- this.deleteButton = document.createElement('p');
- this.deleteButton.className = 'button deleteButton';
- const span = document.createElement('span');
- span.textContent = Language.get('wcf.global.button.delete');
+ this.deleteButton = document.createElement("p");
+ this.deleteButton.className = "button deleteButton";
+ const span = document.createElement("span");
+ span.textContent = Language.get("wcf.global.button.delete");
this.deleteButton.appendChild(span);
this.buttonContainer.appendChild(this.deleteButton);
- this.deleteButton.addEventListener('click', this.deleteElement.bind(this, elementData.uniqueFileId));
+ this.deleteButton.addEventListener("click", this.deleteElement.bind(this, elementData.uniqueFileId));
}
}
}
this.deleteButton = undefined;
}
this.uploadHandler.checkMaxFiles();
- Core.triggerEvent(this.target, 'change');
+ Core.triggerEvent(this.target, "change");
}
_ajaxSetup() {
return {
- url: 'index.php?ajax-file-delete/&t=' + window.SECURITY_TOKEN,
+ url: "index.php?ajax-file-delete/&t=" + window.SECURITY_TOKEN,
};
}
}
* Register default menus and set up event listeners.
*/
function setup() {
- if (document.getElementById('mainMenu') !== null) {
- register('mainMenu');
+ if (document.getElementById("mainMenu") !== null) {
+ register("mainMenu");
}
- const navigationHeader = document.querySelector('.navigationHeader');
+ const navigationHeader = document.querySelector(".navigationHeader");
if (navigationHeader !== null) {
register(Util_1.default.identify(navigationHeader));
}
- window.addEventListener('resize', rebuildAll);
- Listener_1.default.add('WoltLabSuite/Core/Ui/FlexibleMenu', registerTabMenus);
+ window.addEventListener("resize", rebuildAll);
+ Listener_1.default.add("WoltLabSuite/Core/Ui/FlexibleMenu", registerTabMenus);
}
exports.setup = setup;
/**
if (_containers.has(containerId)) {
return;
}
- const list = DomTraverse.childByTag(container, 'UL');
+ const list = DomTraverse.childByTag(container, "UL");
if (list === null) {
throw "Expected an <ul> element as child of container '" + containerId + "'.";
}
* Registers tab menus.
*/
function registerTabMenus() {
- document.querySelectorAll('.tabMenuContainer:not(.jsFlexibleMenuEnabled), .messageTabMenu:not(.jsFlexibleMenuEnabled)').forEach(tabMenu => {
- const nav = DomTraverse.childByTag(tabMenu, 'NAV');
+ document
+ .querySelectorAll(".tabMenuContainer:not(.jsFlexibleMenuEnabled), .messageTabMenu:not(.jsFlexibleMenuEnabled)")
+ .forEach((tabMenu) => {
+ const nav = DomTraverse.childByTag(tabMenu, "NAV");
if (nav !== null) {
- tabMenu.classList.add('jsFlexibleMenuEnabled');
+ tabMenu.classList.add("jsFlexibleMenuEnabled");
register(Util_1.default.identify(nav));
}
});
const styles = window.getComputedStyle(container);
const parent = container.parentNode;
let availableWidth = parent.clientWidth;
- availableWidth -= Util_1.default.styleAsInt(styles, 'margin-left');
- availableWidth -= Util_1.default.styleAsInt(styles, 'margin-right');
+ availableWidth -= Util_1.default.styleAsInt(styles, "margin-left");
+ availableWidth -= Util_1.default.styleAsInt(styles, "margin-right");
const list = _itemLists.get(containerId);
- const items = DomTraverse.childrenByTag(list, 'LI');
+ const items = DomTraverse.childrenByTag(list, "LI");
let dropdown = _dropdowns.get(containerId);
let dropdownWidth = 0;
if (dropdown !== undefined) {
// show all items for calculation
for (let i = 0, length = items.length; i < length; i++) {
const item = items[i];
- if (item.classList.contains('dropdown')) {
+ if (item.classList.contains("dropdown")) {
continue;
}
Util_1.default.show(item);
for (let i = items.length - 1; i >= 0; i--) {
const item = items[i];
// ignore dropdown and active item
- if (item.classList.contains('dropdown') || item.classList.contains('active') || item.classList.contains('ui-state-active')) {
+ if (item.classList.contains("dropdown") ||
+ item.classList.contains("active") ||
+ item.classList.contains("ui-state-active")) {
continue;
}
hiddenItems.push(item);
if (hiddenItems.length) {
let dropdownMenu;
if (dropdown === undefined) {
- dropdown = document.createElement('li');
- dropdown.className = 'dropdown jsFlexibleMenuDropdown';
- const icon = document.createElement('a');
- icon.className = 'icon icon16 fa-list';
+ dropdown = document.createElement("li");
+ dropdown.className = "dropdown jsFlexibleMenuDropdown";
+ const icon = document.createElement("a");
+ icon.className = "icon icon16 fa-list";
dropdown.appendChild(icon);
- dropdownMenu = document.createElement('ul');
- dropdownMenu.classList.add('dropdownMenu');
+ dropdownMenu = document.createElement("ul");
+ dropdownMenu.classList.add("dropdownMenu");
dropdown.appendChild(dropdownMenu);
_dropdowns.set(containerId, dropdown);
_dropdownMenus.set(containerId, dropdownMenu);
}
// build dropdown menu
const fragment = document.createDocumentFragment();
- hiddenItems.forEach(hiddenItem => {
- const item = document.createElement('li');
+ hiddenItems.forEach((hiddenItem) => {
+ const item = document.createElement("li");
item.innerHTML = hiddenItem.innerHTML;
- item.addEventListener('click', event => {
+ item.addEventListener("click", (event) => {
var _a;
event.preventDefault();
- (_a = hiddenItem.querySelector('a')) === null || _a === void 0 ? void 0 : _a.click();
+ (_a = hiddenItem.querySelector("a")) === null || _a === void 0 ? void 0 : _a.click();
// force a rebuild to guarantee the active item being visible
setTimeout(() => {
rebuild(containerId);
});
fragment.appendChild(item);
});
- dropdownMenu.innerHTML = '';
+ dropdownMenu.innerHTML = "";
dropdownMenu.appendChild(fragment);
}
else if (dropdown !== undefined && dropdown.parentNode !== null) {
Suggestion_1 = tslib_1.__importDefault(Suggestion_1);
Simple_1 = tslib_1.__importDefault(Simple_1);
Util_1 = tslib_1.__importDefault(Util_1);
- let _activeId = '';
+ let _activeId = "";
const _data = new Map();
/**
* Creates the DOM structure for target element. If `element` is a `<textarea>`
*/
function createUI(element, options) {
const parentElement = element.parentElement;
- const list = document.createElement('ol');
- list.className = 'inputItemList' + (element.disabled ? ' disabled' : '');
+ const list = document.createElement("ol");
+ list.className = "inputItemList" + (element.disabled ? " disabled" : "");
list.dataset.elementId = element.id;
- list.addEventListener('click', event => {
+ list.addEventListener("click", (event) => {
if (event.target === list) {
element.focus();
}
});
- const listItem = document.createElement('li');
- listItem.className = 'input';
+ const listItem = document.createElement("li");
+ listItem.className = "input";
list.appendChild(listItem);
- element.addEventListener('keydown', keyDown);
- element.addEventListener('keypress', keyPress);
- element.addEventListener('keyup', keyUp);
- element.addEventListener('paste', paste);
- const hasFocus = (element === document.activeElement);
+ element.addEventListener("keydown", keyDown);
+ element.addEventListener("keypress", keyPress);
+ element.addEventListener("keyup", keyUp);
+ element.addEventListener("paste", paste);
+ const hasFocus = element === document.activeElement;
if (hasFocus) {
element.blur();
}
- element.addEventListener('blur', blur);
+ element.addEventListener("blur", blur);
parentElement.insertBefore(list, element);
listItem.appendChild(element);
if (hasFocus) {
if (options.maxLength !== -1) {
element.maxLength = options.maxLength;
}
- const limitReached = document.createElement('span');
- limitReached.className = 'inputItemListLimitReached';
- limitReached.textContent = Language.get('wcf.global.form.input.maxItems');
+ const limitReached = document.createElement("span");
+ limitReached.className = "inputItemListLimitReached";
+ limitReached.textContent = Language.get("wcf.global.form.input.maxItems");
Util_1.default.hide(limitReached);
listItem.appendChild(limitReached);
let shadow = null;
const values = [];
if (options.isCSV) {
- shadow = document.createElement('input');
- shadow.className = 'itemListInputShadow';
- shadow.type = 'hidden';
+ shadow = document.createElement("input");
+ shadow.className = "itemListInputShadow";
+ shadow.type = "hidden";
shadow.name = element.name;
- element.removeAttribute('name');
+ element.removeAttribute("name");
list.parentNode.insertBefore(shadow, list);
- element.value.split(',').forEach(value => {
+ element.value.split(",").forEach((value) => {
value = value.trim();
if (value) {
values.push(value);
}
});
- if (element.nodeName === 'TEXTAREA') {
- const inputElement = document.createElement('input');
- inputElement.type = 'text';
+ if (element.nodeName === "TEXTAREA") {
+ const inputElement = document.createElement("input");
+ inputElement.type = "text";
parentElement.insertBefore(inputElement, element);
inputElement.id = element.id;
element.remove();
if (data.options.maxItems === -1) {
return true;
}
- return (data.list.childElementCount - 1 < data.options.maxItems);
+ return data.list.childElementCount - 1 < data.options.maxItems;
}
/**
* Enforces the maximum number of items.
const input = event.currentTarget;
_activeId = input.id;
const lastItem = input.parentElement.previousElementSibling;
- if (event.key === 'Backspace') {
+ if (event.key === "Backspace") {
if (input.value.length === 0) {
if (lastItem !== null) {
- if (lastItem.classList.contains('active')) {
+ if (lastItem.classList.contains("active")) {
removeItem(lastItem);
}
else {
- lastItem.classList.add('active');
+ lastItem.classList.add("active");
}
}
}
}
- else if (event.key === 'Escape') {
- if (lastItem !== null && lastItem.classList.contains('active')) {
- lastItem.classList.remove('active');
+ else if (event.key === "Escape") {
+ if (lastItem !== null && lastItem.classList.contains("active")) {
+ lastItem.classList.remove("active");
}
}
}
* Handles the `[ENTER]` and `[,]` key to add an item to the list unless it is restricted.
*/
function keyPress(event) {
- if (event.key === 'Enter' || event.key === ',') {
+ if (event.key === "Enter" || event.key === ",") {
event.preventDefault();
const input = event.currentTarget;
if (_data.get(input.id).options.restricted) {
*/
function paste(event) {
event.preventDefault();
- const text = event.clipboardData.getData('text/plain');
+ const text = event.clipboardData.getData("text/plain");
const element = event.currentTarget;
const elementId = element.id;
const maxLength = +element.maxLength;
- text.split(/,/).forEach(item => {
+ text.split(/,/).forEach((item) => {
item = item.trim();
if (maxLength && item.length > maxLength) {
// truncating items provides a better UX than throwing an error or silently discarding it
if (input.value.length > 0) {
const lastItem = input.parentElement.previousElementSibling;
if (lastItem !== null) {
- lastItem.classList.remove('active');
+ lastItem.classList.remove("active");
}
}
}
*/
function addItem(elementId, value) {
const data = _data.get(elementId);
- const listItem = document.createElement('li');
- listItem.className = 'item';
- const content = document.createElement('span');
- content.className = 'content';
+ const listItem = document.createElement("li");
+ listItem.className = "item";
+ const content = document.createElement("span");
+ content.className = "content";
content.dataset.objectId = value.objectId.toString();
if (value.type) {
content.dataset.type = value.type;
content.textContent = value.value;
listItem.appendChild(content);
if (!data.element.disabled) {
- const button = document.createElement('a');
- button.className = 'icon icon16 fa-times';
- button.addEventListener('click', removeItem);
+ const button = document.createElement("a");
+ button.className = "icon icon16 fa-times";
+ button.addEventListener("click", removeItem);
listItem.appendChild(button);
}
data.list.insertBefore(listItem, data.listItem);
data.suggestion.addExcludedValue(value.value);
- data.element.value = '';
+ data.element.value = "";
if (!data.element.disabled) {
handleLimit(elementId);
}
let values = syncShadow(data);
- if (typeof data.options.callbackChange === 'function') {
+ if (typeof data.options.callbackChange === "function") {
if (values === null) {
values = getValues(elementId);
}
item = target.parentElement;
}
const parent = item.parentElement;
- const elementId = parent.dataset.elementId || '';
+ const elementId = parent.dataset.elementId || "";
const data = _data.get(elementId);
if (item.children[0].textContent) {
data.suggestion.removeExcludedValue(item.children[0].textContent);
}
handleLimit(elementId);
let values = syncShadow(data);
- if (typeof data.options.callbackChange === 'function') {
+ if (typeof data.options.callbackChange === "function") {
if (values === null) {
values = getValues(elementId);
}
if (!data.options.isCSV) {
return null;
}
- if (typeof data.options.callbackSyncShadow === 'function') {
+ if (typeof data.options.callbackSyncShadow === "function") {
return data.options.callbackSyncShadow(data);
}
const values = getValues(data.element.id);
data.shadow.value = getValues(data.element.id)
- .map(value => value.value)
- .join(',');
+ .map((value) => value.value)
+ .join(",");
return values;
}
/**
// remove data from previous instance
if (_data.has(elementId)) {
const tmp = _data.get(elementId);
- Object.keys(tmp).forEach(key => {
+ Object.keys(tmp).forEach((key) => {
const el = tmp[key];
if (el instanceof Element && el.parentNode) {
el.remove();
options = Core.extend({
// search parameters for suggestions
ajax: {
- actionName: 'getSearchResultList',
- className: '',
+ actionName: "getSearchResultList",
+ className: "",
data: {},
},
// list of excluded string values, e.g. `['ignore', 'these strings', 'when', 'searching']`
// Callback to set values during the setup.
callbackSetupValues: null,
// value may contain the placeholder `{$objectId}`
- submitFieldName: '',
+ submitFieldName: "",
}, options);
- const form = DomTraverse.parentByTag(element, 'FORM');
+ const form = DomTraverse.parentByTag(element, "FORM");
if (form !== null) {
if (!options.isCSV) {
- if (!options.submitFieldName.length && typeof options.callbackSubmit !== 'function') {
+ if (!options.submitFieldName.length && typeof options.callbackSubmit !== "function") {
throw new Error("Expected a valid function for option 'callbackSubmit', a non-empty value for option 'submitFieldName' or enabling the option 'submitFieldCSV'.");
}
- form.addEventListener('submit', () => {
+ form.addEventListener("submit", () => {
if (acceptsNewItems(elementId)) {
const value = _data.get(elementId).element.value.trim();
if (value.length) {
}
const values = getValues(elementId);
if (options.submitFieldName.length) {
- values.forEach(value => {
- const input = document.createElement('input');
- input.type = 'hidden';
- input.name = options.submitFieldName.replace('{$objectId}', value.objectId.toString());
+ values.forEach((value) => {
+ const input = document.createElement("input");
+ input.type = "hidden";
+ input.name = options.submitFieldName.replace("{$objectId}", value.objectId.toString());
input.value = value.value;
form.appendChild(input);
});
});
}
else {
- form.addEventListener('submit', () => {
+ form.addEventListener("submit", () => {
if (acceptsNewItems(elementId)) {
const value = _data.get(elementId).element.value.trim();
if (value.length) {
values = options.callbackSetupValues();
}
else {
- values = (data.values.length) ? data.values : values;
+ values = data.values.length ? data.values : values;
}
if (Array.isArray(values)) {
- values.forEach(value => {
- if (typeof value === 'string') {
+ values.forEach((value) => {
+ if (typeof value === "string") {
value = { objectId: 0, value: value };
}
addItem(elementId, value);
throw new Error("Element id '" + elementId + "' is unknown.");
}
const values = [];
- data.list.querySelectorAll('.item > span').forEach((span) => {
+ data.list.querySelectorAll(".item > span").forEach((span) => {
values.push({
- objectId: +(span.dataset.objectId || ''),
+ objectId: +(span.dataset.objectId || ""),
value: span.textContent.trim(),
type: span.dataset.type,
});
throw new Error("Element id '" + elementId + "' is unknown.");
}
// remove all existing items first
- DomTraverse.childrenByClass(data.list, 'item').forEach((item) => {
+ DomTraverse.childrenByClass(data.list, "item").forEach((item) => {
removeItem(item, true);
});
// add new items
- values.forEach(value => {
+ values.forEach((value) => {
addItem(elementId, value);
});
}
if (_didInit)
return;
_didInit = true;
- _notificationElement = document.createElement('div');
- _notificationElement.id = 'systemNotification';
- _message = document.createElement('p');
- _message.addEventListener('click', hide);
+ _notificationElement = document.createElement("div");
+ _notificationElement.id = "systemNotification";
+ _message = document.createElement("p");
+ _message.addEventListener("click", hide);
_notificationElement.appendChild(_message);
document.body.appendChild(_notificationElement);
}
*/
function hide() {
clearTimeout(_timeout);
- _notificationElement.classList.remove('active');
+ _notificationElement.classList.remove("active");
if (_callback !== null) {
_callback();
}
}
_busy = true;
init();
- _callback = (typeof callback === 'function') ? callback : null;
- _message.className = cssClassName || 'success';
- _message.textContent = Language.get(message || 'wcf.global.success');
- _notificationElement.classList.add('active');
+ _callback = typeof callback === "function" ? callback : null;
+ _message.className = cssClassName || "success";
+ _message.textContent = Language.get(message || "wcf.global.success");
+ _notificationElement.classList.add("active");
_timeout = setTimeout(hide, 2000);
}
exports.show = show;
let _toTopButton;
let _wrapper;
function buildToTopButton() {
- const button = document.createElement('a');
- button.className = 'button buttonPrimary pageActionButtonToTop initiallyHidden jsTooltip';
- button.href = '';
- button.title = Language.get('wcf.global.scrollUp');
- button.setAttribute('aria-hidden', 'true');
+ const button = document.createElement("a");
+ button.className = "button buttonPrimary pageActionButtonToTop initiallyHidden jsTooltip";
+ button.href = "";
+ button.title = Language.get("wcf.global.scrollUp");
+ button.setAttribute("aria-hidden", "true");
button.innerHTML = '<span class="icon icon32 fa-angle-up"></span>';
- button.addEventListener('click', scrollToTop);
+ button.addEventListener("click", scrollToTop);
return button;
}
function onScroll() {
- if (document.documentElement.classList.contains('disableScrolling')) {
+ if (document.documentElement.classList.contains("disableScrolling")) {
// Ignore any scroll events that take place while body scrolling is disabled,
// because it messes up the scroll offsets.
return;
return;
}
if (offset >= 300) {
- if (_toTopButton.classList.contains('initiallyHidden')) {
- _toTopButton.classList.remove('initiallyHidden');
+ if (_toTopButton.classList.contains("initiallyHidden")) {
+ _toTopButton.classList.remove("initiallyHidden");
}
- _toTopButton.setAttribute('aria-hidden', 'false');
+ _toTopButton.setAttribute("aria-hidden", "false");
}
else {
- _toTopButton.setAttribute('aria-hidden', 'true');
+ _toTopButton.setAttribute("aria-hidden", "true");
}
renderContainer();
if (_lastPosition !== -1) {
- _wrapper.classList[offset < _lastPosition ? 'remove' : 'add']('scrolledDown');
+ _wrapper.classList[offset < _lastPosition ? "remove" : "add"]("scrolledDown");
}
_lastPosition = offset;
}
function scrollToTop(event) {
event.preventDefault();
- const topAnchor = document.getElementById('top');
- topAnchor.scrollIntoView({ behavior: 'smooth' });
+ const topAnchor = document.getElementById("top");
+ topAnchor.scrollIntoView({ behavior: "smooth" });
}
/**
* Toggles the container's visibility.
*/
function renderContainer() {
- const visibleChild = Array.from(_container.children).find(element => {
- return element.getAttribute('aria-hidden') === 'false';
+ const visibleChild = Array.from(_container.children).find((element) => {
+ return element.getAttribute("aria-hidden") === "false";
});
- _container.classList[visibleChild ? 'add' : 'remove']('active');
+ _container.classList[visibleChild ? "add" : "remove"]("active");
}
/**
* Initializes the page action container.
return;
}
_didInit = true;
- _wrapper = document.createElement('div');
- _wrapper.className = 'pageAction';
- _container = document.createElement('div');
- _container.className = 'pageActionButtons';
+ _wrapper = document.createElement("div");
+ _wrapper.className = "pageAction";
+ _container = document.createElement("div");
+ _container.className = "pageActionButtons";
_wrapper.appendChild(_container);
_toTopButton = buildToTopButton();
_wrapper.appendChild(_toTopButton);
document.body.appendChild(_wrapper);
- window.addEventListener('scroll', Core.debounce(onScroll, 100), { passive: true });
+ window.addEventListener("scroll", Core.debounce(onScroll, 100), { passive: true });
onScroll();
}
exports.setup = setup;
setup();
// The wrapper is required for backwards compatibility, because some implementations rely on a
// dedicated parent element to insert elements, for example, for drop-down menus.
- const wrapper = document.createElement('div');
- wrapper.className = 'pageActionButton';
+ const wrapper = document.createElement("div");
+ wrapper.className = "pageActionButton";
wrapper.dataset.name = buttonName;
- wrapper.setAttribute('aria-hidden', 'true');
- button.classList.add('button');
- button.classList.add('buttonPrimary');
+ wrapper.setAttribute("aria-hidden", "true");
+ button.classList.add("button");
+ button.classList.add("buttonPrimary");
wrapper.appendChild(button);
let insertBefore = null;
if (insertBeforeButton) {
insertBefore = _container.firstChild;
}
_container.insertBefore(wrapper, insertBefore);
- _wrapper.classList.remove('scrolledDown');
+ _wrapper.classList.remove("scrolledDown");
_buttons.set(buttonName, button);
// Query a layout related property to force a reflow, otherwise the transition is optimized away.
// noinspection BadExpressionStatementJS
wrapper.offsetParent;
// Toggle the visibility to force the transition to be applied.
- wrapper.setAttribute('aria-hidden', 'false');
+ wrapper.setAttribute("aria-hidden", "false");
renderContainer();
}
exports.add = add;
const listItem = button.parentElement;
const callback = () => {
try {
- if (Core.stringToBool(listItem.getAttribute('aria-hidden'))) {
+ if (Core.stringToBool(listItem.getAttribute("aria-hidden"))) {
_container.removeChild(listItem);
_buttons.delete(buttonName);
}
- listItem.removeEventListener('transitionend', callback);
+ listItem.removeEventListener("transitionend", callback);
}
catch (e) {
// ignore errors if the element has already been removed
}
};
- listItem.addEventListener('transitionend', callback);
+ listItem.addEventListener("transitionend", callback);
hide(buttonName);
}
}
const button = _buttons.get(buttonName);
if (button) {
const parent = button.parentElement;
- parent.setAttribute('aria-hidden', 'true');
+ parent.setAttribute("aria-hidden", "true");
renderContainer();
}
}
const button = _buttons.get(buttonName);
if (button) {
const parent = button.parentElement;
- if (parent.classList.contains('initiallyHidden')) {
- parent.classList.remove('initiallyHidden');
+ if (parent.classList.contains("initiallyHidden")) {
+ parent.classList.remove("initiallyHidden");
}
- parent.setAttribute('aria-hidden', 'false');
- _wrapper.classList.remove('scrolledDown');
+ parent.setAttribute("aria-hidden", "false");
+ _wrapper.classList.remove("scrolledDown");
renderContainer();
}
}
* Provides the collapsible search bar.
*/
function initSearchBar() {
- _pageHeaderSearch = document.getElementById('pageHeaderSearch');
- _pageHeaderSearch.addEventListener('click', ev => ev.stopPropagation());
- _pageHeaderPanel = document.getElementById('pageHeaderPanel');
- _searchInput = document.getElementById('pageHeaderSearchInput');
- _topMenu = document.getElementById('topMenu');
- _userPanelSearchButton = document.getElementById('userPanelSearchButton');
- _userPanelSearchButton.addEventListener('click', event => {
+ _pageHeaderSearch = document.getElementById("pageHeaderSearch");
+ _pageHeaderSearch.addEventListener("click", (ev) => ev.stopPropagation());
+ _pageHeaderPanel = document.getElementById("pageHeaderPanel");
+ _searchInput = document.getElementById("pageHeaderSearchInput");
+ _topMenu = document.getElementById("topMenu");
+ _userPanelSearchButton = document.getElementById("userPanelSearchButton");
+ _userPanelSearchButton.addEventListener("click", (event) => {
event.preventDefault();
event.stopPropagation();
- if (_pageHeader.classList.contains('searchBarOpen')) {
+ if (_pageHeader.classList.contains("searchBarOpen")) {
closeSearchBar();
}
else {
openSearchBar();
}
});
- CloseOverlay_1.default.add('WoltLabSuite/Core/Ui/Page/Header/Fixed', () => {
- if (_pageHeader.classList.contains('searchBarForceOpen')) {
+ CloseOverlay_1.default.add("WoltLabSuite/Core/Ui/Page/Header/Fixed", () => {
+ if (_pageHeader.classList.contains("searchBarForceOpen")) {
return;
}
closeSearchBar();
});
- EventHandler.add('com.woltlab.wcf.MainMenuMobile', 'more', data => {
- if (data.identifier === 'com.woltlab.wcf.search') {
+ EventHandler.add("com.woltlab.wcf.MainMenuMobile", "more", (data) => {
+ if (data.identifier === "com.woltlab.wcf.search") {
data.handler.close(true);
_userPanelSearchButton.click();
}
*/
function openSearchBar() {
window.WCF.Dropdown.Interactive.Handler.closeAll();
- _pageHeader.classList.add('searchBarOpen');
- _userPanelSearchButton.parentElement.classList.add('open');
+ _pageHeader.classList.add("searchBarOpen");
+ _userPanelSearchButton.parentElement.classList.add("open");
if (!_isMobile) {
// calculate value for `right` on desktop
UiAlignment.set(_pageHeaderSearch, _topMenu, {
- horizontal: 'right',
+ horizontal: "right",
});
}
- _pageHeaderSearch.style.setProperty('top', _pageHeaderPanel.clientHeight + 'px', '');
+ _pageHeaderSearch.style.setProperty("top", _pageHeaderPanel.clientHeight + "px", "");
_searchInput.focus();
window.setTimeout(() => {
_searchInput.selectionStart = _searchInput.selectionEnd = _searchInput.value.length;
* Closes the search bar.
*/
function closeSearchBar() {
- _pageHeader.classList.remove('searchBarOpen');
- _userPanelSearchButton.parentElement.classList.remove('open');
- ['bottom', 'left', 'right', 'top'].forEach(propertyName => {
+ _pageHeader.classList.remove("searchBarOpen");
+ _userPanelSearchButton.parentElement.classList.remove("open");
+ ["bottom", "left", "right", "top"].forEach((propertyName) => {
_pageHeaderSearch.style.removeProperty(propertyName);
});
_searchInput.blur();
// close the scope selection
- const scope = _pageHeaderSearch.querySelector('.pageHeaderSearchType');
+ const scope = _pageHeaderSearch.querySelector(".pageHeaderSearchType");
Simple_1.default.close(scope.id);
}
/**
* Initializes the sticky page header handler.
*/
function init() {
- _pageHeader = document.getElementById('pageHeader');
- _pageHeaderContainer = document.getElementById('pageHeaderContainer');
+ _pageHeader = document.getElementById("pageHeader");
+ _pageHeaderContainer = document.getElementById("pageHeaderContainer");
initSearchBar();
- UiScreen.on('screen-md-down', {
+ UiScreen.on("screen-md-down", {
match() {
_isMobile = true;
},
_isMobile = true;
},
});
- EventHandler.add('com.woltlab.wcf.Search', 'close', closeSearchBar);
+ EventHandler.add("com.woltlab.wcf.Search", "close", closeSearchBar);
}
exports.init = init;
});
// issue results in the next button being shown for a short time. To circumvent this issue,
// we wait a second before showing the obverflow controls in Safari.
// see https://webkit.org/blog/6643/improved-font-loading/
- if (Environment.browser() === 'safari') {
+ if (Environment.browser() === "safari") {
window.setTimeout(rebuildVisibility, 1000);
}
else {
const showItem = _invisibleRight.slice(0, 3).pop();
setMarginLeft(_menu.clientWidth - (showItem.offsetLeft + showItem.clientWidth));
if (_menu.lastElementChild === showItem) {
- _buttonShowNext.classList.remove('active');
+ _buttonShowNext.classList.remove("active");
}
- _buttonShowPrevious.classList.add('active');
+ _buttonShowPrevious.classList.add("active");
}
}
/**
const showItem = _invisibleLeft.slice(-3)[0];
setMarginLeft(showItem.offsetLeft * -1);
if (_menu.firstElementChild === showItem) {
- _buttonShowPrevious.classList.remove('active');
+ _buttonShowPrevious.classList.remove("active");
}
- _buttonShowNext.classList.add('active');
+ _buttonShowNext.classList.add("active");
}
}
/**
*/
function setMarginLeft(offset) {
_marginLeft = Math.min(_marginLeft + offset, 0);
- _firstElement.style.setProperty('margin-left', _marginLeft + 'px', '');
+ _firstElement.style.setProperty("margin-left", _marginLeft + "px", "");
}
/**
* Toggles button overlays and rebuilds the list
}
});
}
- _buttonShowPrevious.classList[(_invisibleLeft.length ? 'add' : 'remove')]('active');
- _buttonShowNext.classList[(_invisibleRight.length ? 'add' : 'remove')]('active');
+ _buttonShowPrevious.classList[_invisibleLeft.length ? "add" : "remove"]("active");
+ _buttonShowNext.classList[_invisibleRight.length ? "add" : "remove"]("active");
}
/**
* Builds the UI and binds the event listeners.
*/
function setupOverflow() {
const menuParent = _menu.parentElement;
- _buttonShowNext = document.createElement('a');
- _buttonShowNext.className = 'mainMenuShowNext';
- _buttonShowNext.href = '#';
+ _buttonShowNext = document.createElement("a");
+ _buttonShowNext.className = "mainMenuShowNext";
+ _buttonShowNext.href = "#";
_buttonShowNext.innerHTML = '<span class="icon icon32 fa-angle-right"></span>';
- _buttonShowNext.setAttribute('aria-hidden', 'true');
- _buttonShowNext.addEventListener('click', showNext);
+ _buttonShowNext.setAttribute("aria-hidden", "true");
+ _buttonShowNext.addEventListener("click", showNext);
menuParent.appendChild(_buttonShowNext);
- _buttonShowPrevious = document.createElement('a');
- _buttonShowPrevious.className = 'mainMenuShowPrevious';
- _buttonShowPrevious.href = '#';
+ _buttonShowPrevious = document.createElement("a");
+ _buttonShowPrevious.className = "mainMenuShowPrevious";
+ _buttonShowPrevious.href = "#";
_buttonShowPrevious.innerHTML = '<span class="icon icon32 fa-angle-left"></span>';
- _buttonShowPrevious.setAttribute('aria-hidden', 'true');
- _buttonShowPrevious.addEventListener('click', showPrevious);
+ _buttonShowPrevious.setAttribute("aria-hidden", "true");
+ _buttonShowPrevious.addEventListener("click", showPrevious);
menuParent.insertBefore(_buttonShowPrevious, menuParent.firstChild);
- _firstElement.addEventListener('transitionend', rebuildVisibility);
- window.addEventListener('resize', () => {
- _firstElement.style.setProperty('margin-left', '0px', '');
+ _firstElement.addEventListener("transitionend", rebuildVisibility);
+ window.addEventListener("resize", () => {
+ _firstElement.style.setProperty("margin-left", "0px", "");
_marginLeft = 0;
rebuildVisibility();
});
* Setups a11y improvements.
*/
function setupA11y() {
- _menu.querySelectorAll('.boxMenuHasChildren').forEach(element => {
- const link = element.querySelector('.boxMenuLink');
- link.setAttribute('aria-haspopup', 'true');
- link.setAttribute('aria-expanded', 'false');
- const showMenuButton = document.createElement('button');
- showMenuButton.className = 'visuallyHidden';
+ _menu.querySelectorAll(".boxMenuHasChildren").forEach((element) => {
+ const link = element.querySelector(".boxMenuLink");
+ link.setAttribute("aria-haspopup", "true");
+ link.setAttribute("aria-expanded", "false");
+ const showMenuButton = document.createElement("button");
+ showMenuButton.className = "visuallyHidden";
showMenuButton.tabIndex = 0;
- showMenuButton.setAttribute('role', 'button');
- showMenuButton.setAttribute('aria-label', Language.get('wcf.global.button.showMenu'));
+ showMenuButton.setAttribute("role", "button");
+ showMenuButton.setAttribute("aria-label", Language.get("wcf.global.button.showMenu"));
element.insertBefore(showMenuButton, link.nextSibling);
let showMenu = false;
- showMenuButton.addEventListener('click', () => {
+ showMenuButton.addEventListener("click", () => {
showMenu = !showMenu;
- link.setAttribute('aria-expanded', showMenu ? 'true' : 'false');
- showMenuButton.setAttribute('aria-label', Language.get(showMenu ? 'wcf.global.button.hideMenu' : 'wcf.global.button.showMenu'));
+ link.setAttribute("aria-expanded", showMenu ? "true" : "false");
+ showMenuButton.setAttribute("aria-label", Language.get(showMenu ? "wcf.global.button.hideMenu" : "wcf.global.button.showMenu"));
});
});
}
* Initializes the main menu overflow handling.
*/
function init() {
- const menu = document.querySelector('.mainMenu .boxMenu');
- const firstElement = (menu && menu.childElementCount) ? menu.children[0] : null;
+ const menu = document.querySelector(".mainMenu .boxMenu");
+ const firstElement = menu && menu.childElementCount ? menu.children[0] : null;
if (firstElement === null) {
throw new Error("Unable to find the main menu.");
}
_menu = menu;
_firstElement = firstElement;
- UiScreen.on('screen-lg', {
+ UiScreen.on("screen-lg", {
match: enable,
unmatch: disable,
setup: setup,
const redirectUrl = element.dataset.link;
if (redirectUrl) {
callback = function (pageNo) {
- window.location.href = redirectUrl.replace(/pageNo=%d/, 'pageNo=' + pageNo);
+ window.location.href = redirectUrl.replace(/pageNo=%d/, "pageNo=" + pageNo);
};
}
else {
- callback = function () {
- };
+ callback = function () { };
}
}
- else if (typeof callback !== 'function') {
+ else if (typeof callback !== "function") {
throw new TypeError("Expected a valid function for parameter 'callback'.");
}
if (!this.elements.has(element)) {
- element.querySelectorAll('.jumpTo').forEach((jumpTo) => {
- jumpTo.addEventListener('click', (ev) => this.click(element, ev));
+ element.querySelectorAll(".jumpTo").forEach((jumpTo) => {
+ jumpTo.addEventListener("click", (ev) => this.click(element, ev));
this.elements.set(element, callback);
});
}
event.preventDefault();
this.activeElement = element;
Dialog_1.default.open(this);
- const pages = element.dataset.pages || '0';
+ const pages = element.dataset.pages || "0";
this.input.value = pages;
this.input.max = pages;
this.input.select();
- this.description.textContent = Language.get('wcf.page.jumpTo.description').replace(/#pages#/, pages);
+ this.description.textContent = Language.get("wcf.page.jumpTo.description").replace(/#pages#/, pages);
}
/**
* Handles changes to the page number input field.
* @param {object} event event object
*/
_keyUp(event) {
- if (event.key === 'Enter' && !this.submitButton.disabled) {
+ if (event.key === "Enter" && !this.submitButton.disabled) {
this.submit();
return;
}
}
_dialogSetup() {
const source = `<dl>
- <dt><label for="jsPaginationPageNo">${Language.get('wcf.page.jumpTo')}</label></dt>
+ <dt><label for="jsPaginationPageNo">${Language.get("wcf.page.jumpTo")}</label></dt>
<dd>
<input type="number" id="jsPaginationPageNo" value="1" min="1" max="1" class="tiny">
<small></small>
</dd>
</dl>
<div class="formSubmit">
- <button class="buttonPrimary">${Language.get('wcf.global.button.submit')}</button>
+ <button class="buttonPrimary">${Language.get("wcf.global.button.submit")}</button>
</div>`;
return {
- id: 'paginationOverlay',
+ id: "paginationOverlay",
options: {
- onSetup: content => {
- this.input = content.querySelector('input');
- this.input.addEventListener('keyup', (ev) => this._keyUp(ev));
- this.description = content.querySelector('small');
- this.submitButton = content.querySelector('button');
- this.submitButton.addEventListener('click', () => this.submit());
+ onSetup: (content) => {
+ this.input = content.querySelector("input");
+ this.input.addEventListener("keyup", (ev) => this._keyUp(ev));
+ this.description = content.querySelector("small");
+ this.submitButton = content.querySelector("button");
+ this.submitButton.addEventListener("click", () => this.submit());
},
- title: Language.get('wcf.global.page.pagination'),
+ title: Language.get("wcf.global.page.pagination"),
},
source: source,
};
Language = tslib_1.__importStar(Language);
DomTraverse = tslib_1.__importStar(DomTraverse);
UiScreen = tslib_1.__importStar(UiScreen);
- const _pageContainer = document.getElementById('pageContainer');
+ const _pageContainer = document.getElementById("pageContainer");
/**
* Which edge of the menu is touched? Empty string
* if no menu is currently touched.
*
* One 'left', 'right' or ''.
*/
- let _androidTouching = '';
+ let _androidTouching = "";
class UiPageMenuAbstract {
constructor(eventIdentifier, elementId, buttonSelector) {
this.activeList = [];
this.enabled = true;
this.items = new Map();
this.removeActiveList = false;
- if (document.body.dataset.template === 'packageInstallationSetup') {
+ if (document.body.dataset.template === "packageInstallationSetup") {
// work-around for WCFSetup on mobile
return;
}
this.menu = document.getElementById(elementId);
const callbackOpen = this.open.bind(this);
this.button = document.querySelector(buttonSelector);
- this.button.addEventListener('click', callbackOpen);
+ this.button.addEventListener("click", callbackOpen);
this.initItems();
this.initHeader();
- EventHandler.add(this.eventIdentifier, 'open', callbackOpen);
- EventHandler.add(this.eventIdentifier, 'close', this.close.bind(this));
- EventHandler.add(this.eventIdentifier, 'updateButtonState', this.updateButtonState.bind(this));
- this.menu.addEventListener('animationend', () => {
- if (!this.menu.classList.contains('open')) {
- this.menu.querySelectorAll('.menuOverlayItemList').forEach(itemList => {
+ EventHandler.add(this.eventIdentifier, "open", callbackOpen);
+ EventHandler.add(this.eventIdentifier, "close", this.close.bind(this));
+ EventHandler.add(this.eventIdentifier, "updateButtonState", this.updateButtonState.bind(this));
+ this.menu.addEventListener("animationend", () => {
+ if (!this.menu.classList.contains("open")) {
+ this.menu.querySelectorAll(".menuOverlayItemList").forEach((itemList) => {
// force the main list to be displayed
- itemList.classList.remove('active', 'hidden');
+ itemList.classList.remove("active", "hidden");
});
}
});
- this.menu.children[0].addEventListener('transitionend', () => {
- this.menu.classList.add('allowScroll');
+ this.menu.children[0].addEventListener("transitionend", () => {
+ this.menu.classList.add("allowScroll");
if (this.removeActiveList) {
this.removeActiveList = false;
const list = this.activeList.pop();
if (list) {
- list.classList.remove('activeList');
+ list.classList.remove("activeList");
}
}
});
- const backdrop = document.createElement('div');
- backdrop.className = 'menuOverlayMobileBackdrop';
- backdrop.addEventListener('click', this.close.bind(this));
- this.menu.insertAdjacentElement('afterend', backdrop);
+ const backdrop = document.createElement("div");
+ backdrop.className = "menuOverlayMobileBackdrop";
+ backdrop.addEventListener("click", this.close.bind(this));
+ this.menu.insertAdjacentElement("afterend", backdrop);
this.menu.parentElement.insertBefore(backdrop, this.menu.nextSibling);
this.updateButtonState();
- if (Environment.platform() === 'android') {
+ if (Environment.platform() === "android") {
this.initializeAndroid();
}
}
if (event instanceof Event) {
event.preventDefault();
}
- this.menu.classList.add('open');
- this.menu.classList.add('allowScroll');
- this.menu.children[0].classList.add('activeList');
+ this.menu.classList.add("open");
+ this.menu.classList.add("allowScroll");
+ this.menu.children[0].classList.add("activeList");
UiScreen.scrollDisable();
- _pageContainer.classList.add('menuOverlay-' + this.menu.id);
+ _pageContainer.classList.add("menuOverlay-" + this.menu.id);
UiScreen.pageOverlayOpen();
return true;
}
if (event instanceof Event) {
event.preventDefault();
}
- if (this.menu.classList.contains('open')) {
- this.menu.classList.remove('open');
+ if (this.menu.classList.contains("open")) {
+ this.menu.classList.remove("open");
UiScreen.scrollEnable();
UiScreen.pageOverlayClose();
- _pageContainer.classList.remove('menuOverlay-' + this.menu.id);
+ _pageContainer.classList.remove("menuOverlay-" + this.menu.id);
return true;
}
return false;
// specify on which side of the page the menu appears
let appearsAt;
switch (this.menu.id) {
- case 'pageUserMenuMobile':
- appearsAt = 'right';
+ case "pageUserMenuMobile":
+ appearsAt = "right";
break;
- case 'pageMainMenuMobile':
- appearsAt = 'left';
+ case "pageMainMenuMobile":
+ appearsAt = "left";
break;
default:
return;
const backdrop = this.menu.nextElementSibling;
// horizontal position of the touch start
let touchStart = undefined;
- document.addEventListener('touchstart', event => {
+ document.addEventListener("touchstart", (event) => {
const touches = event.touches;
let isLeftEdge;
let isRightEdge;
- const isOpen = this.menu.classList.contains('open');
+ const isOpen = this.menu.classList.contains("open");
// check whether we touch the edges of the menu
- if (appearsAt === 'left') {
- isLeftEdge = !isOpen && (touches[0].clientX < 20 /* AtEdge */);
- isRightEdge = isOpen && (Math.abs(this.menu.offsetWidth - touches[0].clientX) < 20 /* AtEdge */);
+ if (appearsAt === "left") {
+ isLeftEdge = !isOpen && touches[0].clientX < 20 /* AtEdge */;
+ isRightEdge = isOpen && Math.abs(this.menu.offsetWidth - touches[0].clientX) < 20 /* AtEdge */;
}
else {
- isLeftEdge = isOpen && (Math.abs(document.body.clientWidth - this.menu.offsetWidth - touches[0].clientX) < 20 /* AtEdge */);
- isRightEdge = !isOpen && ((document.body.clientWidth - touches[0].clientX) < 20 /* AtEdge */);
+ isLeftEdge =
+ isOpen &&
+ Math.abs(document.body.clientWidth - this.menu.offsetWidth - touches[0].clientX) < 20 /* AtEdge */;
+ isRightEdge = !isOpen && document.body.clientWidth - touches[0].clientX < 20 /* AtEdge */;
}
// abort if more than one touch
if (touches.length > 1) {
if (_androidTouching) {
- Core.triggerEvent(document, 'touchend');
+ Core.triggerEvent(document, "touchend");
}
return;
}
}
}
// break if redactor is in use
- if (document.documentElement.classList.contains('redactorActive')) {
+ if (document.documentElement.classList.contains("redactorActive")) {
return;
}
touchStart = {
y: touches[0].clientY,
};
if (isLeftEdge)
- _androidTouching = 'left';
+ _androidTouching = "left";
if (isRightEdge)
- _androidTouching = 'right';
+ _androidTouching = "right";
});
- document.addEventListener('touchend', event => {
+ document.addEventListener("touchend", (event) => {
// break if we did not start a touch
if (!_androidTouching || !touchStart) {
return;
}
// break if the menu did not even start opening
- if (!this.menu.classList.contains('open')) {
+ if (!this.menu.classList.contains("open")) {
// reset
touchStart = undefined;
- _androidTouching = '';
+ _androidTouching = "";
return;
}
// last known position of the finger
position = touchStart.x;
}
// clean up touch styles
- this.menu.classList.add('androidMenuTouchEnd');
- this.menu.style.removeProperty('transform');
+ this.menu.classList.add("androidMenuTouchEnd");
+ this.menu.style.removeProperty("transform");
backdrop.style.removeProperty(appearsAt);
- this.menu.addEventListener('transitionend', () => {
- this.menu.classList.remove('androidMenuTouchEnd');
+ this.menu.addEventListener("transitionend", () => {
+ this.menu.classList.remove("androidMenuTouchEnd");
}, { once: true });
// check whether the user moved the finger far enough
- if (appearsAt === 'left') {
- if (_androidTouching === 'left' && position < (touchStart.x + 100))
+ if (appearsAt === "left") {
+ if (_androidTouching === "left" && position < touchStart.x + 100)
this.close();
- if (_androidTouching === 'right' && position < (touchStart.x - 100))
+ if (_androidTouching === "right" && position < touchStart.x - 100)
this.close();
}
else {
- if (_androidTouching === 'left' && position > (touchStart.x + 100))
+ if (_androidTouching === "left" && position > touchStart.x + 100)
this.close();
- if (_androidTouching === 'right' && position > (touchStart.x - 100))
+ if (_androidTouching === "right" && position > touchStart.x - 100)
this.close();
}
// reset
touchStart = undefined;
- _androidTouching = '';
+ _androidTouching = "";
});
- document.addEventListener('touchmove', event => {
+ document.addEventListener("touchmove", (event) => {
// break if we did not start a touch
if (!_androidTouching || !touchStart) {
return;
// check whether the user started moving in the correct direction
// this avoids false positives, in case the user just wanted to tap
let movedFromEdge = false;
- if (_androidTouching === 'left')
- movedFromEdge = touches[0].clientX > (touchStart.x + 5 /* MovedHorizontally */);
- if (_androidTouching === 'right')
- movedFromEdge = touches[0].clientX < (touchStart.x - 5 /* MovedHorizontally */);
+ if (_androidTouching === "left")
+ movedFromEdge = touches[0].clientX > touchStart.x + 5 /* MovedHorizontally */;
+ if (_androidTouching === "right")
+ movedFromEdge = touches[0].clientX < touchStart.x - 5 /* MovedHorizontally */;
const movedVertically = Math.abs(touches[0].clientY - touchStart.y) > 20 /* MovedVertically */;
- let isOpen = this.menu.classList.contains('open');
+ let isOpen = this.menu.classList.contains("open");
if (!isOpen && movedFromEdge && !movedVertically) {
// the menu is not yet open, but the user moved into the right direction
this.open();
if (isOpen) {
// update CSS to the new finger position
let position = touches[0].clientX;
- if (appearsAt === 'right')
+ if (appearsAt === "right")
position = document.body.clientWidth - position;
if (position > this.menu.offsetWidth)
position = this.menu.offsetWidth;
if (position < 0)
position = 0;
- this.menu.style.setProperty('transform', 'translateX(' + (appearsAt === 'left' ? 1 : -1) * (position - this.menu.offsetWidth) + 'px)');
- backdrop.style.setProperty(appearsAt, Math.min(this.menu.offsetWidth, position) + 'px');
+ this.menu.style.setProperty("transform", "translateX(" + (appearsAt === "left" ? 1 : -1) * (position - this.menu.offsetWidth) + "px)");
+ backdrop.style.setProperty(appearsAt, Math.min(this.menu.offsetWidth, position) + "px");
}
});
}
* Initializes all menu items.
*/
initItems() {
- this.menu.querySelectorAll('.menuOverlayItemLink').forEach((element) => {
+ this.menu.querySelectorAll(".menuOverlayItemLink").forEach((element) => {
this.initItem(element);
});
}
const parent = item.parentElement;
const more = parent.dataset.more;
if (more) {
- item.addEventListener('click', event => {
+ item.addEventListener("click", (event) => {
event.preventDefault();
event.stopPropagation();
- EventHandler.fire(this.eventIdentifier, 'more', {
+ EventHandler.fire(this.eventIdentifier, "more", {
handler: this,
identifier: more,
item: item,
return;
}
// handle static items with an icon-type button next to it (acp menu)
- if (itemList.nodeName !== 'OL' && itemList.classList.contains('menuOverlayItemLinkIcon')) {
+ if (itemList.nodeName !== "OL" && itemList.classList.contains("menuOverlayItemLinkIcon")) {
// add wrapper
- const wrapper = document.createElement('span');
- wrapper.className = 'menuOverlayItemWrapper';
+ const wrapper = document.createElement("span");
+ wrapper.className = "menuOverlayItemWrapper";
parent.insertBefore(wrapper, item);
wrapper.appendChild(item);
while (wrapper.nextElementSibling) {
}
return;
}
- const isLink = item.href !== '#';
+ const isLink = item.href !== "#";
const parentItemList = parent.parentElement;
let itemTitle = itemList.dataset.title;
this.items.set(item, {
parentItemList: parentItemList,
});
if (!itemTitle) {
- itemTitle = DomTraverse.childByClass(item, 'menuOverlayItemTitle').textContent;
+ itemTitle = DomTraverse.childByClass(item, "menuOverlayItemTitle").textContent;
itemList.dataset.title = itemTitle;
}
const callbackLink = this.showItemList.bind(this, item);
if (isLink) {
- const wrapper = document.createElement('span');
- wrapper.className = 'menuOverlayItemWrapper';
+ const wrapper = document.createElement("span");
+ wrapper.className = "menuOverlayItemWrapper";
parent.insertBefore(wrapper, item);
wrapper.appendChild(item);
- const moreLink = document.createElement('a');
- moreLink.href = '#';
- moreLink.className = 'menuOverlayItemLinkIcon' + (item.classList.contains('active') ? ' active' : '');
+ const moreLink = document.createElement("a");
+ moreLink.href = "#";
+ moreLink.className = "menuOverlayItemLinkIcon" + (item.classList.contains("active") ? " active" : "");
moreLink.innerHTML = '<span class="icon icon24 fa-angle-right"></span>';
- moreLink.addEventListener('click', callbackLink);
+ moreLink.addEventListener("click", callbackLink);
wrapper.appendChild(moreLink);
}
else {
- item.classList.add('menuOverlayItemLinkMore');
- item.addEventListener('click', callbackLink);
+ item.classList.add("menuOverlayItemLinkMore");
+ item.addEventListener("click", callbackLink);
}
- const backLinkItem = document.createElement('li');
- backLinkItem.className = 'menuOverlayHeader';
- const wrapper = document.createElement('span');
- wrapper.className = 'menuOverlayItemWrapper';
- const backLink = document.createElement('a');
- backLink.href = '#';
- backLink.className = 'menuOverlayItemLink menuOverlayBackLink';
- backLink.textContent = parentItemList.dataset.title || '';
- backLink.addEventListener('click', this.hideItemList.bind(this, item));
- const closeLink = document.createElement('a');
- closeLink.href = '#';
- closeLink.className = 'menuOverlayItemLinkIcon';
+ const backLinkItem = document.createElement("li");
+ backLinkItem.className = "menuOverlayHeader";
+ const wrapper = document.createElement("span");
+ wrapper.className = "menuOverlayItemWrapper";
+ const backLink = document.createElement("a");
+ backLink.href = "#";
+ backLink.className = "menuOverlayItemLink menuOverlayBackLink";
+ backLink.textContent = parentItemList.dataset.title || "";
+ backLink.addEventListener("click", this.hideItemList.bind(this, item));
+ const closeLink = document.createElement("a");
+ closeLink.href = "#";
+ closeLink.className = "menuOverlayItemLinkIcon";
closeLink.innerHTML = '<span class="icon icon24 fa-times"></span>';
- closeLink.addEventListener('click', this.close.bind(this));
+ closeLink.addEventListener("click", this.close.bind(this));
wrapper.appendChild(backLink);
wrapper.appendChild(closeLink);
backLinkItem.appendChild(wrapper);
itemList.insertBefore(backLinkItem, itemList.firstElementChild);
- if (!backLinkItem.nextElementSibling.classList.contains('menuOverlayTitle')) {
- const titleItem = document.createElement('li');
- titleItem.className = 'menuOverlayTitle';
- const title = document.createElement('span');
+ if (!backLinkItem.nextElementSibling.classList.contains("menuOverlayTitle")) {
+ const titleItem = document.createElement("li");
+ titleItem.className = "menuOverlayTitle";
+ const title = document.createElement("span");
title.textContent = itemTitle;
titleItem.appendChild(title);
itemList.insertBefore(titleItem, backLinkItem.nextElementSibling);
* Renders the menu item list header.
*/
initHeader() {
- const listItem = document.createElement('li');
- listItem.className = 'menuOverlayHeader';
- const wrapper = document.createElement('span');
- wrapper.className = 'menuOverlayItemWrapper';
+ const listItem = document.createElement("li");
+ listItem.className = "menuOverlayHeader";
+ const wrapper = document.createElement("span");
+ wrapper.className = "menuOverlayItemWrapper";
listItem.appendChild(wrapper);
- const logoWrapper = document.createElement('span');
- logoWrapper.className = 'menuOverlayLogoWrapper';
+ const logoWrapper = document.createElement("span");
+ logoWrapper.className = "menuOverlayLogoWrapper";
wrapper.appendChild(logoWrapper);
- const logo = document.createElement('span');
- logo.className = 'menuOverlayLogo';
+ const logo = document.createElement("span");
+ logo.className = "menuOverlayLogo";
const pageLogo = this.menu.dataset.pageLogo;
- logo.style.setProperty('background-image', `url("${pageLogo}")`, '');
+ logo.style.setProperty("background-image", `url("${pageLogo}")`, "");
logoWrapper.appendChild(logo);
- const closeLink = document.createElement('a');
- closeLink.href = '#';
- closeLink.className = 'menuOverlayItemLinkIcon';
+ const closeLink = document.createElement("a");
+ closeLink.href = "#";
+ closeLink.className = "menuOverlayItemLinkIcon";
closeLink.innerHTML = '<span class="icon icon24 fa-times"></span>';
- closeLink.addEventListener('click', this.close.bind(this));
+ closeLink.addEventListener("click", this.close.bind(this));
wrapper.appendChild(closeLink);
- const list = DomTraverse.childByClass(this.menu, 'menuOverlayItemList');
+ const list = DomTraverse.childByClass(this.menu, "menuOverlayItemList");
list.insertBefore(listItem, list.firstElementChild);
}
/**
if (event instanceof Event) {
event.preventDefault();
}
- this.menu.classList.remove('allowScroll');
+ this.menu.classList.remove("allowScroll");
this.removeActiveList = true;
const data = this.items.get(item);
- data.parentItemList.classList.remove('hidden');
+ data.parentItemList.classList.remove("hidden");
this.updateDepth(false);
}
/**
const data = this.items.get(item);
const load = data.itemList.dataset.load;
if (load) {
- if (!Core.stringToBool(item.dataset.loaded || '')) {
+ if (!Core.stringToBool(item.dataset.loaded || "")) {
const target = event.currentTarget;
const icon = target.firstElementChild;
- if (icon.classList.contains('fa-angle-right')) {
- icon.classList.remove('fa-angle-right');
- icon.classList.add('fa-spinner');
+ if (icon.classList.contains("fa-angle-right")) {
+ icon.classList.remove("fa-angle-right");
+ icon.classList.add("fa-spinner");
}
- EventHandler.fire(this.eventIdentifier, 'load_' + load);
+ EventHandler.fire(this.eventIdentifier, "load_" + load);
return;
}
}
- this.menu.classList.remove('allowScroll');
- data.itemList.classList.add('activeList');
- data.parentItemList.classList.add('hidden');
+ this.menu.classList.remove("allowScroll");
+ data.itemList.classList.add("activeList");
+ data.parentItemList.classList.add("hidden");
this.activeList.push(data.itemList);
this.updateDepth(true);
}
updateDepth(increase) {
- this.depth += (increase) ? 1 : -1;
+ this.depth += increase ? 1 : -1;
let offset = this.depth * -100;
- if (Language.get('wcf.global.pageDirection') === 'rtl') {
+ if (Language.get("wcf.global.pageDirection") === "rtl") {
// reverse logic for RTL
offset *= -1;
}
const child = this.menu.children[0];
- child.style.setProperty('transform', `translateX(${offset}%)`, '');
+ child.style.setProperty("transform", `translateX(${offset}%)`, "");
}
updateButtonState() {
let hasNewContent = false;
- const itemList = this.menu.querySelector('.menuOverlayItemList');
- this.menu.querySelectorAll('.badgeUpdate').forEach(badge => {
+ const itemList = this.menu.querySelector(".menuOverlayItemList");
+ this.menu.querySelectorAll(".badgeUpdate").forEach((badge) => {
const value = badge.textContent;
- if (~~value > 0 && badge.closest('.menuOverlayItemList') === itemList) {
+ if (~~value > 0 && badge.closest(".menuOverlayItemList") === itemList) {
hasNewContent = true;
}
});
- this.button.classList[hasNewContent ? 'add' : 'remove']('pageMenuMobileButtonHasContent');
+ this.button.classList[hasNewContent ? "add" : "remove"]("pageMenuMobileButtonHasContent");
}
}
return UiPageMenuAbstract;
const inputContainer = this.searchInput.parentNode;
const value = this.searchInput.value.trim();
if (value.length < 3) {
- Util_1.default.innerError(inputContainer, Language.get('wcf.page.search.error.tooShort'));
+ Util_1.default.innerError(inputContainer, Language.get("wcf.page.search.error.tooShort"));
return;
}
else {
click(event) {
event.preventDefault();
const page = event.currentTarget;
- const pageTitle = page.querySelector('h3');
- this.callbackSelect(page.dataset.pageId + '#' + pageTitle.textContent.replace(/['"]/g, ''));
+ const pageTitle = page.querySelector("h3");
+ this.callbackSelect(page.dataset.pageId + "#" + pageTitle.textContent.replace(/['"]/g, ""));
Dialog_1.default.close(this);
}
_ajaxSuccess(data) {
const html = data.returnValues
- .map(page => {
+ .map((page) => {
const name = StringUtil.escapeHTML(page.name);
const displayLink = StringUtil.escapeHTML(page.displayLink);
return `<li>
</div>
</li>`;
})
- .join('');
+ .join("");
this.resultList.innerHTML = html;
- Util_1.default[html ? 'show' : 'hide'](this.resultContainer);
+ Util_1.default[html ? "show" : "hide"](this.resultContainer);
if (html) {
- this.resultList.querySelectorAll('.containerHeadline').forEach((item) => {
- item.addEventListener('click', (ev) => this.click(ev));
+ this.resultList.querySelectorAll(".containerHeadline").forEach((item) => {
+ item.addEventListener("click", (ev) => this.click(ev));
});
}
else {
- Util_1.default.innerError(this.searchInput.parentElement, Language.get('wcf.page.search.error.noResults'));
+ Util_1.default.innerError(this.searchInput.parentElement, Language.get("wcf.page.search.error.noResults"));
}
}
_ajaxSetup() {
return {
data: {
- actionName: 'search',
- className: 'wcf\\data\\page\\PageAction',
+ actionName: "search",
+ className: "wcf\\data\\page\\PageAction",
},
};
}
_dialogSetup() {
return {
- id: 'wcfUiPageSearch',
+ id: "wcfUiPageSearch",
options: {
onSetup: () => {
- this.searchInput = document.getElementById('wcfUiPageSearchInput');
- this.searchInput.addEventListener('keydown', event => {
- if (event.key === 'Enter') {
+ this.searchInput = document.getElementById("wcfUiPageSearchInput");
+ this.searchInput.addEventListener("keydown", (event) => {
+ if (event.key === "Enter") {
this.search(event);
}
});
- this.searchInput.nextElementSibling.addEventListener('click', (ev) => this.search(ev));
- this.resultContainer = document.getElementById('wcfUiPageSearchResultContainer');
- this.resultList = document.getElementById('wcfUiPageSearchResultList');
+ this.searchInput.nextElementSibling.addEventListener("click", (ev) => this.search(ev));
+ this.resultContainer = document.getElementById("wcfUiPageSearchResultContainer");
+ this.resultList = document.getElementById("wcfUiPageSearchResultList");
},
onShow: () => {
this.searchInput.focus();
},
- title: Language.get('wcf.page.search'),
+ title: Language.get("wcf.page.search"),
},
source: `<div class="section">
<dl>
- <dt><label for="wcfUiPageSearchInput">${Language.get('wcf.page.search.name')}</label></dt>
+ <dt><label for="wcfUiPageSearchInput">${Language.get("wcf.page.search.name")}</label></dt>
<dd>
<div class="inputAddon">
<input type="text" id="wcfUiPageSearchInput" class="long">
</div>
<section id="wcfUiPageSearchResultContainer" class="section" style="display: none;">
<header class="sectionHeader">
- <h2 class="sectionTitle">${Language.get('wcf.page.search.results')}</h2>
+ <h2 class="sectionTitle">${Language.get("wcf.page.search.results")}</h2>
</header>
<ol id="wcfUiPageSearchResultList" class="containerList"></ol>
</section>`,
this.callbackSuccess = callback;
Dialog_1.default.open(this);
Dialog_1.default.setTitle(this, title);
- this.searchInputLabel.textContent = Language.get(labelLanguageItem || 'wcf.page.pageObjectID.search.terms');
+ this.searchInputLabel.textContent = Language.get(labelLanguageItem || "wcf.page.pageObjectID.search.terms");
this._getSearchInputHandler().setPageId(pageId);
}
/**
buildList(data) {
this.resetList();
if (!Array.isArray(data.returnValues) || data.returnValues.length === 0) {
- Util_1.default.innerError(this.searchInput, Language.get('wcf.page.pageObjectID.search.noResults'));
+ Util_1.default.innerError(this.searchInput, Language.get("wcf.page.pageObjectID.search.noResults"));
return;
}
- data.returnValues.forEach(item => {
+ data.returnValues.forEach((item) => {
let image = item.image;
if (/^fa-/.test(image)) {
- image = `<span class="icon icon48 ${image} pointer jsTooltip" title="${Language.get('wcf.global.select')}"></span>`;
+ image = `<span class="icon icon48 ${image} pointer jsTooltip" title="${Language.get("wcf.global.select")}"></span>`;
}
- const listItem = document.createElement('li');
+ const listItem = document.createElement("li");
listItem.dataset.objectId = item.objectID.toString();
- const description = item.description ? `<p>${item.description}</p>` : '';
+ const description = item.description ? `<p>${item.description}</p>` : "";
listItem.innerHTML = `<div class="box48">
${image}
<div>
</div>
</div>
</div>`;
- listItem.addEventListener('click', this.click.bind(this));
+ listItem.addEventListener("click", this.click.bind(this));
this.resultList.appendChild(listItem);
});
Util_1.default.show(this.resultListContainer);
*/
resetList() {
Util_1.default.innerError(this.searchInput, false);
- this.resultList.innerHTML = '';
+ this.resultList.innerHTML = "";
Util_1.default.hide(this.resultListContainer);
}
/**
*/
_getSearchInputHandler() {
if (!this.searchInputHandler) {
- const input = document.getElementById('wcfUiPageSearchInput');
+ const input = document.getElementById("wcfUiPageSearchInput");
this.searchInputHandler = new Input_1.default(input, {
callbackSuccess: this.buildList.bind(this),
});
*/
click(event) {
const clickTarget = event.target;
- if (clickTarget.nodeName === 'A') {
+ if (clickTarget.nodeName === "A") {
return;
}
event.stopPropagation();
}
_dialogSetup() {
return {
- id: 'wcfUiPageSearchHandler',
+ id: "wcfUiPageSearchHandler",
options: {
onShow: (content) => {
if (!this.searchInput) {
- this.searchInput = document.getElementById('wcfUiPageSearchInput');
+ this.searchInput = document.getElementById("wcfUiPageSearchInput");
this.searchInputLabel = content.querySelector('label[for="wcfUiPageSearchInput"]');
- this.resultList = document.getElementById('wcfUiPageSearchResultList');
- this.resultListContainer = document.getElementById('wcfUiPageSearchResultListContainer');
+ this.resultList = document.getElementById("wcfUiPageSearchResultList");
+ this.resultListContainer = document.getElementById("wcfUiPageSearchResultListContainer");
}
// clear search input
- this.searchInput.value = '';
+ this.searchInput.value = "";
// reset results
Util_1.default.hide(this.resultListContainer);
- this.resultList.innerHTML = '';
+ this.resultList.innerHTML = "";
this.searchInput.focus();
},
- title: '',
+ title: "",
},
source: `<div class="section">
<dl>
<dt>
- <label for="wcfUiPageSearchInput">${Language.get('wcf.page.pageObjectID.search.terms')}</label>
+ <label for="wcfUiPageSearchInput">${Language.get("wcf.page.pageObjectID.search.terms")}</label>
</dt>
<dd>
<input type="text" id="wcfUiPageSearchInput" class="long">
</div>
<section id="wcfUiPageSearchResultListContainer" class="section sectionContainerList">
<header class="sectionHeader">
- <h2 class="sectionTitle">${Language.get('wcf.page.pageObjectID.search.results')}</h2>
+ <h2 class="sectionTitle">${Language.get("wcf.page.pageObjectID.search.results")}</h2>
</header>
<ul id="wcfUiPageSearchResultList" class="containerList wcfUiPageSearchResultList"></ul>
</section>`,
Input_1 = tslib_1.__importDefault(Input_1);
class UiPageSearchInput extends Input_1.default {
constructor(element, options) {
- if (typeof options.callbackSuccess !== 'function') {
+ if (typeof options.callbackSuccess !== "function") {
throw new Error("Expected a valid callback function for 'callbackSuccess'.");
}
options = Core.extend({
ajax: {
- className: 'wcf\\data\\page\\PageAction',
+ className: "wcf\\data\\page\\PageAction",
},
}, options);
super(element, options);
this.element = element;
this.activePage = options.activePage;
this.maxPage = options.maxPage;
- if (typeof options.callbackSwitch === 'function') {
+ if (typeof options.callbackSwitch === "function") {
this.callbackSwitch = options.callbackSwitch;
}
- if (typeof options.callbackShouldSwitch === 'function') {
+ if (typeof options.callbackShouldSwitch === "function") {
this.callbackShouldSwitch = options.callbackShouldSwitch;
}
- this.element.classList.add('pagination');
+ this.element.classList.add("pagination");
this.rebuild();
}
/**
rebuild() {
let hasHiddenPages = false;
// clear content
- this.element.innerHTML = '';
- const list = document.createElement('ul');
- let listItem = document.createElement('li');
- listItem.className = 'skip';
+ this.element.innerHTML = "";
+ const list = document.createElement("ul");
+ let listItem = document.createElement("li");
+ listItem.className = "skip";
list.appendChild(listItem);
- let iconClassNames = 'icon icon24 fa-chevron-left';
+ let iconClassNames = "icon icon24 fa-chevron-left";
if (this.activePage > 1) {
- const link = document.createElement('a');
- link.className = iconClassNames + ' jsTooltip';
- link.href = '#';
- link.title = Language.get('wcf.global.page.previous');
- link.rel = 'prev';
+ const link = document.createElement("a");
+ link.className = iconClassNames + " jsTooltip";
+ link.href = "#";
+ link.title = Language.get("wcf.global.page.previous");
+ link.rel = "prev";
listItem.appendChild(link);
- link.addEventListener('click', (ev) => this.switchPage(this.activePage - 1, ev));
+ link.addEventListener("click", (ev) => this.switchPage(this.activePage - 1, ev));
}
else {
listItem.innerHTML = '<span class="' + iconClassNames + '"></span>';
- listItem.classList.add('disabled');
+ listItem.classList.add("disabled");
}
// add first page
list.appendChild(this.createLink(1));
right = this.maxPage;
}
// left ... links
- const jumpToHtml = '<a class="jsTooltip" title="' + Language.get('wcf.page.jumpTo') + '">…</a>';
+ const jumpToHtml = '<a class="jsTooltip" title="' + Language.get("wcf.page.jumpTo") + '">…</a>';
if (left > 1) {
if (left - 1 < 2) {
list.appendChild(this.createLink(2));
}
else {
- listItem = document.createElement('li');
- listItem.className = 'jumpTo';
+ listItem = document.createElement("li");
+ listItem.className = "jumpTo";
listItem.innerHTML = jumpToHtml;
list.appendChild(listItem);
hasHiddenPages = true;
list.appendChild(this.createLink(this.maxPage - 1));
}
else {
- listItem = document.createElement('li');
- listItem.className = 'jumpTo';
+ listItem = document.createElement("li");
+ listItem.className = "jumpTo";
listItem.innerHTML = jumpToHtml;
list.appendChild(listItem);
hasHiddenPages = true;
// add last page
list.appendChild(this.createLink(this.maxPage));
// add next button
- listItem = document.createElement('li');
- listItem.className = 'skip';
+ listItem = document.createElement("li");
+ listItem.className = "skip";
list.appendChild(listItem);
- iconClassNames = 'icon icon24 fa-chevron-right';
+ iconClassNames = "icon icon24 fa-chevron-right";
if (this.activePage < this.maxPage) {
- const link = document.createElement('a');
- link.className = iconClassNames + ' jsTooltip';
- link.href = '#';
- link.title = Language.get('wcf.global.page.next');
- link.rel = 'next';
+ const link = document.createElement("a");
+ link.className = iconClassNames + " jsTooltip";
+ link.href = "#";
+ link.title = Language.get("wcf.global.page.next");
+ link.rel = "next";
listItem.appendChild(link);
- link.addEventListener('click', (ev) => this.switchPage(this.activePage + 1, ev));
+ link.addEventListener("click", (ev) => this.switchPage(this.activePage + 1, ev));
}
else {
listItem.innerHTML = '<span class="' + iconClassNames + '"></span>';
- listItem.classList.add('disabled');
+ listItem.classList.add("disabled");
}
if (hasHiddenPages) {
list.dataset.pages = this.maxPage.toString();
* Creates a link to a specific page.
*/
createLink(pageNo) {
- const listItem = document.createElement('li');
+ const listItem = document.createElement("li");
if (pageNo !== this.activePage) {
- const link = document.createElement('a');
+ const link = document.createElement("a");
link.textContent = StringUtil.addThousandsSeparator(pageNo);
- link.addEventListener('click', (ev) => this.switchPage(pageNo, ev));
+ link.addEventListener("click", (ev) => this.switchPage(pageNo, ev));
listItem.appendChild(link);
}
else {
- listItem.classList.add('active');
- listItem.innerHTML = '<span>' + StringUtil.addThousandsSeparator(pageNo) + '</span><span class="invisible">' + Language.get('wcf.page.pagePosition', {
- pageNo: pageNo,
- pages: this.maxPage,
- }) + '</span>';
+ listItem.classList.add("active");
+ listItem.innerHTML =
+ "<span>" +
+ StringUtil.addThousandsSeparator(pageNo) +
+ '</span><span class="invisible">' +
+ Language.get("wcf.page.pagePosition", {
+ pageNo: pageNo,
+ pages: this.maxPage,
+ }) +
+ "</span>";
}
return listItem;
}
const target = event.currentTarget;
// force tooltip to vanish and strip positioning
if (target && target.dataset.tooltip) {
- const tooltip = document.getElementById('balloonTooltip');
+ const tooltip = document.getElementById("balloonTooltip");
if (tooltip) {
- Core.triggerEvent(target, 'mouseleave');
- tooltip.style.removeProperty('top');
- tooltip.style.removeProperty('bottom');
+ Core.triggerEvent(target, "mouseleave");
+ tooltip.style.removeProperty("top");
+ tooltip.style.removeProperty("bottom");
}
}
}
let _scrollTop = 0;
let _pageOverlayCounter = 0;
const _mqMap = new Map(Object.entries({
- 'screen-xs': '(max-width: 544px)',
- 'screen-sm': '(min-width: 545px) and (max-width: 768px)',
- 'screen-sm-down': '(max-width: 768px)',
- 'screen-sm-up': '(min-width: 545px)',
- 'screen-sm-md': '(min-width: 545px) and (max-width: 1024px)',
- 'screen-md': '(min-width: 769px) and (max-width: 1024px)',
- 'screen-md-down': '(max-width: 1024px)',
- 'screen-md-up': '(min-width: 769px)',
- 'screen-lg': '(min-width: 1025px)',
- 'screen-lg-only': '(min-width: 1025px) and (max-width: 1280px)',
- 'screen-lg-down': '(max-width: 1280px)',
- 'screen-xl': '(min-width: 1281px)',
+ "screen-xs": "(max-width: 544px)" /* smartphone */,
+ "screen-sm": "(min-width: 545px) and (max-width: 768px)" /* tablet (portrait) */,
+ "screen-sm-down": "(max-width: 768px)" /* smartphone + tablet (portrait) */,
+ "screen-sm-up": "(min-width: 545px)" /* tablet (portrait) + tablet (landscape) + desktop */,
+ "screen-sm-md": "(min-width: 545px) and (max-width: 1024px)" /* tablet (portrait) + tablet (landscape) */,
+ "screen-md": "(min-width: 769px) and (max-width: 1024px)" /* tablet (landscape) */,
+ "screen-md-down": "(max-width: 1024px)" /* smartphone + tablet (portrait) + tablet (landscape) */,
+ "screen-md-up": "(min-width: 769px)" /* tablet (landscape) + desktop */,
+ "screen-lg": "(min-width: 1025px)" /* desktop */,
+ "screen-lg-only": "(min-width: 1025px) and (max-width: 1280px)",
+ "screen-lg-down": "(max-width: 1280px)",
+ "screen-xl": "(min-width: 1281px)",
}));
// Microsoft Edge rewrites the media queries to whatever it
// pleases, causing the input and output query to mismatch
*/
function on(query, callbacks) {
const uuid = Core.getUuid(), queryObject = _getQueryObject(query);
- if (typeof callbacks.match === 'function') {
+ if (typeof callbacks.match === "function") {
queryObject.callbacksMatch.set(uuid, callbacks.match);
}
- if (typeof callbacks.unmatch === 'function') {
+ if (typeof callbacks.unmatch === "function") {
queryObject.callbacksUnmatch.set(uuid, callbacks.unmatch);
}
- if (typeof callbacks.setup === 'function') {
+ if (typeof callbacks.setup === "function") {
if (queryObject.mql.matches) {
callbacks.setup();
}
function scrollDisable() {
if (_scrollDisableCounter === 0) {
_scrollTop = document.body.scrollTop;
- _scrollOffsetFrom = 'body';
+ _scrollOffsetFrom = "body";
if (!_scrollTop) {
_scrollTop = document.documentElement.scrollTop;
- _scrollOffsetFrom = 'documentElement';
+ _scrollOffsetFrom = "documentElement";
}
- const pageContainer = document.getElementById('pageContainer');
+ const pageContainer = document.getElementById("pageContainer");
// setting translateY causes Mobile Safari to snap
- if (Environment.platform() === 'ios') {
- pageContainer.style.setProperty('position', 'relative', '');
- pageContainer.style.setProperty('top', '-' + _scrollTop + 'px', '');
+ if (Environment.platform() === "ios") {
+ pageContainer.style.setProperty("position", "relative", "");
+ pageContainer.style.setProperty("top", "-" + _scrollTop + "px", "");
}
else {
- pageContainer.style.setProperty('margin-top', '-' + _scrollTop + 'px', '');
+ pageContainer.style.setProperty("margin-top", "-" + _scrollTop + "px", "");
}
- document.documentElement.classList.add('disableScrolling');
+ document.documentElement.classList.add("disableScrolling");
}
_scrollDisableCounter++;
}
if (_scrollDisableCounter) {
_scrollDisableCounter--;
if (_scrollDisableCounter === 0) {
- document.documentElement.classList.remove('disableScrolling');
- const pageContainer = document.getElementById('pageContainer');
- if (Environment.platform() === 'ios') {
- pageContainer.style.removeProperty('position');
- pageContainer.style.removeProperty('top');
+ document.documentElement.classList.remove("disableScrolling");
+ const pageContainer = document.getElementById("pageContainer");
+ if (Environment.platform() === "ios") {
+ pageContainer.style.removeProperty("position");
+ pageContainer.style.removeProperty("top");
}
else {
- pageContainer.style.removeProperty('margin-top');
+ pageContainer.style.removeProperty("margin-top");
}
if (_scrollTop) {
document[_scrollOffsetFrom].scrollTop = ~~_scrollTop;
*/
function pageOverlayOpen() {
if (_pageOverlayCounter === 0) {
- document.documentElement.classList.add('pageOverlayActive');
+ document.documentElement.classList.add("pageOverlayActive");
}
_pageOverlayCounter++;
}
if (_pageOverlayCounter) {
_pageOverlayCounter--;
if (_pageOverlayCounter === 0) {
- document.documentElement.classList.remove('pageOverlayActive');
+ document.documentElement.classList.remove("pageOverlayActive");
}
}
}
}
exports.setDialogContainer = setDialogContainer;
function _getQueryObject(query) {
- if (typeof query !== 'string' || query.trim() === '') {
- throw new TypeError('Expected a non-empty string for parameter \'query\'.');
+ if (typeof query !== "string" || query.trim() === "") {
+ throw new TypeError("Expected a non-empty string for parameter 'query'.");
}
// Microsoft Edge rewrites the media queries to whatever it
// pleases, causing the input and output query to mismatch
if (_callback !== null) {
_callback();
}
- window.removeEventListener('scroll', onScroll);
+ window.removeEventListener("scroll", onScroll);
_callback = null;
_timeoutScroll = null;
}, 100);
if (!(element instanceof HTMLElement)) {
throw new TypeError("Expected a valid DOM element.");
}
- else if (callback !== undefined && typeof callback !== 'function') {
+ else if (callback !== undefined && typeof callback !== "function") {
throw new TypeError("Expected a valid callback function.");
}
else if (!document.body.contains(element)) {
}
if (callback) {
_callback = callback;
- window.addEventListener('scroll', onScroll);
+ window.addEventListener("scroll", onScroll);
}
let y = Util_1.default.offset(element).top;
if (_offset === null) {
_offset = 50;
- const pageHeader = document.getElementById('pageHeaderPanel');
+ const pageHeader = document.getElementById("pageHeaderPanel");
if (pageHeader !== null) {
const position = window.getComputedStyle(pageHeader).position;
- if (position === 'fixed' || position === 'static') {
+ if (position === "fixed" || position === "static") {
_offset = pageHeader.offsetHeight;
}
else {
window.scrollTo({
left: 0,
top: y,
- behavior: 'smooth',
+ behavior: "smooth",
});
window.setTimeout(() => {
// no scrolling took place
this.activeItem = undefined;
this.callbackDropdownInit = undefined;
this.callbackSelect = undefined;
- this.dropdownContainerId = '';
+ this.dropdownContainerId = "";
this.excludedSearchValues = new Set();
this.list = undefined;
- this.lastValue = '';
+ this.lastValue = "";
this.request = undefined;
this.timerDelay = undefined;
this.element = element;
if (!(this.element instanceof HTMLInputElement)) {
throw new TypeError("Expected a valid DOM element.");
}
- else if (this.element.nodeName !== 'INPUT' || (this.element.type !== 'search' && this.element.type !== 'text')) {
+ else if (this.element.nodeName !== "INPUT" || (this.element.type !== "search" && this.element.type !== "text")) {
throw new Error('Expected an input[type="text"].');
}
options = Core.extend({
ajax: {
- actionName: 'getSearchResultList',
- className: '',
- interfaceName: 'wcf\\data\\ISearchAction',
+ actionName: "getSearchResultList",
+ className: "",
+ interfaceName: "wcf\\data\\ISearchAction",
},
autoFocus: true,
callbackDropdownInit: undefined,
delay: 500,
excludedSearchValues: [],
minLength: 3,
- noResultPlaceholder: '',
+ noResultPlaceholder: "",
preventSubmit: false,
}, options);
this.ajaxPayload = options.ajax;
this.callbackDropdownInit = options.callbackDropdownInit;
this.callbackSelect = options.callbackSelect;
this.delay = options.delay;
- options.excludedSearchValues.forEach(value => {
+ options.excludedSearchValues.forEach((value) => {
this.addExcludedSearchValues(value);
});
this.minLength = options.minLength;
this.noResultPlaceholder = options.noResultPlaceholder;
this.preventSubmit = options.preventSubmit;
// Disable auto-complete because it collides with the suggestion dropdown.
- this.element.autocomplete = 'off';
- this.element.addEventListener('keydown', (ev) => this.keydown(ev));
- this.element.addEventListener('keyup', (ev) => this.keyup(ev));
+ this.element.autocomplete = "off";
+ this.element.addEventListener("keydown", (ev) => this.keydown(ev));
+ this.element.addEventListener("keyup", (ev) => this.keyup(ev));
}
/**
* Adds an excluded search value.
*/
keydown(event) {
if ((this.activeItem !== null && Simple_1.default.isOpen(this.dropdownContainerId)) || this.preventSubmit) {
- if (event.key === 'Enter') {
+ if (event.key === "Enter") {
event.preventDefault();
}
}
- if (['ArrowUp', 'ArrowDown', 'Escape'].includes(event.key)) {
+ if (["ArrowUp", "ArrowDown", "Escape"].includes(event.key)) {
event.preventDefault();
}
}
// handle dropdown keyboard navigation
if (this.activeItem !== null || !this.autoFocus) {
if (Simple_1.default.isOpen(this.dropdownContainerId)) {
- if (event.key === 'ArrowUp') {
+ if (event.key === "ArrowUp") {
event.preventDefault();
return this.keyboardPreviousItem();
}
- else if (event.key === 'ArrowDown') {
+ else if (event.key === "ArrowDown") {
event.preventDefault();
return this.keyboardNextItem();
}
- else if (event.key === 'Enter') {
+ else if (event.key === "Enter") {
event.preventDefault();
return this.keyboardSelectItem();
}
}
}
// close list on escape
- if (event.key === 'Escape') {
+ if (event.key === "Escape") {
Simple_1.default.close(this.dropdownContainerId);
return;
}
keyboardNextItem() {
let nextItem = undefined;
if (this.activeItem) {
- this.activeItem.classList.remove('active');
+ this.activeItem.classList.remove("active");
if (this.activeItem.nextElementSibling) {
nextItem = this.activeItem.nextElementSibling;
}
}
this.activeItem = nextItem || this.list.children[0];
- this.activeItem.classList.add('active');
+ this.activeItem.classList.add("active");
}
/**
* Selects the previous dropdown item.
keyboardPreviousItem() {
let nextItem = undefined;
if (this.activeItem) {
- this.activeItem.classList.remove('active');
+ this.activeItem.classList.remove("active");
if (this.activeItem.previousElementSibling) {
nextItem = this.activeItem.previousElementSibling;
}
}
this.activeItem = nextItem || this.list.children[this.list.childElementCount - 1];
- this.activeItem.classList.add('active');
+ this.activeItem.classList.add("active");
}
/**
* Selects the active item from the dropdown.
*/
selectItem(item) {
if (this.callbackSelect && !this.callbackSelect(item)) {
- this.element.value = '';
+ this.element.value = "";
}
else {
- this.element.value = item.dataset.label || '';
+ this.element.value = item.dataset.label || "";
}
this.activeItem = undefined;
Simple_1.default.close(this.dropdownContainerId);
_ajaxSuccess(data) {
let createdList = false;
if (!this.list) {
- this.list = document.createElement('ul');
- this.list.className = 'dropdownMenu';
+ this.list = document.createElement("ul");
+ this.list.className = "dropdownMenu";
createdList = true;
- if (typeof this.callbackDropdownInit === 'function') {
+ if (typeof this.callbackDropdownInit === "function") {
this.callbackDropdownInit(this.list);
}
}
else {
// reset current list
- this.list.innerHTML = '';
+ this.list.innerHTML = "";
}
- if (typeof data.returnValues === 'object') {
+ if (typeof data.returnValues === "object") {
const callbackClick = this.clickSelectItem.bind(this);
let listItem;
- Object.keys(data.returnValues).forEach(key => {
+ Object.keys(data.returnValues).forEach((key) => {
listItem = this.createListItem(data.returnValues[key]);
- listItem.addEventListener('click', callbackClick);
+ listItem.addEventListener("click", callbackClick);
this.list.appendChild(listItem);
});
}
Simple_1.default.open(this.dropdownContainerId, true);
// mark first item as active
const firstChild = this.list.childElementCount ? this.list.children[0] : undefined;
- if (this.autoFocus && firstChild && ~~(firstChild.dataset.objectId || '')) {
+ if (this.autoFocus && firstChild && ~~(firstChild.dataset.objectId || "")) {
this.activeItem = firstChild;
- this.activeItem.classList.add('active');
+ this.activeItem.classList.add("active");
}
}
}
if (!this.noResultPlaceholder) {
return false;
}
- const listItem = document.createElement('li');
- listItem.className = 'dropdownText';
- const span = document.createElement('span');
+ const listItem = document.createElement("li");
+ listItem.className = "dropdownText";
+ const span = document.createElement("span");
span.textContent = this.noResultPlaceholder;
listItem.appendChild(span);
this.list.appendChild(listItem);
* Creates an list item from response data.
*/
createListItem(item) {
- const listItem = document.createElement('li');
+ const listItem = document.createElement("li");
listItem.dataset.objectId = item.objectID.toString();
listItem.dataset.label = item.label;
- const span = document.createElement('span');
+ const span = document.createElement("span");
span.textContent = item.label;
listItem.appendChild(span);
return listItem;
Input_1 = tslib_1.__importDefault(Input_1);
function click(event) {
event.preventDefault();
- const pageHeader = document.getElementById('pageHeader');
- pageHeader.classList.add('searchBarForceOpen');
+ const pageHeader = document.getElementById("pageHeader");
+ pageHeader.classList.add("searchBarForceOpen");
window.setTimeout(() => {
- pageHeader.classList.remove('searchBarForceOpen');
+ pageHeader.classList.remove("searchBarForceOpen");
}, 10);
const target = event.currentTarget;
const objectType = target.dataset.objectType;
- const container = document.getElementById('pageHeaderSearchParameters');
- container.innerHTML = '';
+ const container = document.getElementById("pageHeaderSearchParameters");
+ container.innerHTML = "";
const extendedLink = target.dataset.extendedLink;
if (extendedLink) {
- const link = document.querySelector('.pageHeaderSearchExtendedLink');
+ const link = document.querySelector(".pageHeaderSearchExtendedLink");
link.href = extendedLink;
}
const parameters = new Map();
try {
- const data = JSON.parse(target.dataset.parameters || '');
+ const data = JSON.parse(target.dataset.parameters || "");
if (Core.isPlainObject(data)) {
- Object.keys(data).forEach(key => {
+ Object.keys(data).forEach((key) => {
parameters.set(key, data[key]);
});
}
}
- catch (e) {
- }
+ catch (e) { }
if (objectType) {
- parameters.set('types[]', objectType);
+ parameters.set("types[]", objectType);
}
parameters.forEach((value, key) => {
- const input = document.createElement('input');
- input.type = 'hidden';
+ const input = document.createElement("input");
+ input.type = "hidden";
input.name = key;
input.value = value;
container.appendChild(input);
});
// update label
- const inputContainer = document.getElementById('pageHeaderSearchInputContainer');
- const button = inputContainer.querySelector('.pageHeaderSearchType > .button > .pageHeaderSearchTypeLabel');
+ const inputContainer = document.getElementById("pageHeaderSearchInputContainer");
+ const button = inputContainer.querySelector(".pageHeaderSearchType > .button > .pageHeaderSearchTypeLabel");
button.textContent = target.textContent;
}
function init(objectType) {
- const searchInput = document.getElementById('pageHeaderSearchInput');
+ const searchInput = document.getElementById("pageHeaderSearchInput");
new Input_1.default(searchInput, {
ajax: {
- className: 'wcf\\data\\search\\keyword\\SearchKeywordAction',
+ className: "wcf\\data\\search\\keyword\\SearchKeywordAction",
},
autoFocus: false,
callbackDropdownInit(dropdownMenu) {
- dropdownMenu.classList.add('dropdownMenuPageSearch');
- if (UiScreen.is('screen-lg')) {
- dropdownMenu.dataset.dropdownAlignmentHorizontal = 'right';
+ dropdownMenu.classList.add("dropdownMenuPageSearch");
+ if (UiScreen.is("screen-lg")) {
+ dropdownMenu.dataset.dropdownAlignmentHorizontal = "right";
const minWidth = searchInput.clientWidth;
- dropdownMenu.style.setProperty('min-width', minWidth + 'px', '');
+ dropdownMenu.style.setProperty("min-width", minWidth + "px", "");
// calculate offset to ignore the width caused by the submit button
const parent = searchInput.parentElement;
- const offsetRight = (Util_1.default.offset(parent).left + parent.clientWidth) - (Util_1.default.offset(searchInput).left + minWidth);
- const offsetTop = Util_1.default.styleAsInt(window.getComputedStyle(parent), 'padding-bottom');
- dropdownMenu.style.setProperty('transform', 'translateX(-' + Math.ceil(offsetRight) + 'px) translateY(-' + offsetTop + 'px)', '');
+ const offsetRight = Util_1.default.offset(parent).left + parent.clientWidth - (Util_1.default.offset(searchInput).left + minWidth);
+ const offsetTop = Util_1.default.styleAsInt(window.getComputedStyle(parent), "padding-bottom");
+ dropdownMenu.style.setProperty("transform", "translateX(-" + Math.ceil(offsetRight) + "px) translateY(-" + offsetTop + "px)", "");
}
},
callbackSelect() {
setTimeout(() => {
- const form = DomTraverse.parentByTag(searchInput, 'FORM');
+ const form = DomTraverse.parentByTag(searchInput, "FORM");
form.submit();
}, 1);
return true;
},
});
- const searchType = document.querySelector('.pageHeaderSearchType');
+ const searchType = document.querySelector(".pageHeaderSearchType");
const dropdownMenu = Simple_1.default.getDropdownMenu(Util_1.default.identify(searchType));
- dropdownMenu.querySelectorAll('a[data-object-type]').forEach(link => {
- link.addEventListener('click', click);
+ dropdownMenu.querySelectorAll("a[data-object-type]").forEach((link) => {
+ link.addEventListener("click", click);
});
// trigger click on init
const link = dropdownMenu.querySelector('a[data-object-type="' + objectType + '"]');
class UiSmileyInsert {
constructor(editorId) {
this.editorId = editorId;
- let container = document.getElementById('smilies-' + this.editorId);
+ let container = document.getElementById("smilies-" + this.editorId);
if (!container) {
// form builder
- container = document.getElementById(this.editorId + 'SmiliesTabContainer');
+ container = document.getElementById(this.editorId + "SmiliesTabContainer");
if (!container) {
- throw new Error('Unable to find the message tab menu container containing the smilies.');
+ throw new Error("Unable to find the message tab menu container containing the smilies.");
}
}
this.container = container;
- this.container.addEventListener('keydown', (ev) => this.keydown(ev));
- this.container.addEventListener('mousedown', (ev) => this.mousedown(ev));
+ this.container.addEventListener("keydown", (ev) => this.keydown(ev));
+ this.container.addEventListener("mousedown", (ev) => this.mousedown(ev));
}
keydown(event) {
const activeButton = document.activeElement;
- if (!activeButton.classList.contains('jsSmiley')) {
+ if (!activeButton.classList.contains("jsSmiley")) {
return;
}
- if (['ArrowLeft', 'ArrowRight', 'End', 'Home'].includes(event.key)) {
+ if (["ArrowLeft", "ArrowRight", "End", "Home"].includes(event.key)) {
event.preventDefault();
const target = event.currentTarget;
- const smilies = Array.from(target.querySelectorAll('.jsSmiley'));
- if (event.key === 'ArrowLeft') {
+ const smilies = Array.from(target.querySelectorAll(".jsSmiley"));
+ if (event.key === "ArrowLeft") {
smilies.reverse();
}
let index = smilies.indexOf(activeButton);
- if (event.key === 'Home') {
+ if (event.key === "Home") {
index = 0;
}
- else if (event.key === 'End') {
+ else if (event.key === "End") {
index = smilies.length - 1;
}
else {
}
smilies[index].focus();
}
- else if (event.key === 'Enter' || event.key === 'Space') {
+ else if (event.key === "Enter" || event.key === "Space") {
event.preventDefault();
- const image = activeButton.querySelector('img');
+ const image = activeButton.querySelector("img");
this.insert(image);
}
}
mousedown(event) {
const target = event.target;
// Clicks may occur on a few different elements, but we are only looking for the image.
- const listItem = target.closest('li');
+ const listItem = target.closest("li");
if (listItem && this.container.contains(listItem)) {
event.preventDefault();
- const img = listItem.querySelector('img');
+ const img = listItem.querySelector("img");
if (img) {
this.insert(img);
}
}
}
insert(img) {
- EventHandler.fire('com.woltlab.wcf.redactor2', 'insertSmiley_' + this.editorId, {
+ EventHandler.fire("com.woltlab.wcf.redactor2", "insertSmiley_" + this.editorId, {
img,
});
}
*/
constructor(elementId, options) {
this.dropdownMenu = null;
- this.value = '';
+ this.value = "";
const element = document.getElementById(elementId);
if (element === null) {
throw new Error("Expected a valid element id.");
}
this.element = element;
this.ajaxPayload = Core.extend({
- actionName: 'getSearchResultList',
- className: '',
- interfaceName: 'wcf\\data\\ISearchAction',
+ actionName: "getSearchResultList",
+ className: "",
+ interfaceName: "wcf\\data\\ISearchAction",
parameters: {
data: {},
},
}, options.ajax);
- if (typeof options.callbackSelect !== 'function') {
+ if (typeof options.callbackSelect !== "function") {
throw new Error("Expected a valid callback for option 'callbackSelect'.");
}
this.callbackSelect = options.callbackSelect;
this.excludedSearchValues = new Set(Array.isArray(options.excludedSearchValues) ? options.excludedSearchValues : []);
this.threshold = options.threshold === undefined ? 3 : options.threshold;
- this.element.addEventListener('click', (ev) => ev.preventDefault());
- this.element.addEventListener('keydown', (ev) => this.keyDown(ev));
- this.element.addEventListener('keyup', (ev) => this.keyUp(ev));
+ this.element.addEventListener("click", (ev) => ev.preventDefault());
+ this.element.addEventListener("keydown", (ev) => this.keyDown(ev));
+ this.element.addEventListener("keyup", (ev) => this.keyUp(ev));
}
/**
* Adds an excluded search value.
if (!this.isActive()) {
return true;
}
- if (['ArrowDown', 'ArrowUp', 'Enter', 'Escape'].indexOf(event.key) === -1) {
+ if (["ArrowDown", "ArrowUp", "Enter", "Escape"].indexOf(event.key) === -1) {
return true;
}
let active;
let i = 0, length = this.dropdownMenu.childElementCount;
while (i < length) {
active = this.dropdownMenu.children[i];
- if (active.classList.contains('active')) {
+ if (active.classList.contains("active")) {
break;
}
i++;
}
- if (event.key === 'Enter') {
+ if (event.key === "Enter") {
Simple_1.default.close(this.element.id);
this.select(undefined, active);
}
- else if (event.key === 'Escape') {
+ else if (event.key === "Escape") {
if (Simple_1.default.isOpen(this.element.id)) {
Simple_1.default.close(this.element.id);
}
}
else {
let index = 0;
- if (event.key === 'ArrowUp') {
- index = ((i === 0) ? length : i) - 1;
+ if (event.key === "ArrowUp") {
+ index = (i === 0 ? length : i) - 1;
}
- else if (event.key === 'ArrowDown') {
+ else if (event.key === "ArrowDown") {
index = i + 1;
if (index === length)
index = 0;
}
if (index !== i) {
- active.classList.remove('active');
- this.dropdownMenu.children[index].classList.add('active');
+ active.classList.remove("active");
+ this.dropdownMenu.children[index].classList.add("active");
}
}
event.preventDefault();
const anchor = item.children[0];
this.callbackSelect(this.element.id, {
objectId: +(anchor.dataset.objectId || 0),
- value: item.textContent || '',
- type: anchor.dataset.type || '',
+ value: item.textContent || "",
+ type: anchor.dataset.type || "",
});
if (event instanceof MouseEvent) {
this.element.focus();
*/
_ajaxSuccess(data) {
if (this.dropdownMenu === null) {
- this.dropdownMenu = document.createElement('div');
- this.dropdownMenu.className = 'dropdownMenu';
+ this.dropdownMenu = document.createElement("div");
+ this.dropdownMenu.className = "dropdownMenu";
Simple_1.default.initFragment(this.element, this.dropdownMenu);
}
else {
- this.dropdownMenu.innerHTML = '';
+ this.dropdownMenu.innerHTML = "";
}
if (Array.isArray(data.returnValues)) {
data.returnValues.forEach((item, index) => {
- const anchor = document.createElement('a');
+ const anchor = document.createElement("a");
if (item.icon) {
- anchor.className = 'box16';
- anchor.innerHTML = item.icon + ' <span></span>';
+ anchor.className = "box16";
+ anchor.innerHTML = item.icon + " <span></span>";
anchor.children[1].textContent = item.label;
}
else {
if (item.type) {
anchor.dataset.type = item.type;
}
- anchor.addEventListener('click', (ev) => this.select(ev));
- const listItem = document.createElement('li');
+ anchor.addEventListener("click", (ev) => this.select(ev));
+ const listItem = document.createElement("li");
if (index === 0) {
- listItem.className = 'active';
+ listItem.className = "active";
}
listItem.appendChild(anchor);
this.dropdownMenu.appendChild(listItem);
* Initializes available tab menus.
*/
function init() {
- document.querySelectorAll('.tabMenuContainer:not(.staticTabMenuContainer)').forEach(container => {
+ document.querySelectorAll(".tabMenuContainer:not(.staticTabMenuContainer)").forEach((container) => {
const containerId = Util_1.default.identify(container);
if (_tabMenus.has(containerId)) {
return;
tabMenu.select(returnValue.id, undefined, true);
}
}
- const list = document.querySelector('#' + containerId + ' > nav > ul');
- list.addEventListener('click', event => {
+ const list = document.querySelector("#" + containerId + " > nav > ul");
+ list.addEventListener("click", (event) => {
event.preventDefault();
event.stopPropagation();
if (event.target === list) {
- list.classList.add('active');
+ list.classList.add("active");
_activeList = list;
}
else {
- list.classList.remove('active');
+ list.classList.remove("active");
_activeList = null;
}
});
// bind scroll listener
- container.querySelectorAll('.tabMenu, .menu').forEach(menu => {
+ container.querySelectorAll(".tabMenu, .menu").forEach((menu) => {
function callback() {
timeout = null;
rebuildMenuOverflow(menu);
}
let timeout = null;
- menu.querySelector('ul').addEventListener('scroll', () => {
+ menu.querySelector("ul").addEventListener("scroll", () => {
if (timeout !== null) {
window.clearTimeout(timeout);
}
// to not work and a warning is displayed on the console. We can work around this
// by manually checking if the input fields validate on submit and display the
// parent tab ourselves.
- const form = container.closest('form');
+ const form = container.closest("form");
if (form !== null) {
const submitButton = form.querySelector('input[type="submit"]');
if (submitButton !== null) {
- submitButton.addEventListener('click', event => {
+ submitButton.addEventListener("click", (event) => {
if (event.defaultPrevented) {
return;
}
- container.querySelectorAll('input, select').forEach((element) => {
+ container.querySelectorAll("input, select").forEach((element) => {
if (!element.checkValidity()) {
event.preventDefault();
// Select the tab that contains the erroneous element.
- const tabMenu = getTabMenu(element.closest('.tabMenuContainer').id);
- const tabMenuContent = element.closest('.tabMenuContent');
- tabMenu.select(tabMenuContent.dataset.name || '');
+ const tabMenu = getTabMenu(element.closest(".tabMenuContainer").id);
+ const tabMenuContent = element.closest(".tabMenuContent");
+ tabMenu.select(tabMenuContent.dataset.name || "");
UiScroll.element(element, () => {
element.reportValidity();
});
* Selects the first tab containing an element with class `formError`.
*/
function selectErroneousTabs() {
- _tabMenus.forEach(tabMenu => {
+ _tabMenus.forEach((tabMenu) => {
let foundError = false;
- tabMenu.getContainers().forEach(container => {
- if (!foundError && container.querySelector('.formError') !== null) {
+ tabMenu.getContainers().forEach((container) => {
+ if (!foundError && container.querySelector(".formError") !== null) {
foundError = true;
tabMenu.select(container.id);
}
}
function scrollEnable(isSetup) {
_enableTabScroll = true;
- _tabMenus.forEach(tabMenu => {
+ _tabMenus.forEach((tabMenu) => {
const activeTab = tabMenu.getActiveTab();
if (isSetup) {
- rebuildMenuOverflow(activeTab.closest('.menu, .tabMenu'));
+ rebuildMenuOverflow(activeTab.closest(".menu, .tabMenu"));
}
else {
scrollToTab(activeTab);
if (scrollLeft === left) {
return;
}
- list.classList.add('enableAnimation');
+ list.classList.add("enableAnimation");
// new value is larger, we're scrolling towards the end
if (scrollLeft < left) {
- list.firstElementChild.style.setProperty('margin-left', (scrollLeft - left) + 'px', '');
+ list.firstElementChild.style.setProperty("margin-left", scrollLeft - left + "px", "");
}
else {
// new value is smaller, we're scrolling towards the start
- list.style.setProperty('padding-left', (scrollLeft - left) + 'px', '');
+ list.style.setProperty("padding-left", scrollLeft - left + "px", "");
}
setTimeout(() => {
- list.classList.remove('enableAnimation');
- list.firstElementChild.style.removeProperty('margin-left');
- list.style.removeProperty('padding-left');
+ list.classList.remove("enableAnimation");
+ list.firstElementChild.style.removeProperty("margin-left");
+ list.style.removeProperty("padding-left");
list.scrollLeft = left;
}, 300);
}
return;
}
const width = menu.clientWidth;
- const list = menu.querySelector('ul');
+ const list = menu.querySelector("ul");
const scrollLeft = list.scrollLeft;
const scrollWidth = list.scrollWidth;
- const overflowLeft = (scrollLeft > 0);
- let overlayLeft = menu.querySelector('.tabMenuOverlayLeft');
+ const overflowLeft = scrollLeft > 0;
+ let overlayLeft = menu.querySelector(".tabMenuOverlayLeft");
if (overflowLeft) {
if (overlayLeft === null) {
- overlayLeft = document.createElement('span');
- overlayLeft.className = 'tabMenuOverlayLeft icon icon24 fa-angle-left';
- overlayLeft.addEventListener('click', () => {
+ overlayLeft = document.createElement("span");
+ overlayLeft.className = "tabMenuOverlayLeft icon icon24 fa-angle-left";
+ overlayLeft.addEventListener("click", () => {
const listWidth = list.clientWidth;
scrollMenu(list, list.scrollLeft - ~~(listWidth / 2), list.scrollLeft, list.scrollWidth, listWidth, 0);
});
menu.insertBefore(overlayLeft, menu.firstChild);
}
- overlayLeft.classList.add('active');
+ overlayLeft.classList.add("active");
}
else if (overlayLeft !== null) {
- overlayLeft.classList.remove('active');
+ overlayLeft.classList.remove("active");
}
- const overflowRight = (width + scrollLeft < scrollWidth);
- let overlayRight = menu.querySelector('.tabMenuOverlayRight');
+ const overflowRight = width + scrollLeft < scrollWidth;
+ let overlayRight = menu.querySelector(".tabMenuOverlayRight");
if (overflowRight) {
if (overlayRight === null) {
- overlayRight = document.createElement('span');
- overlayRight.className = 'tabMenuOverlayRight icon icon24 fa-angle-right';
- overlayRight.addEventListener('click', () => {
+ overlayRight = document.createElement("span");
+ overlayRight.className = "tabMenuOverlayRight icon icon24 fa-angle-right";
+ overlayRight.addEventListener("click", () => {
const listWidth = list.clientWidth;
scrollMenu(list, list.scrollLeft + ~~(listWidth / 2), list.scrollLeft, list.scrollWidth, listWidth, 0);
});
menu.appendChild(overlayRight);
}
- overlayRight.classList.add('active');
+ overlayRight.classList.add("active");
}
else if (overlayRight !== null) {
- overlayRight.classList.remove('active');
+ overlayRight.classList.remove("active");
}
}
/**
function setup() {
init();
selectErroneousTabs();
- Listener_1.default.add('WoltLabSuite/Core/Ui/TabMenu', init);
- CloseOverlay_1.default.add('WoltLabSuite/Core/Ui/TabMenu', () => {
+ Listener_1.default.add("WoltLabSuite/Core/Ui/TabMenu", init);
+ CloseOverlay_1.default.add("WoltLabSuite/Core/Ui/TabMenu", () => {
if (_activeList) {
- _activeList.classList.remove('active');
+ _activeList.classList.remove("active");
_activeList = null;
}
});
- UiScreen.on('screen-sm-down', {
+ UiScreen.on("screen-sm-down", {
match() {
scrollEnable(false);
},
scrollEnable(true);
},
});
- window.addEventListener('hashchange', () => {
+ window.addEventListener("hashchange", () => {
const hash = Simple_1.default.getIdentifierFromHash();
const element = hash ? document.getElementById(hash) : null;
- if (element !== null && element.classList.contains('tabMenuContent')) {
- _tabMenus.forEach(tabMenu => {
+ if (element !== null && element.classList.contains("tabMenuContent")) {
+ _tabMenus.forEach((tabMenu) => {
if (tabMenu.hasTab(hash)) {
tabMenu.select(hash);
}
window.setTimeout(() => {
// check if page was initially scrolled using a tab id
const tabMenuContent = document.getElementById(hash);
- if (tabMenuContent && tabMenuContent.classList.contains('tabMenuContent')) {
- const scrollY = (window.scrollY || window.pageYOffset);
+ if (tabMenuContent && tabMenuContent.classList.contains("tabMenuContent")) {
+ const scrollY = window.scrollY || window.pageYOffset;
if (scrollY > 0) {
const parent = tabMenuContent.parentNode;
let offsetTop = parent.offsetTop - 50;
if (!_enableTabScroll) {
return;
}
- const list = tab.closest('ul');
+ const list = tab.closest("ul");
const width = list.clientWidth;
const scrollLeft = list.scrollLeft;
const scrollWidth = list.scrollWidth;
* </div>
*/
validate() {
- if (!this.container.classList.contains('tabMenuContainer')) {
+ if (!this.container.classList.contains("tabMenuContainer")) {
return false;
}
- const nav = DomTraverse.childByTag(this.container, 'NAV');
+ const nav = DomTraverse.childByTag(this.container, "NAV");
if (nav === null) {
return false;
}
// get children
- const tabs = nav.querySelectorAll('li');
+ const tabs = nav.querySelectorAll("li");
if (tabs.length === 0) {
return false;
}
- DomTraverse.childrenByTag(this.container, 'DIV').forEach((container) => {
+ DomTraverse.childrenByTag(this.container, "DIV").forEach((container) => {
let name = container.dataset.name;
if (!name) {
name = Util_1.default.identify(container);
this.containers.set(name, container);
});
const containerId = this.container.id;
- tabs.forEach(tab => {
+ tabs.forEach((tab) => {
const name = this._getTabName(tab);
if (!name) {
return;
}
if (this.tabs.has(name)) {
- throw new Error("Tab names must be unique, li[data-name='" + name + "'] (tab menu id: '" + containerId + "') exists more than once.");
+ throw new Error("Tab names must be unique, li[data-name='" +
+ name +
+ "'] (tab menu id: '" +
+ containerId +
+ "') exists more than once.");
}
const container = this.containers.get(name);
if (container === undefined) {
throw new Error("Expected content element '" + name + "' (tab menu id: '" + containerId + "') to be a direct children.");
}
// check if tab holds exactly one children which is an anchor element
- if (tab.childElementCount !== 1 || tab.children[0].nodeName !== 'A') {
+ if (tab.childElementCount !== 1 || tab.children[0].nodeName !== "A") {
throw new Error("Expected exactly one <a> as children for li[data-name='" + name + "'] (tab menu id: '" + containerId + "').");
}
this.tabs.set(name, tab);
throw new Error("Expected at least one tab (tab menu id: '" + containerId + "').");
}
if (this.isLegacy) {
- this.container.dataset.isLegacy = 'true';
+ this.container.dataset.isLegacy = "true";
this.tabs.forEach(function (tab, name) {
- tab.setAttribute('aria-controls', name);
+ tab.setAttribute("aria-controls", name);
});
}
return true;
*/
init(oldTabs) {
// bind listeners
- this.tabs.forEach(tab => {
- if (!oldTabs || oldTabs.get(tab.dataset.name || '') !== tab) {
+ this.tabs.forEach((tab) => {
+ if (!oldTabs || oldTabs.get(tab.dataset.name || "") !== tab) {
const firstChild = tab.children[0];
- firstChild.addEventListener('click', (ev) => this._onClick(ev));
+ firstChild.addEventListener("click", (ev) => this._onClick(ev));
// iOS 13 changed the behavior for click events after scrolling the menu. It prevents
// the synthetic mouse events like "click" from triggering for a short duration after
// a scrolling has occurred. If the user scrolls to the end of the list and immediately
// attempts to click the tab, nothing will happen. However, if the user waits for some
// time, the tap will trigger a "click" event again.
- //
+ //
// A "click" event is basically the result of a touch without any (significant) finger
// movement indicated by a "touchmove" event. This changes allows the user to scroll
// both the menu and the page normally, but still benefit from snappy reactions when
// tapping a menu item.
- if (Environment.platform() === 'ios') {
+ if (Environment.platform() === "ios") {
let isClick = false;
- firstChild.addEventListener('touchstart', () => {
+ firstChild.addEventListener("touchstart", () => {
isClick = true;
});
- firstChild.addEventListener('touchmove', () => {
+ firstChild.addEventListener("touchmove", () => {
isClick = false;
});
- firstChild.addEventListener('touchend', (event) => {
+ firstChild.addEventListener("touchend", (event) => {
if (isClick) {
isClick = false;
// This will block the regular click event from firing.
if (!oldTabs) {
const hash = TabMenuSimple.getIdentifierFromHash();
let selectTab = undefined;
- if (hash !== '') {
+ if (hash !== "") {
selectTab = this.tabs.get(hash);
// check for parent tab menu
if (selectTab) {
const item = this.container.parentNode;
- if (item.classList.contains('tabMenuContainer')) {
+ if (item.classList.contains("tabMenuContainer")) {
returnValue = item;
}
}
}
if (preselect === true) {
this.tabs.forEach(function (tab) {
- if (!selectTab && !Util_1.default.isHidden(tab) && (!tab.previousElementSibling || Util_1.default.isHidden(tab.previousElementSibling))) {
+ if (!selectTab &&
+ !Util_1.default.isHidden(tab) &&
+ (!tab.previousElementSibling || Util_1.default.isHidden(tab.previousElementSibling))) {
selectTab = tab;
}
});
}
- else if (typeof preselect === 'string' && preselect !== "false") {
+ else if (typeof preselect === "string" && preselect !== "false") {
selectTab = this.tabs.get(preselect);
}
}
if (selectTab) {
- this.containers.forEach(container => {
- container.classList.add('hidden');
+ this.containers.forEach((container) => {
+ container.classList.add("hidden");
});
this.select(null, selectTab, true);
}
const store = this.container.dataset.store;
if (store) {
- const input = document.createElement('input');
- input.type = 'hidden';
+ const input = document.createElement("input");
+ input.type = "hidden";
input.name = store;
- input.value = this.getActiveTab().dataset.name || '';
+ input.value = this.getActiveTab().dataset.name || "";
this.container.appendChild(input);
this.store = input;
}
* @param {boolean=} disableEvent suppress event handling
*/
select(name, tab, disableEvent) {
- name = (name) ? name.toString() : '';
+ name = name ? name.toString() : "";
tab = tab || this.tabs.get(name);
if (!tab) {
// check if name is an integer
if (~~name === +name) {
name = ~~name;
let i = 0;
- this.tabs.forEach(item => {
+ this.tabs.forEach((item) => {
if (i === name) {
tab = item;
}
throw new Error("Expected a valid tab name, '" + name + "' given (tab menu id: '" + this.container.id + "').");
}
}
- name = (name || tab.dataset.name || '');
+ name = (name || tab.dataset.name || "");
// unmark active tab
const oldTab = this.getActiveTab();
let oldContent = null;
return;
}
if (!disableEvent) {
- EventHandler.fire('com.woltlab.wcf.simpleTabMenu_' + this.container.id, 'beforeSelect', {
+ EventHandler.fire("com.woltlab.wcf.simpleTabMenu_" + this.container.id, "beforeSelect", {
tab: oldTab,
tabName: oldTabName,
});
}
- oldTab.classList.remove('active');
- oldContent = this.containers.get(oldTab.dataset.name || '');
- oldContent.classList.remove('active');
- oldContent.classList.add('hidden');
+ oldTab.classList.remove("active");
+ oldContent = this.containers.get(oldTab.dataset.name || "");
+ oldContent.classList.remove("active");
+ oldContent.classList.add("hidden");
if (this.isLegacy) {
- oldTab.classList.remove('ui-state-active');
- oldContent.classList.remove('ui-state-active');
+ oldTab.classList.remove("ui-state-active");
+ oldContent.classList.remove("ui-state-active");
}
}
- tab.classList.add('active');
+ tab.classList.add("active");
const newContent = this.containers.get(name);
- newContent.classList.add('active');
- newContent.classList.remove('hidden');
+ newContent.classList.add("active");
+ newContent.classList.remove("hidden");
if (this.isLegacy) {
- tab.classList.add('ui-state-active');
- newContent.classList.add('ui-state-active');
+ tab.classList.add("ui-state-active");
+ newContent.classList.add("ui-state-active");
}
if (this.store) {
this.store.value = name;
}
if (!disableEvent) {
- EventHandler.fire('com.woltlab.wcf.simpleTabMenu_' + this.container.id, 'select', {
+ EventHandler.fire("com.woltlab.wcf.simpleTabMenu_" + this.container.id, "select", {
active: tab,
activeName: name,
previous: oldTab,
previousName: oldTab ? oldTab.dataset.name : null,
});
- const jQuery = (this.isLegacy && typeof window.jQuery === 'function') ? window.jQuery : null;
+ const jQuery = this.isLegacy && typeof window.jQuery === "function" ? window.jQuery : null;
if (jQuery) {
// simulate jQuery UI Tabs event
- jQuery(this.container).trigger('wcftabsbeforeactivate', {
+ jQuery(this.container).trigger("wcftabsbeforeactivate", {
newTab: jQuery(tab),
oldTab: jQuery(oldTab),
newPanel: jQuery(newContent),
oldPanel: jQuery(oldContent),
});
}
- let location = window.location.href.replace(/#+[^#]*$/, '');
+ let location = window.location.href.replace(/#+[^#]*$/, "");
if (TabMenuSimple.getIdentifierFromHash() === name) {
location += window.location.hash;
}
else {
- location += '#' + name;
+ location += "#" + name;
}
// update history
- window.history.replaceState(undefined, '', location);
+ window.history.replaceState(undefined, "", location);
}
// TODO
/*
*/
selectFirstVisible() {
let selectTab = null;
- this.tabs.forEach(tab => {
+ this.tabs.forEach((tab) => {
if (!selectTab && !Util_1.default.isHidden(tab)) {
selectTab = tab;
}
let name = tab.dataset.name || null;
// handle legacy tab menus
if (!name) {
- if (tab.childElementCount === 1 && tab.children[0].nodeName === 'A') {
+ if (tab.childElementCount === 1 && tab.children[0].nodeName === "A") {
const link = tab.children[0];
if (link.href.match(/#([^#]+)$/)) {
name = RegExp.$1;
* Returns the currently active tab.
*/
getActiveTab() {
- return document.querySelector('#' + this.container.id + ' > nav > ul > li.active');
+ return document.querySelector("#" + this.container.id + " > nav > ul > li.active");
}
/**
* Returns the list of registered content containers.
if (window.location.hash.match(/^#+([^\/]+)+(?:\/.+)?/)) {
return RegExp.$1;
}
- return '';
+ return "";
}
- ;
}
return TabMenuSimple;
});
if (element === null) {
throw new Error("Unable to find element by selector '" + elementSelector + "'.");
}
- const type = (element.nodeName === 'INPUT') ? element.type : '';
- if (type !== 'checkbox' && type !== 'radio') {
+ const type = element.nodeName === "INPUT" ? element.type : "";
+ if (type !== "checkbox" && type !== "radio") {
throw new Error("Illegal element, expected input[type='checkbox'] or input[type='radio'].");
}
this.element = element;
- this.hide = this.getElements('hide', Array.isArray(options.hide) ? options.hide : []);
- this.hide = this.getElements('show', Array.isArray(options.show) ? options.show : []);
- this.element.addEventListener('change', (ev) => this.change(ev));
+ this.hide = this.getElements("hide", Array.isArray(options.hide) ? options.hide : []);
+ this.hide = this.getElements("show", Array.isArray(options.show) ? options.show : []);
+ this.element.addEventListener("change", (ev) => this.change(ev));
this.updateVisibility(this.show, this.element.checked);
this.updateVisibility(this.hide, !this.element.checked);
}
getElements(type, items) {
const elements = [];
- items.forEach(item => {
+ items.forEach((item) => {
let element = null;
- if (typeof item === 'string') {
+ if (typeof item === "string") {
element = document.querySelector(item);
if (element === null) {
throw new Error(`Unable to find an element with the selector '${item}'.`);
* Loops through the target elements and shows / hides them.
*/
updateVisibility(elements, showElement) {
- elements.forEach(element => {
- Util_1.default[showElement ? 'show' : 'hide'](element);
+ elements.forEach((element) => {
+ Util_1.default[showElement ? "show" : "hide"](element);
});
}
}
function mouseEnter(event) {
const element = event.currentTarget;
let title = element.title.trim();
- if (title !== '') {
+ if (title !== "") {
element.dataset.tooltip = title;
- element.setAttribute('aria-label', title);
- element.removeAttribute('title');
+ element.setAttribute("aria-label", title);
+ element.removeAttribute("title");
}
- title = element.dataset.tooltip || '';
+ title = element.dataset.tooltip || "";
// reset tooltip position
- _tooltip.style.removeProperty('top');
- _tooltip.style.removeProperty('left');
+ _tooltip.style.removeProperty("top");
+ _tooltip.style.removeProperty("left");
// ignore empty tooltip
if (!title.length) {
- _tooltip.classList.remove('active');
+ _tooltip.classList.remove("active");
return;
}
else {
- _tooltip.classList.add('active');
+ _tooltip.classList.add("active");
}
_text.textContent = title;
UiAlignment.set(_tooltip, element, {
- horizontal: 'center',
+ horizontal: "center",
verticalOffset: 4,
pointer: true,
- pointerClassNames: ['inverse'],
- vertical: 'top',
+ pointerClassNames: ["inverse"],
+ vertical: "top",
});
}
/**
* Hides the tooltip once the mouse leaves the element.
*/
function mouseLeave() {
- _tooltip.classList.remove('active');
+ _tooltip.classList.remove("active");
}
/**
* Initializes the tooltip element and binds event listener.
*/
function setup() {
- if (Environment.platform() !== 'desktop') {
+ if (Environment.platform() !== "desktop") {
return;
}
- _tooltip = document.createElement('div');
- _tooltip.id = 'balloonTooltip';
- _tooltip.classList.add('balloonTooltip');
- _tooltip.addEventListener('transitionend', () => {
- if (!_tooltip.classList.contains('active')) {
+ _tooltip = document.createElement("div");
+ _tooltip.id = "balloonTooltip";
+ _tooltip.classList.add("balloonTooltip");
+ _tooltip.addEventListener("transitionend", () => {
+ if (!_tooltip.classList.contains("active")) {
// reset back to the upper left corner, prevent it from staying outside
// the viewport if the body overflow was previously hidden
- ['bottom', 'left', 'right', 'top'].forEach(property => {
+ ["bottom", "left", "right", "top"].forEach((property) => {
_tooltip.style.removeProperty(property);
});
}
});
- _text = document.createElement('span');
- _text.id = 'balloonTooltipText';
+ _text = document.createElement("span");
+ _text.id = "balloonTooltipText";
_tooltip.appendChild(_text);
- _pointer = document.createElement('span');
- _pointer.classList.add('elementPointer');
- _pointer.appendChild(document.createElement('span'));
+ _pointer = document.createElement("span");
+ _pointer.classList.add("elementPointer");
+ _pointer.appendChild(document.createElement("span"));
_tooltip.appendChild(_pointer);
document.body.appendChild(_tooltip);
init();
- Listener_1.default.add('WoltLabSuite/Core/Ui/Tooltip', init);
- window.addEventListener('scroll', mouseLeave);
+ Listener_1.default.add("WoltLabSuite/Core/Ui/Tooltip", init);
+ window.addEventListener("scroll", mouseLeave);
}
exports.setup = setup;
/**
* Initializes tooltip elements.
*/
function init() {
- document.querySelectorAll('.jsTooltip').forEach((element) => {
- element.classList.remove('jsTooltip');
+ document.querySelectorAll(".jsTooltip").forEach((element) => {
+ element.classList.remove("jsTooltip");
const title = element.title.trim();
if (title.length) {
element.dataset.tooltip = title;
- element.removeAttribute('title');
- element.setAttribute('aria-label', title);
- element.addEventListener('mouseenter', mouseEnter);
- element.addEventListener('mouseleave', mouseLeave);
- element.addEventListener('click', mouseLeave);
+ element.removeAttribute("title");
+ element.setAttribute("aria-label", title);
+ element.addEventListener("mouseenter", mouseEnter);
+ element.addEventListener("mouseleave", mouseLeave);
+ element.addEventListener("click", mouseLeave);
}
});
}
UiNotification = tslib_1.__importStar(UiNotification);
class UserEditor {
constructor() {
- this.actionName = '';
- this.header = document.querySelector('.userProfileUser');
- ['ban', 'disableAvatar', 'disableCoverPhoto', 'disableSignature', 'enable'].forEach(action => {
- const button = document.querySelector('.userProfileButtonMenu .jsButtonUser' + StringUtil.ucfirst(action));
+ this.actionName = "";
+ this.header = document.querySelector(".userProfileUser");
+ ["ban", "disableAvatar", "disableCoverPhoto", "disableSignature", "enable"].forEach((action) => {
+ const button = document.querySelector(".userProfileButtonMenu .jsButtonUser" + StringUtil.ucfirst(action));
// The button is missing if the current user lacks the permission.
if (button) {
button.dataset.action = action;
- button.addEventListener('click', (ev) => this._click(ev));
+ button.addEventListener("click", (ev) => this._click(ev));
}
});
}
_click(event) {
event.preventDefault();
const target = event.currentTarget;
- const action = target.dataset.action || '';
- let actionName = '';
+ const action = target.dataset.action || "";
+ let actionName = "";
switch (action) {
- case 'ban':
- if (Core.stringToBool(this.header.dataset.banned || '')) {
- actionName = 'unban';
+ case "ban":
+ if (Core.stringToBool(this.header.dataset.banned || "")) {
+ actionName = "unban";
}
break;
- case 'disableAvatar':
- if (Core.stringToBool(this.header.dataset.disableAvatar || '')) {
- actionName = 'enableAvatar';
+ case "disableAvatar":
+ if (Core.stringToBool(this.header.dataset.disableAvatar || "")) {
+ actionName = "enableAvatar";
}
break;
- case 'disableCoverPhoto':
- if (Core.stringToBool(this.header.dataset.disableCoverPhoto || '')) {
- actionName = 'enableCoverPhoto';
+ case "disableCoverPhoto":
+ if (Core.stringToBool(this.header.dataset.disableCoverPhoto || "")) {
+ actionName = "enableCoverPhoto";
}
break;
- case 'disableSignature':
- if (Core.stringToBool(this.header.dataset.disableSignature || '')) {
- actionName = 'enableSignature';
+ case "disableSignature":
+ if (Core.stringToBool(this.header.dataset.disableSignature || "")) {
+ actionName = "enableSignature";
}
break;
- case 'enable':
- actionName = (Core.stringToBool(this.header.dataset.isDisabled || '')) ? 'enable' : 'disable';
+ case "enable":
+ actionName = Core.stringToBool(this.header.dataset.isDisabled || "") ? "enable" : "disable";
break;
}
- if (actionName === '') {
+ if (actionName === "") {
this.actionName = action;
Dialog_1.default.open(this);
}
*/
_submit(event) {
event.preventDefault();
- const label = document.getElementById('wcfUiUserEditorExpiresLabel');
- let expires = '';
- let errorMessage = '';
- const neverExpires = document.getElementById('wcfUiUserEditorNeverExpires');
+ const label = document.getElementById("wcfUiUserEditorExpiresLabel");
+ let expires = "";
+ let errorMessage = "";
+ const neverExpires = document.getElementById("wcfUiUserEditorNeverExpires");
if (!neverExpires.checked) {
- const expireValue = document.getElementById('wcfUiUserEditorExpiresDatePicker');
+ const expireValue = document.getElementById("wcfUiUserEditorExpiresDatePicker");
expires = expireValue.value;
- if (expires === '') {
- errorMessage = Language.get('wcf.global.form.error.empty');
+ if (expires === "") {
+ errorMessage = Language.get("wcf.global.form.error.empty");
}
}
Util_1.default.innerError(label, errorMessage);
const parameters = {};
- parameters[this.actionName + 'Expires'] = expires;
- const reason = document.getElementById('wcfUiUserEditorReason');
- parameters[this.actionName + 'Reason'] = reason.value.trim();
+ parameters[this.actionName + "Expires"] = expires;
+ const reason = document.getElementById("wcfUiUserEditorReason");
+ parameters[this.actionName + "Reason"] = reason.value.trim();
Ajax.api(this, {
actionName: this.actionName,
parameters: parameters,
_ajaxSuccess(data) {
let button;
switch (data.actionName) {
- case 'ban':
- case 'unban':
- this.header.dataset.banned = (data.actionName === 'ban') ? 'true' : 'false';
- button = document.querySelector('.userProfileButtonMenu .jsButtonUserBan');
- button.textContent = Language.get('wcf.user.' + (data.actionName === 'ban' ? 'unban' : 'ban'));
- const contentTitle = this.header.querySelector('.contentTitle');
- let banIcon = contentTitle.querySelector('.jsUserBanned');
- if (data.actionName === 'ban') {
- banIcon = document.createElement('span');
- banIcon.className = 'icon icon24 fa-lock jsUserBanned jsTooltip';
+ case "ban":
+ case "unban":
+ this.header.dataset.banned = data.actionName === "ban" ? "true" : "false";
+ button = document.querySelector(".userProfileButtonMenu .jsButtonUserBan");
+ button.textContent = Language.get("wcf.user." + (data.actionName === "ban" ? "unban" : "ban"));
+ const contentTitle = this.header.querySelector(".contentTitle");
+ let banIcon = contentTitle.querySelector(".jsUserBanned");
+ if (data.actionName === "ban") {
+ banIcon = document.createElement("span");
+ banIcon.className = "icon icon24 fa-lock jsUserBanned jsTooltip";
banIcon.title = data.returnValues;
contentTitle.appendChild(banIcon);
}
banIcon.remove();
}
break;
- case 'disableAvatar':
- case 'enableAvatar':
- this.header.dataset.disableAvatar = (data.actionName === 'disableAvatar') ? 'true' : 'false';
- button = document.querySelector('.userProfileButtonMenu .jsButtonUserDisableAvatar');
- button.textContent = Language.get('wcf.user.' + (data.actionName === 'disableAvatar' ? 'enable' : 'disable') + 'Avatar');
+ case "disableAvatar":
+ case "enableAvatar":
+ this.header.dataset.disableAvatar = data.actionName === "disableAvatar" ? "true" : "false";
+ button = document.querySelector(".userProfileButtonMenu .jsButtonUserDisableAvatar");
+ button.textContent = Language.get("wcf.user." + (data.actionName === "disableAvatar" ? "enable" : "disable") + "Avatar");
break;
- case 'disableCoverPhoto':
- case 'enableCoverPhoto':
- this.header.dataset.disableCoverPhoto = (data.actionName === 'disableCoverPhoto') ? 'true' : 'false';
- button = document.querySelector('.userProfileButtonMenu .jsButtonUserDisableCoverPhoto');
- button.textContent = Language.get('wcf.user.' + (data.actionName === 'disableCoverPhoto' ? 'enable' : 'disable') + 'CoverPhoto');
+ case "disableCoverPhoto":
+ case "enableCoverPhoto":
+ this.header.dataset.disableCoverPhoto = data.actionName === "disableCoverPhoto" ? "true" : "false";
+ button = document.querySelector(".userProfileButtonMenu .jsButtonUserDisableCoverPhoto");
+ button.textContent = Language.get("wcf.user." + (data.actionName === "disableCoverPhoto" ? "enable" : "disable") + "CoverPhoto");
break;
- case 'disableSignature':
- case 'enableSignature':
- this.header.dataset.disableSignature = (data.actionName === 'disableSignature') ? 'true' : 'false';
- button = document.querySelector('.userProfileButtonMenu .jsButtonUserDisableSignature');
- button.textContent = Language.get('wcf.user.' + (data.actionName === 'disableSignature' ? 'enable' : 'disable') + 'Signature');
+ case "disableSignature":
+ case "enableSignature":
+ this.header.dataset.disableSignature = data.actionName === "disableSignature" ? "true" : "false";
+ button = document.querySelector(".userProfileButtonMenu .jsButtonUserDisableSignature");
+ button.textContent = Language.get("wcf.user." + (data.actionName === "disableSignature" ? "enable" : "disable") + "Signature");
break;
- case 'enable':
- case 'disable':
- this.header.dataset.isDisabled = (data.actionName === 'disable') ? 'true' : 'false';
- button = document.querySelector('.userProfileButtonMenu .jsButtonUserEnable');
- button.textContent = Language.get('wcf.acp.user.' + (data.actionName === 'enable' ? 'disable' : 'enable'));
+ case "enable":
+ case "disable":
+ this.header.dataset.isDisabled = data.actionName === "disable" ? "true" : "false";
+ button = document.querySelector(".userProfileButtonMenu .jsButtonUserEnable");
+ button.textContent = Language.get("wcf.acp.user." + (data.actionName === "enable" ? "disable" : "enable"));
break;
}
- if (['ban', 'disableAvatar', 'disableCoverPhoto', 'disableSignature'].indexOf(data.actionName) !== -1) {
+ if (["ban", "disableAvatar", "disableCoverPhoto", "disableSignature"].indexOf(data.actionName) !== -1) {
Dialog_1.default.close(this);
}
UiNotification.show();
_ajaxSetup() {
return {
data: {
- className: 'wcf\\data\\user\\UserAction',
+ className: "wcf\\data\\user\\UserAction",
objectIDs: [+this.header.dataset.objectId],
},
};
}
_dialogSetup() {
return {
- id: 'wcfUiUserEditor',
+ id: "wcfUiUserEditor",
options: {
- onSetup: content => {
- const checkbox = document.getElementById('wcfUiUserEditorNeverExpires');
- checkbox.addEventListener('change', () => {
- const settings = document.getElementById('wcfUiUserEditorExpiresSettings');
- Util_1.default[checkbox.checked ? 'hide' : 'show'](settings);
+ onSetup: (content) => {
+ const checkbox = document.getElementById("wcfUiUserEditorNeverExpires");
+ checkbox.addEventListener("change", () => {
+ const settings = document.getElementById("wcfUiUserEditorExpiresSettings");
+ Util_1.default[checkbox.checked ? "hide" : "show"](settings);
});
- const submitButton = content.querySelector('button.buttonPrimary');
- submitButton.addEventListener('click', this._submit.bind(this));
+ const submitButton = content.querySelector("button.buttonPrimary");
+ submitButton.addEventListener("click", this._submit.bind(this));
},
- onShow: content => {
- Dialog_1.default.setTitle('wcfUiUserEditor', Language.get('wcf.user.' + this.actionName + '.confirmMessage'));
- const reason = document.getElementById('wcfUiUserEditorReason');
+ onShow: (content) => {
+ Dialog_1.default.setTitle("wcfUiUserEditor", Language.get("wcf.user." + this.actionName + ".confirmMessage"));
+ const reason = document.getElementById("wcfUiUserEditorReason");
let label = reason.nextElementSibling;
- const phrase = 'wcf.user.' + this.actionName + '.reason.description';
+ const phrase = "wcf.user." + this.actionName + ".reason.description";
label.textContent = Language.get(phrase);
- window[(label.textContent === phrase) ? 'elHide' : 'elShow'](label);
- label = document.getElementById('wcfUiUserEditorNeverExpires').nextElementSibling;
- label.textContent = Language.get('wcf.user.' + this.actionName + '.neverExpires');
+ window[label.textContent === phrase ? "elHide" : "elShow"](label);
+ label = document.getElementById("wcfUiUserEditorNeverExpires").nextElementSibling;
+ label.textContent = Language.get("wcf.user." + this.actionName + ".neverExpires");
label = content.querySelector('label[for="wcfUiUserEditorExpires"]');
- label.textContent = Language.get('wcf.user.' + this.actionName + '.expires');
- label = document.getElementById('wcfUiUserEditorExpiresLabel');
- label.textContent = Language.get('wcf.user.' + this.actionName + '.expires.description');
+ label.textContent = Language.get("wcf.user." + this.actionName + ".expires");
+ label = document.getElementById("wcfUiUserEditorExpiresLabel");
+ label.textContent = Language.get("wcf.user." + this.actionName + ".expires.description");
},
},
source: `<div class="section">
<dl>
- <dt><label for="wcfUiUserEditorReason">${Language.get('wcf.global.reason')}</label></dt>
+ <dt><label for="wcfUiUserEditorReason">${Language.get("wcf.global.reason")}</label></dt>
<dd><textarea id="wcfUiUserEditorReason" cols="40" rows="3"></textarea><small></small></dd>
</dl>
<dl>
</dl>
</div>
<div class="formSubmit">
- <button class="buttonPrimary">${Language.get('wcf.global.button.submit')}</button>
+ <button class="buttonPrimary">${Language.get("wcf.global.button.submit")}</button>
</div>`,
};
}
Object.defineProperty(exports, "__esModule", { value: true });
exports.init = void 0;
Listener_1 = tslib_1.__importDefault(Listener_1);
- const _availableMessages = document.getElementsByClassName('ignoredUserMessage');
+ const _availableMessages = document.getElementsByClassName("ignoredUserMessage");
const _knownMessages = new Set();
/**
* Adds ignored messages to the collection.
for (let i = 0, length = _availableMessages.length; i < length; i++) {
const message = _availableMessages[i];
if (!_knownMessages.has(message)) {
- message.addEventListener('click', showMessage, { once: true });
+ message.addEventListener("click", showMessage, { once: true });
_knownMessages.add(message);
}
}
function showMessage(event) {
event.preventDefault();
const message = event.currentTarget;
- message.classList.remove('ignoredUserMessage');
+ message.classList.remove("ignoredUserMessage");
_knownMessages.delete(message);
// Firefox selects the entire message on click for no reason
window.getSelection().removeAllRanges();
*/
function init() {
rebuild();
- Listener_1.default.add('WoltLabSuite/Core/Ui/User/Ignore', rebuild);
+ Listener_1.default.add("WoltLabSuite/Core/Ui/User/Ignore", rebuild);
}
exports.init = init;
});
this.pageCount = 0;
this.pageNo = 1;
this.options = Core.extend({
- className: '',
- dialogTitle: '',
+ className: "",
+ dialogTitle: "",
parameters: {},
}, options);
}
* Shows the current or given page.
*/
showPage(pageNo) {
- if (typeof pageNo === 'number') {
+ if (typeof pageNo === "number") {
this.pageNo = +pageNo;
}
if (this.pageCount !== 0 && (this.pageNo < 1 || this.pageNo > this.pageCount)) {
if (this.cache.has(this.pageNo)) {
const dialog = Dialog_1.default.open(this, this.cache.get(this.pageNo));
if (this.pageCount > 1) {
- const element = dialog.content.querySelector('.jsPagination');
+ const element = dialog.content.querySelector(".jsPagination");
if (element !== null) {
new Pagination_1.default(element, {
activePage: this.pageNo,
_ajaxSetup() {
return {
data: {
- actionName: 'getGroupedUserList',
+ actionName: "getGroupedUserList",
className: this.options.className,
- interfaceName: 'wcf\\data\\IGroupedUserListAction',
+ interfaceName: "wcf\\data\\IGroupedUserListAction",
},
};
}
Input_1 = tslib_1.__importDefault(Input_1);
class UiUserSearchInput extends Input_1.default {
constructor(element, options) {
- const includeUserGroups = (Core.isPlainObject(options) && options.includeUserGroups === true);
+ const includeUserGroups = Core.isPlainObject(options) && options.includeUserGroups === true;
options = Core.extend({
ajax: {
- className: 'wcf\\data\\user\\UserAction',
+ className: "wcf\\data\\user\\UserAction",
parameters: {
data: {
- includeUserGroups: (includeUserGroups ? 1 : 0),
+ includeUserGroups: includeUserGroups ? 1 : 0,
},
},
},
createListItem(item) {
const listItem = super.createListItem(item);
listItem.dataset.type = item.type;
- const box = document.createElement('div');
- box.className = 'box16';
- box.innerHTML = (item.type === 'group') ? '<span class="icon icon16 fa-users"></span>' : item.icon;
+ const box = document.createElement("div");
+ box.className = "box16";
+ box.innerHTML = item.type === "group" ? '<span class="icon icon16 fa-users"></span>' : item.icon;
box.appendChild(listItem.children[0]);
listItem.appendChild(box);
return listItem;
this.currentPageNo = 0;
this.currentUser = 0;
this.knownElements = new WeakSet();
- Listener_1.default.add('WoltLabSuite/Core/Ui/User/Trophy/List', this.rebuild.bind(this));
+ Listener_1.default.add("WoltLabSuite/Core/Ui/User/Trophy/List", this.rebuild.bind(this));
this.rebuild();
}
/**
* Adds event userTrophyOverlayList elements.
*/
rebuild() {
- document.querySelectorAll('.userTrophyOverlayList').forEach((element) => {
+ document.querySelectorAll(".userTrophyOverlayList").forEach((element) => {
if (!this.knownElements.has(element)) {
- element.addEventListener('click', (ev) => this.open(element, ev));
+ element.addEventListener("click", (ev) => this.open(element, ev));
this.knownElements.add(element);
}
});
}
if (data && data.has(this.currentPageNo)) {
const dialog = Dialog_1.default.open(this, data.get(this.currentPageNo));
- Dialog_1.default.setTitle('userTrophyListOverlay', data.title);
+ Dialog_1.default.setTitle("userTrophyListOverlay", data.title);
if (data.pageCount > 1) {
- const element = dialog.content.querySelector('.jsPagination');
+ const element = dialog.content.querySelector(".jsPagination");
if (element !== null) {
new Pagination_1.default(element, {
activePage: this.currentPageNo,
_ajaxSetup() {
return {
data: {
- actionName: 'getGroupedUserTrophyList',
- className: 'wcf\\data\\user\\trophy\\UserTrophyAction',
+ actionName: "getGroupedUserTrophyList",
+ className: "wcf\\data\\user\\trophy\\UserTrophyAction",
},
};
}
_dialogSetup() {
return {
- id: 'userTrophyListOverlay',
+ id: "userTrophyListOverlay",
options: {
title: "",
},
*/
init(userId, username, link) {
if (user) {
- throw new Error('User has already been initialized.');
+ throw new Error("User has already been initialized.");
}
user = new User(userId, username, link);
},
* @module WoltLabSuite/Core/Ajax
*/
-import AjaxRequest from './Ajax/Request';
-import { AjaxCallbackObject, CallbackSuccess, CallbackFailure, RequestData, RequestOptions } from './Ajax/Data';
+import AjaxRequest from "./Ajax/Request";
+import { AjaxCallbackObject, CallbackSuccess, CallbackFailure, RequestData, RequestOptions } from "./Ajax/Data";
const _cache = new WeakMap();
* Shorthand function to perform a request against the WCF-API with overrides
* for success and failure callbacks.
*/
-export function api(callbackObject: AjaxCallbackObject, data?: RequestData, success?: CallbackSuccess, failure?: CallbackFailure): AjaxRequest {
- if (typeof data !== 'object') data = {};
+export function api(
+ callbackObject: AjaxCallbackObject,
+ data?: RequestData,
+ success?: CallbackSuccess,
+ failure?: CallbackFailure
+): AjaxRequest {
+ if (typeof data !== "object") data = {};
let request = _cache.get(callbackObject);
if (request === undefined) {
- if (typeof callbackObject._ajaxSetup !== 'function') {
+ if (typeof callbackObject._ajaxSetup !== "function") {
throw new TypeError("Callback object must implement at least _ajaxSetup().");
}
options.callbackObject = callbackObject;
if (!options.url) {
- options.url = 'index.php?ajax-proxy/&t=' + window.SECURITY_TOKEN;
+ options.url = "index.php?ajax-proxy/&t=" + window.SECURITY_TOKEN;
options.withCredentials = true;
}
let oldSuccess = null;
let oldFailure = null;
- if (typeof success === 'function') {
- oldSuccess = request.getOption('success');
- request.setOption('success', success);
+ if (typeof success === "function") {
+ oldSuccess = request.getOption("success");
+ request.setOption("success", success);
}
- if (typeof failure === 'function') {
- oldFailure = request.getOption('failure');
- request.setOption('failure', failure);
+ if (typeof failure === "function") {
+ oldFailure = request.getOption("failure");
+ request.setOption("failure", failure);
}
request.setData(data);
request.sendRequest();
// restore callbacks
- if (oldSuccess !== null) request.setOption('success', oldSuccess);
- if (oldFailure !== null) request.setOption('failure', oldFailure);
+ if (oldSuccess !== null) request.setOption("success", oldSuccess);
+ if (oldFailure !== null) request.setOption("failure", oldFailure);
return request;
}
options.pinData = false;
options.callbackObject = null;
if (!options.url) {
- options.url = 'index.php?ajax-proxy/&t=' + window.SECURITY_TOKEN;
+ options.url = "index.php?ajax-proxy/&t=" + window.SECURITY_TOKEN;
options.withCredentials = true;
}
*/
export function getRequestObject(callbackObject: AjaxCallbackObject): AjaxRequest {
if (!_cache.has(callbackObject)) {
- throw new Error('Expected a previously used callback object, provided object is unknown.');
+ throw new Error("Expected a previously used callback object, provided object is unknown.");
}
return _cache.get(callbackObject);
};
}
-
export type RequestData = FormData | RequestPayload | DatabaseObjectActionPayload;
export interface ResponseData {
export interface DatabaseObjectActionResponse extends ResponseData {
actionName: string;
objectIDs: number[];
- returnValues: {
- [key: string]: any;
- } | any[];
+ returnValues:
+ | {
+ [key: string]: any;
+ }
+ | any[];
}
-export type CallbackFailure = (data: ResponseData, responseText: string, xhr: XMLHttpRequest, requestData: RequestData) => boolean;
+export type CallbackFailure = (
+ data: ResponseData,
+ responseText: string,
+ xhr: XMLHttpRequest,
+ requestData: RequestData
+) => boolean;
export type CallbackFinalize = (xhr: XMLHttpRequest) => void;
export type CallbackProgress = (event: ProgressEvent) => void;
-export type CallbackSuccess = (data: ResponseData | DatabaseObjectActionResponse, responseText: string, xhr: XMLHttpRequest, requestData: RequestData) => void;
+export type CallbackSuccess = (
+ data: ResponseData | DatabaseObjectActionResponse,
+ responseText: string,
+ xhr: XMLHttpRequest,
+ requestData: RequestData
+) => void;
export type CallbackUploadProgress = (event: ProgressEvent) => void;
export type CallbackSetup = () => RequestOptions;
export interface RequestOptions {
// request data
- data?: RequestData,
- contentType?: string,
- responseType?: string,
- type?: string,
- url?: string,
- withCredentials?: boolean,
+ data?: RequestData;
+ contentType?: string;
+ responseType?: string;
+ type?: string;
+ url?: string;
+ withCredentials?: boolean;
// behavior
- autoAbort?: boolean,
- ignoreError?: boolean,
- pinData?: boolean,
- silent?: boolean,
- includeRequestedWith?: boolean,
+ autoAbort?: boolean;
+ ignoreError?: boolean;
+ pinData?: boolean;
+ silent?: boolean;
+ includeRequestedWith?: boolean;
// callbacks
- failure?: CallbackFailure,
- finalize?: CallbackFinalize,
- success?: CallbackSuccess,
- progress?: CallbackProgress,
- uploadProgress?: CallbackUploadProgress,
+ failure?: CallbackFailure;
+ finalize?: CallbackFinalize;
+ success?: CallbackSuccess;
+ progress?: CallbackProgress;
+ uploadProgress?: CallbackUploadProgress;
- callbackObject?: AjaxCallbackObject | null,
+ callbackObject?: AjaxCallbackObject | null;
}
* @module WoltLabSuite/Core/Ajax/Jsonp
*/
-import * as Core from '../Core';
+import * as Core from "../Core";
/**
* Dispatch a JSONP request, the `url` must not contain a callback parameter.
*/
-export function send(url: string, success: (...args: unknown[]) => void, failure: () => void, options?: JsonpOptions): void {
- url = (typeof (url as any) === 'string') ? url.trim() : '';
+export function send(
+ url: string,
+ success: (...args: unknown[]) => void,
+ failure: () => void,
+ options?: JsonpOptions
+): void {
+ url = typeof (url as any) === "string" ? url.trim() : "";
if (url.length === 0) {
- throw new Error('Expected a non-empty string for parameter \'url\'.');
+ throw new Error("Expected a non-empty string for parameter 'url'.");
}
- if (typeof success !== 'function') {
- throw new TypeError('Expected a valid callback function for parameter \'success\'.');
+ if (typeof success !== "function") {
+ throw new TypeError("Expected a valid callback function for parameter 'success'.");
}
- options = Core.extend({
- parameterName: 'callback',
- timeout: 10,
- }, options || {}) as JsonpOptions;
+ options = Core.extend(
+ {
+ parameterName: "callback",
+ timeout: 10,
+ },
+ options || {}
+ ) as JsonpOptions;
- const callbackName = 'wcf_jsonp_' + Core.getUuid().replace(/-/g, '').substr(0, 8);
+ const callbackName = "wcf_jsonp_" + Core.getUuid().replace(/-/g, "").substr(0, 8);
let script;
const timeout = window.setTimeout(() => {
- if (typeof failure === 'function') {
+ if (typeof failure === "function") {
failure();
}
script.remove();
};
- url += (url.indexOf('?') === -1) ? '?' : '&';
- url += options.parameterName + '=' + callbackName;
+ url += url.indexOf("?") === -1 ? "?" : "&";
+ url += options.parameterName + "=" + callbackName;
- script = document.createElement('script');
+ script = document.createElement("script");
script.async = true;
script.src = url;
* @module WoltLabSuite/Core/Ajax/Request
*/
-import * as AjaxStatus from './Status';
-import { ResponseData, RequestOptions, RequestData } from './Data';
-import * as Core from '../Core';
-import DomChangeListener from '../Dom/Change/Listener';
-import DomUtil from '../Dom/Util';
-import * as Language from '../Language';
+import * as AjaxStatus from "./Status";
+import { ResponseData, RequestOptions, RequestData } from "./Data";
+import * as Core from "../Core";
+import DomChangeListener from "../Dom/Change/Listener";
+import DomUtil from "../Dom/Util";
+import * as Language from "../Language";
let _didInit = false;
let _ignoreAllErrors = false;
private _xhr?: XMLHttpRequest;
constructor(options: RequestOptions) {
- this._options = Core.extend({
- data: {},
- contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
- responseType: 'application/json',
- type: 'POST',
- url: '',
- withCredentials: false,
-
- // behavior
- autoAbort: false,
- ignoreError: false,
- pinData: false,
- silent: false,
- includeRequestedWith: true,
-
- // callbacks
- failure: null,
- finalize: null,
- success: null,
- progress: null,
- uploadProgress: null,
-
- callbackObject: null,
- }, options);
-
- if (typeof options.callbackObject === 'object') {
+ this._options = Core.extend(
+ {
+ data: {},
+ contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+ responseType: "application/json",
+ type: "POST",
+ url: "",
+ withCredentials: false,
+
+ // behavior
+ autoAbort: false,
+ ignoreError: false,
+ pinData: false,
+ silent: false,
+ includeRequestedWith: true,
+
+ // callbacks
+ failure: null,
+ finalize: null,
+ success: null,
+ progress: null,
+ uploadProgress: null,
+
+ callbackObject: null,
+ },
+ options
+ );
+
+ if (typeof options.callbackObject === "object") {
this._options.callbackObject = options.callbackObject;
}
this._options.url = Core.convertLegacyUrl(this._options.url!);
- if (this._options.url.indexOf('index.php') === 0) {
+ if (this._options.url.indexOf("index.php") === 0) {
this._options.url = window.WSC_API_URL + this._options.url;
}
}
if (this._options.callbackObject) {
- if (typeof this._options.callbackObject._ajaxFailure === 'function') this._options.failure = this._options.callbackObject._ajaxFailure.bind(this._options.callbackObject);
- if (typeof this._options.callbackObject._ajaxFinalize === 'function') this._options.finalize = this._options.callbackObject._ajaxFinalize.bind(this._options.callbackObject);
- if (typeof this._options.callbackObject._ajaxSuccess === 'function') this._options.success = this._options.callbackObject._ajaxSuccess.bind(this._options.callbackObject);
- if (typeof this._options.callbackObject._ajaxProgress === 'function') this._options.progress = this._options.callbackObject._ajaxProgress.bind(this._options.callbackObject);
- if (typeof this._options.callbackObject._ajaxUploadProgress === 'function') this._options.uploadProgress = this._options.callbackObject._ajaxUploadProgress.bind(this._options.callbackObject);
+ if (typeof this._options.callbackObject._ajaxFailure === "function")
+ this._options.failure = this._options.callbackObject._ajaxFailure.bind(this._options.callbackObject);
+ if (typeof this._options.callbackObject._ajaxFinalize === "function")
+ this._options.finalize = this._options.callbackObject._ajaxFinalize.bind(this._options.callbackObject);
+ if (typeof this._options.callbackObject._ajaxSuccess === "function")
+ this._options.success = this._options.callbackObject._ajaxSuccess.bind(this._options.callbackObject);
+ if (typeof this._options.callbackObject._ajaxProgress === "function")
+ this._options.progress = this._options.callbackObject._ajaxProgress.bind(this._options.callbackObject);
+ if (typeof this._options.callbackObject._ajaxUploadProgress === "function")
+ this._options.uploadProgress = this._options.callbackObject._ajaxUploadProgress.bind(
+ this._options.callbackObject
+ );
}
if (!_didInit) {
_didInit = true;
- window.addEventListener('beforeunload', () => _ignoreAllErrors = true);
+ window.addEventListener("beforeunload", () => (_ignoreAllErrors = true));
}
}
this._xhr = new XMLHttpRequest();
this._xhr.open(this._options.type!, this._options.url!, true);
if (this._options.contentType) {
- this._xhr.setRequestHeader('Content-Type', this._options.contentType);
+ this._xhr.setRequestHeader("Content-Type", this._options.contentType);
}
if (this._options.withCredentials || this._options.includeRequestedWith) {
- this._xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
+ this._xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
}
if (this._options.withCredentials) {
this._xhr.withCredentials = true;
const options = Core.clone(this._options) as RequestOptions;
this._xhr.onload = function () {
if (this.readyState === XMLHttpRequest.DONE) {
- if (this.status >= 200 && this.status < 300 || this.status === 304) {
- if (options.responseType && this.getResponseHeader('Content-Type')!.indexOf(options.responseType) !== 0) {
+ if ((this.status >= 200 && this.status < 300) || this.status === 304) {
+ if (options.responseType && this.getResponseHeader("Content-Type")!.indexOf(options.responseType) !== 0) {
// request succeeded but invalid response type
self._failure(this, options);
} else {
this._xhr.upload.onprogress = this._options.uploadProgress;
}
- if (this._options.type === 'POST') {
+ if (this._options.type === "POST") {
let data: string | RequestData = this._options.data!;
- if (typeof data === 'object' && Core.getType(data) !== 'FormData') {
+ if (typeof data === "object" && Core.getType(data) !== "FormData") {
data = Core.serialize(data);
}
* Sets request data while honoring pinned data from setup callback.
*/
setData(data: RequestData): void {
- if (this._data !== null && Core.getType(data) !== 'FormData') {
+ if (this._data !== null && Core.getType(data) !== "FormData") {
data = Core.extend(this._data, data);
}
AjaxStatus.hide();
}
- if (typeof options.success === 'function') {
+ if (typeof options.success === "function") {
let data: ResponseData | null = null;
- if (xhr.getResponseHeader('Content-Type')!.split(';', 1)[0].trim() === 'application/json') {
+ if (xhr.getResponseHeader("Content-Type")!.split(";", 1)[0].trim() === "application/json") {
try {
data = JSON.parse(xhr.responseText) as ResponseData;
} catch (e) {
// force-invoke the background queue
if (data && data.forceBackgroundQueuePerform) {
- import('../BackgroundQueue').then(backgroundQueue => backgroundQueue.invoke());
+ import("../BackgroundQueue").then((backgroundQueue) => backgroundQueue.invoke());
}
}
let data: ResponseData | null = null;
try {
data = JSON.parse(xhr.responseText);
- } catch (e) {
- }
+ } catch (e) {}
let showError = true;
- if (typeof options.failure === 'function') {
- showError = options.failure((data || {}), (xhr.responseText || ''), xhr, options.data!);
+ if (typeof options.failure === "function") {
+ showError = options.failure(data || {}, xhr.responseText || "", xhr, options.data!);
}
if (options.ignoreError !== true && showError) {
const html = this.getErrorHtml(data, xhr);
if (html) {
- import('../Ui/Dialog').then(UiDialog => {
+ import("../Ui/Dialog").then((UiDialog) => {
UiDialog.openStatic(DomUtil.getUniqueId(), html, {
- title: Language.get('wcf.global.error.title'),
+ title: Language.get("wcf.global.error.title"),
});
});
}
* Returns the inner HTML for an error/exception display.
*/
getErrorHtml(data: ResponseData | null, xhr: XMLHttpRequest): string | null {
- let details = '';
+ let details = "";
let message: string;
if (data !== null) {
if (data.returnValues && data.returnValues.description) {
- details += '<br><p>Description:</p><p>' + data.returnValues.description + '</p>';
+ details += "<br><p>Description:</p><p>" + data.returnValues.description + "</p>";
}
if (data.file && data.line) {
- details += '<br><p>File:</p><p>' + data.file + ' in line ' + data.line + '</p>';
+ details += "<br><p>File:</p><p>" + data.file + " in line " + data.line + "</p>";
}
- if (data.stacktrace) details += '<br><p>Stacktrace:</p><p>' + data.stacktrace + '</p>';
- else if (data.exceptionID) details += '<br><p>Exception ID: <code>' + data.exceptionID + '</code></p>';
+ if (data.stacktrace) details += "<br><p>Stacktrace:</p><p>" + data.stacktrace + "</p>";
+ else if (data.exceptionID) details += "<br><p>Exception ID: <code>" + data.exceptionID + "</code></p>";
message = data.message;
data.previous.forEach(function (previous) {
- details += '<hr><p>' + previous.message + '</p>';
- details += '<br><p>Stacktrace</p><p>' + previous.stacktrace + '</p>';
+ details += "<hr><p>" + previous.message + "</p>";
+ details += "<br><p>Stacktrace</p><p>" + previous.stacktrace + "</p>";
});
} else {
message = xhr.responseText;
}
- if (!message || message === 'undefined') {
+ if (!message || message === "undefined") {
if (!window.ENABLE_DEBUG_MODE) return null;
- message = 'XMLHttpRequest failed without a responseText. Check your browser console.';
+ message = "XMLHttpRequest failed without a responseText. Check your browser console.";
}
- return '<div class="ajaxDebugMessage"><p>' + message + '</p>' + details + '</div>';
+ return '<div class="ajaxDebugMessage"><p>' + message + "</p>" + details + "</div>";
}
/**
* @param {Object} options request options
*/
_finalize(options: RequestOptions): void {
- if (typeof options.finalize === 'function') {
+ if (typeof options.finalize === "function") {
options.finalize(this._xhr!);
}
// fix anchor tags generated through WCF::getAnchor()
document.querySelectorAll('a[href*="#"]').forEach((link: HTMLAnchorElement) => {
let href = link.href;
- if (href.indexOf('AJAXProxy') !== -1 || href.indexOf('ajax-proxy') !== -1) {
- href = href.substr(href.indexOf('#'));
- link.href = document.location.toString().replace(/#.*/, '') + href;
+ if (href.indexOf("AJAXProxy") !== -1 || href.indexOf("ajax-proxy") !== -1) {
+ href = href.substr(href.indexOf("#"));
+ link.href = document.location.toString().replace(/#.*/, "") + href;
}
});
}
* @module WoltLabSuite/Core/Ajax/Status
*/
-import * as Language from '../Language';
+import * as Language from "../Language";
class AjaxStatus {
private _activeRequests = 0;
private readonly _overlay: Element;
private _timer: number | null = null;
-
+
constructor() {
- this._overlay = document.createElement('div');
- this._overlay.classList.add('spinner');
- this._overlay.setAttribute('role', 'status');
+ this._overlay = document.createElement("div");
+ this._overlay.classList.add("spinner");
+ this._overlay.setAttribute("role", "status");
- const icon = document.createElement('span');
- icon.className = 'icon icon48 fa-spinner';
+ const icon = document.createElement("span");
+ icon.className = "icon icon48 fa-spinner";
this._overlay.appendChild(icon);
- const title = document.createElement('span');
- title.textContent = Language.get('wcf.global.loading');
+ const title = document.createElement("span");
+ title.textContent = Language.get("wcf.global.loading");
this._overlay.appendChild(title);
document.body.appendChild(this._overlay);
}
-
+
show(): void {
this._activeRequests++;
if (this._timer === null) {
this._timer = window.setTimeout(() => {
if (this._activeRequests) {
- this._overlay.classList.add('active');
+ this._overlay.classList.add("active");
}
this._timer = null;
}, 250);
}
}
-
+
hide(): void {
if (--this._activeRequests === 0) {
if (this._timer !== null) {
window.clearTimeout(this._timer);
}
- this._overlay.classList.remove('active');
+ this._overlay.classList.remove("active");
}
}
}
if (status === undefined) {
status = new AjaxStatus();
}
-
+
return status;
}
* @module WoltLabSuite/Core/BackgroundQueue
*/
-import * as Ajax from './Ajax';
-import { AjaxCallbackObject, RequestOptions, ResponseData } from './Ajax/Data';
+import * as Ajax from "./Ajax";
+import { AjaxCallbackObject, RequestOptions, ResponseData } from "./Ajax/Data";
class BackgroundQueue implements AjaxCallbackObject {
private _invocations = 0;
this._invocations++;
// invoke the queue up to 5 times in a row
- if ((data as unknown) as number > 0 && this._invocations < 5) {
+ if (((data as unknown) as number) > 0 && this._invocations < 5) {
window.setTimeout(() => {
this._isBusy = false;
this.invoke();
*/
export function invoke(): void {
if (!queue) {
- console.error('The background queue has not been initialized yet.');
+ console.error("The background queue has not been initialized yet.");
return;
}
* Adds a callback for given identifier.
*/
add(identifier: string, callback: Callback): void {
- if (typeof callback !== 'function') {
- throw new TypeError('Expected a valid callback as second argument for identifier \'' + identifier + '\'.');
+ if (typeof callback !== "function") {
+ throw new TypeError("Expected a valid callback as second argument for identifier '" + identifier + "'.");
}
if (!this._callbacks.has(identifier)) {
* @see https://secure.wikimedia.org/wikipedia/de/wiki/HSV-Farbraum#Transformation_von_RGB_und_HSV
*/
export function hsvToRgb(h: number, s: number, v: number): RGB {
- const rgb: RGB = {r: 0, g: 0, b: 0};
+ const rgb: RGB = { r: 0, g: 0, b: 0 };
let h2: number, f: number, p: number, q: number, t: number;
h2 = Math.floor(h / 60);
export function hexToRgb(hex: string): RGB | typeof Number.NaN {
if (/^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(hex)) {
// only convert #abc and #abcdef
- const parts = hex.split('');
+ const parts = hex.split("");
// drop the hashtag
- if (parts[0] === '#') {
+ if (parts[0] === "#") {
parts.shift();
}
// parse shorthand #xyz
if (parts.length === 3) {
return {
- r: parseInt(parts[0] + '' + parts[0], 16),
- g: parseInt(parts[1] + '' + parts[1], 16),
- b: parseInt(parts[2] + '' + parts[2], 16),
+ r: parseInt(parts[0] + "" + parts[0], 16),
+ g: parseInt(parts[1] + "" + parts[1], 16),
+ b: parseInt(parts[2] + "" + parts[2], 16),
};
} else {
return {
- r: parseInt(parts[0] + '' + parts[1], 16),
- g: parseInt(parts[2] + '' + parts[3], 16),
- b: parseInt(parts[4] + '' + parts[5], 16),
+ r: parseInt(parts[0] + "" + parts[1], 16),
+ g: parseInt(parts[2] + "" + parts[3], 16),
+ b: parseInt(parts[4] + "" + parts[5], 16),
};
}
}
* @see http://www.linuxtopia.org/online_books/javascript_guides/javascript_faq/rgbtohex.htm
*/
export function rgbToHex(r: number, g: number, b: number): string {
- const charList = '0123456789ABCDEF';
+ const charList = "0123456789ABCDEF";
if (g === undefined) {
if (r.toString().match(/^rgba?\((\d+), ?(\d+), ?(\d+)(?:, ?[0-9.]+)?\)$/)) {
}
}
- return (charList.charAt((r - r % 16) / 16) + '' + charList.charAt(r % 16)) + '' + (charList.charAt((g - g % 16) / 16) + '' + charList.charAt(g % 16)) + '' + (charList.charAt((b - b % 16) / 16) + '' + charList.charAt(b % 16));
+ return (
+ charList.charAt((r - (r % 16)) / 16) +
+ "" +
+ charList.charAt(r % 16) +
+ "" +
+ (charList.charAt((g - (g % 16)) / 16) + "" + charList.charAt(g % 16)) +
+ "" +
+ (charList.charAt((b - (b % 16)) / 16) + "" + charList.charAt(b % 16))
+ );
}
interface RGB {
*/
const _clone = function (variable: any): any {
- if (typeof variable === 'object' && (Array.isArray(variable) || isPlainObject(variable))) {
+ if (typeof variable === "object" && (Array.isArray(variable) || isPlainObject(variable))) {
return _cloneObject(variable);
}
}
const newObj = {};
- Object.keys(obj).forEach(key => newObj[key] = _clone(obj[key]));
+ Object.keys(obj).forEach((key) => (newObj[key] = _clone(obj[key])));
return newObj;
};
-const _prefix = 'wsc' + window.WCF_PATH.hashCode() + '-';
+const _prefix = "wsc" + window.WCF_PATH.hashCode() + "-";
/**
* Deep clones an object.
export function convertLegacyUrl(url: string): string {
return url.replace(/^index\.php\/(.*?)\/\?/, (match: string, controller: string) => {
const parts = controller.split(/([A-Z][a-z0-9]+)/);
- controller = '';
+ controller = "";
for (let i = 0, length = parts.length; i < length; i++) {
const part = parts[i].trim();
if (part.length) {
- if (controller.length) controller += '-';
+ if (controller.length) controller += "-";
controller += part.toLowerCase();
}
}
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
- if (!Array.isArray(obj[key]) && typeof obj[key] === 'object') {
+ if (!Array.isArray(obj[key]) && typeof obj[key] === "object") {
if (isPlainObject(obj[key])) {
// object literals have the prototype of Object which in return has no parent prototype
newObj[key] = extend(out[key], obj[key]);
* function MyDerivedClass() {}
* Core.inherit(MyDerivedClass, TheAwesomeBaseClass, {
* // regular prototype for `MyDerivedClass`
- *
+ *
* overwrittenMethodFromBaseClass: function(foo, bar) {
* // do stuff
- *
+ *
* // invoke parent
* MyDerivedClass._super.prototype.overwrittenMethodFromBaseClass.call(this, foo, bar);
* }
*
* @see https://github.com/nodejs/node/blob/7d14dd9b5e78faabb95d454a79faa513d0bbc2a5/lib/util.js#L697-L735
*/
-export function inherit(constructor: new() => any, superConstructor: new() => any, propertiesObject: object): void {
+export function inherit(constructor: new () => any, superConstructor: new () => any, propertiesObject: object): void {
if (constructor === undefined || constructor === null) {
- throw new TypeError('The constructor must not be undefined or null.');
+ throw new TypeError("The constructor must not be undefined or null.");
}
if (superConstructor === undefined || superConstructor === null) {
- throw new TypeError('The super constructor must not be undefined or null.');
+ throw new TypeError("The super constructor must not be undefined or null.");
}
if (superConstructor.prototype === undefined) {
- throw new TypeError('The super constructor must have a prototype.');
+ throw new TypeError("The super constructor must have a prototype.");
}
(constructor as any)._super = superConstructor;
- constructor.prototype = extend(Object.create(superConstructor.prototype, {
- constructor: {
- configurable: true,
- enumerable: false,
- value: constructor,
- writable: true,
- },
- }), propertiesObject || {});
+ constructor.prototype = extend(
+ Object.create(superConstructor.prototype, {
+ constructor: {
+ configurable: true,
+ enumerable: false,
+ value: constructor,
+ writable: true,
+ },
+ }),
+ propertiesObject || {}
+ );
}
/**
* Returns true if `obj` is an object literal.
*/
export function isPlainObject(obj: any): boolean {
- if (typeof obj !== 'object' || obj === null || obj.nodeType) {
+ if (typeof obj !== "object" || obj === null || obj.nodeType) {
return false;
}
- return (Object.getPrototypeOf(obj) === Object.prototype);
+ return Object.getPrototypeOf(obj) === Object.prototype;
}
/**
* Returns the object's class name.
*/
export function getType(obj: object): string {
- return Object.prototype.toString.call(obj).replace(/^\[object (.+)]$/, '$1');
+ return Object.prototype.toString.call(obj).replace(/^\[object (.+)]$/, "$1");
}
/**
* @see http://stackoverflow.com/a/2117523
*/
export function getUuid(): string {
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
- const r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
+ const r = (Math.random() * 16) | 0,
+ v = c == "x" ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
- const parameterKey = (prefix) ? prefix + '[' + key + ']' : key;
+ const parameterKey = prefix ? prefix + "[" + key + "]" : key;
const value = obj[key];
- if (typeof value === 'object') {
+ if (typeof value === "object") {
parameters.push(serialize(value, parameterKey));
} else {
- parameters.push(encodeURIComponent(parameterKey) + '=' + encodeURIComponent(value));
+ parameters.push(encodeURIComponent(parameterKey) + "=" + encodeURIComponent(value));
}
}
}
- return parameters.join('&');
+ return parameters.join("&");
}
/**
* legacy functions `elAttrBool()` and `elDataBool()`.
*/
export function stringToBool(value: string | null): boolean {
- return value === '1' || value === 'true';
+ return value === "1" || value === "true";
}
-
type DebounceCallback = (...args: any[]) => void;
interface DebounceOptions {
waitMilliseconds = 50,
options: DebounceOptions = {
isImmediate: false,
- },
+ }
): (this: ThisParameterType<F>, ...args: Parameters<F>) => void {
let timeoutId: ReturnType<typeof setTimeout> | undefined;
* @module WoltLabSuite/Core/Date/Picker
*/
-import * as Core from '../Core';
-import * as DateUtil from './Util';
-import DomChangeListener from '../Dom/Change/Listener';
-import * as EventHandler from '../Event/Handler';
-import * as Language from '../Language';
-import * as UiAlignment from '../Ui/Alignment';
-import UiCloseOverlay from '../Ui/CloseOverlay';
-import DomUtil from '../Dom/Util';
+import * as Core from "../Core";
+import * as DateUtil from "./Util";
+import DomChangeListener from "../Dom/Change/Listener";
+import * as EventHandler from "../Event/Handler";
+import * as Language from "../Language";
+import * as UiAlignment from "../Ui/Alignment";
+import UiCloseOverlay from "../Ui/CloseOverlay";
+import DomUtil from "../Dom/Util";
let _didInit = false;
let _firstDayOfWeek = 0;
return;
}
- _datePicker = document.createElement('div');
- _datePicker.className = 'datePicker';
- _datePicker.addEventListener('click', event => {
+ _datePicker = document.createElement("div");
+ _datePicker.className = "datePicker";
+ _datePicker.addEventListener("click", (event) => {
event.stopPropagation();
});
- const header = document.createElement('header');
+ const header = document.createElement("header");
_datePicker.appendChild(header);
- _dateMonthPrevious = document.createElement('a');
- _dateMonthPrevious.className = 'previous jsTooltip';
- _dateMonthPrevious.href = '#';
- _dateMonthPrevious.setAttribute('role', 'button');
+ _dateMonthPrevious = document.createElement("a");
+ _dateMonthPrevious.className = "previous jsTooltip";
+ _dateMonthPrevious.href = "#";
+ _dateMonthPrevious.setAttribute("role", "button");
_dateMonthPrevious.tabIndex = 0;
- _dateMonthPrevious.title = Language.get('wcf.date.datePicker.previousMonth');
- _dateMonthPrevious.setAttribute('aria-label', Language.get('wcf.date.datePicker.previousMonth'));
+ _dateMonthPrevious.title = Language.get("wcf.date.datePicker.previousMonth");
+ _dateMonthPrevious.setAttribute("aria-label", Language.get("wcf.date.datePicker.previousMonth"));
_dateMonthPrevious.innerHTML = '<span class="icon icon16 fa-arrow-left"></span>';
- _dateMonthPrevious.addEventListener('click', DatePicker.previousMonth);
+ _dateMonthPrevious.addEventListener("click", DatePicker.previousMonth);
header.appendChild(_dateMonthPrevious);
- const monthYearContainer = document.createElement('span');
+ const monthYearContainer = document.createElement("span");
header.appendChild(monthYearContainer);
- _dateMonth = document.createElement('select');
- _dateMonth.className = 'month jsTooltip';
- _dateMonth.title = Language.get('wcf.date.datePicker.month');
- _dateMonth.setAttribute('aria-label', Language.get('wcf.date.datePicker.month'));
- _dateMonth.addEventListener('change', changeMonth);
+ _dateMonth = document.createElement("select");
+ _dateMonth.className = "month jsTooltip";
+ _dateMonth.title = Language.get("wcf.date.datePicker.month");
+ _dateMonth.setAttribute("aria-label", Language.get("wcf.date.datePicker.month"));
+ _dateMonth.addEventListener("change", changeMonth);
monthYearContainer.appendChild(_dateMonth);
- let months = '';
- const monthNames = Language.get('__monthsShort');
+ let months = "";
+ const monthNames = Language.get("__monthsShort");
for (let i = 0; i < 12; i++) {
- months += '<option value="' + i + '">' + monthNames[i] + '</option>';
+ months += '<option value="' + i + '">' + monthNames[i] + "</option>";
}
_dateMonth.innerHTML = months;
- _dateYear = document.createElement('select');
- _dateYear.className = 'year jsTooltip';
- _dateYear.title = Language.get('wcf.date.datePicker.year');
- _dateYear.setAttribute('aria-label', Language.get('wcf.date.datePicker.year'));
- _dateYear.addEventListener('change', changeYear);
+ _dateYear = document.createElement("select");
+ _dateYear.className = "year jsTooltip";
+ _dateYear.title = Language.get("wcf.date.datePicker.year");
+ _dateYear.setAttribute("aria-label", Language.get("wcf.date.datePicker.year"));
+ _dateYear.addEventListener("change", changeYear);
monthYearContainer.appendChild(_dateYear);
- _dateMonthNext = document.createElement('a');
- _dateMonthNext.className = 'next jsTooltip';
- _dateMonthNext.href = '#';
- _dateMonthNext.setAttribute('role', 'button');
+ _dateMonthNext = document.createElement("a");
+ _dateMonthNext.className = "next jsTooltip";
+ _dateMonthNext.href = "#";
+ _dateMonthNext.setAttribute("role", "button");
_dateMonthNext.tabIndex = 0;
- _dateMonthNext.title = Language.get('wcf.date.datePicker.nextMonth');
- _dateMonthNext.setAttribute('aria-label', Language.get('wcf.date.datePicker.nextMonth'));
+ _dateMonthNext.title = Language.get("wcf.date.datePicker.nextMonth");
+ _dateMonthNext.setAttribute("aria-label", Language.get("wcf.date.datePicker.nextMonth"));
_dateMonthNext.innerHTML = '<span class="icon icon16 fa-arrow-right"></span>';
- _dateMonthNext.addEventListener('click', DatePicker.nextMonth);
+ _dateMonthNext.addEventListener("click", DatePicker.nextMonth);
header.appendChild(_dateMonthNext);
- _dateGrid = document.createElement('ul');
+ _dateGrid = document.createElement("ul");
_datePicker.appendChild(_dateGrid);
- const item = document.createElement('li');
- item.className = 'weekdays';
+ const item = document.createElement("li");
+ item.className = "weekdays";
_dateGrid.appendChild(item);
- const weekdays = Language.get('__daysShort');
+ const weekdays = Language.get("__daysShort");
for (let i = 0; i < 7; i++) {
let day = i + _firstDayOfWeek;
if (day > 6) day -= 7;
- const span = document.createElement('span');
+ const span = document.createElement("span");
span.textContent = weekdays[day];
item.appendChild(span);
}
// create date grid
for (let i = 0; i < 6; i++) {
- const row = document.createElement('li');
+ const row = document.createElement("li");
_dateGrid.appendChild(row);
for (let j = 0; j < 7; j++) {
- const cell = document.createElement('a');
- cell.addEventListener('click', click);
+ const cell = document.createElement("a");
+ cell.addEventListener("click", click);
_dateCells.push(cell);
row.appendChild(cell);
}
}
- _dateTime = document.createElement('footer');
+ _dateTime = document.createElement("footer");
_datePicker.appendChild(_dateTime);
- _dateHour = document.createElement('select');
- _dateHour.className = 'hour';
- _dateHour.title = Language.get('wcf.date.datePicker.hour');
- _dateHour.setAttribute('aria-label', Language.get('wcf.date.datePicker.hour'));
- _dateHour.addEventListener('change', formatValue);
+ _dateHour = document.createElement("select");
+ _dateHour.className = "hour";
+ _dateHour.title = Language.get("wcf.date.datePicker.hour");
+ _dateHour.setAttribute("aria-label", Language.get("wcf.date.datePicker.hour"));
+ _dateHour.addEventListener("change", formatValue);
const date = new Date(2000, 0, 1);
- const timeFormat = Language.get('wcf.date.timeFormat').replace(/:/, '').replace(/[isu]/g, '');
- let tmp = '';
+ const timeFormat = Language.get("wcf.date.timeFormat").replace(/:/, "").replace(/[isu]/g, "");
+ let tmp = "";
for (let i = 0; i < 24; i++) {
date.setHours(i);
tmp += '<option value="' + i + '">' + DateUtil.format(date, timeFormat) + "</option>";
_dateTime.appendChild(_dateHour);
- _dateTime.appendChild(document.createTextNode('\u00A0:\u00A0'));
+ _dateTime.appendChild(document.createTextNode("\u00A0:\u00A0"));
- _dateMinute = document.createElement('select');
- _dateMinute.className = 'minute';
- _dateMinute.title = Language.get('wcf.date.datePicker.minute');
- _dateMinute.setAttribute('aria-label', Language.get('wcf.date.datePicker.minute'));
- _dateMinute.addEventListener('change', formatValue);
+ _dateMinute = document.createElement("select");
+ _dateMinute.className = "minute";
+ _dateMinute.title = Language.get("wcf.date.datePicker.minute");
+ _dateMinute.setAttribute("aria-label", Language.get("wcf.date.datePicker.minute"));
+ _dateMinute.addEventListener("change", formatValue);
- tmp = '';
+ tmp = "";
for (let i = 0; i < 60; i++) {
- tmp += '<option value="' + i + '">' + (i < 10 ? '0' + i.toString() : i) + '</option>';
+ tmp += '<option value="' + i + '">' + (i < 10 ? "0" + i.toString() : i) + "</option>";
}
_dateMinute.innerHTML = tmp;
document.body.appendChild(_datePicker);
- document.body.addEventListener('focus', maintainFocus, {capture: true});
+ document.body.addEventListener("focus", maintainFocus, { capture: true });
}
/**
* Initializes the minimum/maximum date range.
*/
function initDateRange(element: HTMLInputElement, now: Date, isMinDate: boolean): void {
- const name = isMinDate ? 'minDate' : 'maxDate';
- let value = (element.dataset[name] || '').trim();
+ const name = isMinDate ? "minDate" : "maxDate";
+ let value = (element.dataset[name] || "").trim();
if (value.match(/^(\d{4})-(\d{2})-(\d{2})$/)) {
// YYYY-mm-dd
value = new Date(value).getTime().toString();
- } else if (value === 'now') {
+ } else if (value === "now") {
value = now.getTime().toString();
} else if (value.match(/^\d{1,3}$/)) {
// relative time span in years
value = RegExp.$1;
if (document.getElementById(value) === null) {
- throw new Error("Reference date picker identified by '" + value + "' does not exists (element id: '" + element.id + "').");
+ throw new Error(
+ "Reference date picker identified by '" + value + "' does not exists (element id: '" + element.id + "')."
+ );
}
} else if (/^\d{4}-\d{2}-\d{2}T/.test(value)) {
value = new Date(value).getTime().toString();
} else {
- value = new Date((isMinDate ? 1902 : 2038), 0, 1).getTime().toString();
+ value = new Date(isMinDate ? 1902 : 2038, 0, 1).getTime().toString();
}
element.dataset[name] = value;
if (_didInit) return;
_didInit = true;
- _firstDayOfWeek = parseInt(Language.get('wcf.date.firstDayOfTheWeek'), 10);
+ _firstDayOfWeek = parseInt(Language.get("wcf.date.firstDayOfTheWeek"), 10);
- DomChangeListener.add('WoltLabSuite/Core/Date/Picker', DatePicker.init);
- UiCloseOverlay.add('WoltLabSuite/Core/Date/Picker', close);
+ DomChangeListener.add("WoltLabSuite/Core/Date/Picker", DatePicker.init);
+ UiCloseOverlay.add("WoltLabSuite/Core/Date/Picker", close);
}
function getDateValue(attributeName: string): Date {
- let date = _input!.dataset[attributeName] || '';
+ let date = _input!.dataset[attributeName] || "";
if (date.match(/^datePicker-(.+)$/)) {
const referenceElement = document.getElementById(RegExp.$1);
if (referenceElement === null) {
throw new Error(`Unable to find an element with the id '${RegExp.$1}'.`);
}
- date = referenceElement.dataset.value || '';
+ date = referenceElement.dataset.value || "";
}
return new Date(parseInt(date, 10));
createPicker();
const target = event.currentTarget as HTMLInputElement;
- const input = (target.nodeName === 'INPUT') ? target : target.previousElementSibling as HTMLInputElement;
+ const input = target.nodeName === "INPUT" ? target : (target.previousElementSibling as HTMLInputElement);
if (input === _input) {
close();
return;
}
- const dialogContent = input.closest('.dialogContent') as HTMLElement;
+ const dialogContent = input.closest(".dialogContent") as HTMLElement;
if (dialogContent !== null) {
- if (!Core.stringToBool(dialogContent.dataset.hasDatepickerScrollListener || '')) {
- dialogContent.addEventListener('scroll', onDialogScroll);
- dialogContent.dataset.hasDatepickerScrollListener = '1';
+ if (!Core.stringToBool(dialogContent.dataset.hasDatepickerScrollListener || "")) {
+ dialogContent.addEventListener("scroll", onDialogScroll);
+ dialogContent.dataset.hasDatepickerScrollListener = "1";
}
}
if (value) {
date = new Date(parseInt(value, 10));
- if (date.toString() === 'Invalid Date') {
+ if (date.toString() === "Invalid Date") {
date = new Date();
}
} else {
}
// set min/max date
- _minDate = getDateValue('minDate');
+ _minDate = getDateValue("minDate");
if (_minDate.getTime() > date.getTime()) {
date = _minDate;
}
- _maxDate = getDateValue('maxDate');
+ _maxDate = getDateValue("maxDate");
if (data.isDateTime) {
_dateHour.value = date.getHours().toString();
_dateMinute.value = date.getMinutes().toString();
- _datePicker!.classList.add('datePickerTime');
+ _datePicker!.classList.add("datePickerTime");
} else {
- _datePicker!.classList.remove('datePickerTime');
+ _datePicker!.classList.remove("datePickerTime");
}
- _datePicker!.classList[(data.isTimeOnly) ? 'add' : 'remove']('datePickerTimeOnly');
+ _datePicker!.classList[data.isTimeOnly ? "add" : "remove"]("datePickerTimeOnly");
renderPicker(date.getDate(), date.getMonth(), date.getFullYear());
UiAlignment.set(_datePicker!, _input);
- _input.nextElementSibling!.setAttribute('aria-expanded', 'true');
+ _input.nextElementSibling!.setAttribute("aria-expanded", "true");
_wasInsidePicker = false;
}
* Closes the date picker.
*/
function close() {
- if (_datePicker === null || !_datePicker.classList.contains('active')) {
+ if (_datePicker === null || !_datePicker.classList.contains("active")) {
return;
}
- _datePicker.classList.remove('active');
+ _datePicker.classList.remove("active");
const data = _data.get(_input!) as DatePickerData;
- if (typeof data.onClose === 'function') {
+ if (typeof data.onClose === "function") {
data.onClose();
}
- EventHandler.fire('WoltLabSuite/Core/Date/Picker', 'close', {element: _input});
+ EventHandler.fire("WoltLabSuite/Core/Date/Picker", "close", { element: _input });
const sibling = _input!.nextElementSibling as HTMLElement;
- sibling.setAttribute('aria-expanded', 'false');
+ sibling.setAttribute("aria-expanded", "false");
_input = null;
}
renderGrid(day, month, year);
// create options for month and year
- let years = '';
+ let years = "";
for (let i = _minDate.getFullYear(), last = _maxDate.getFullYear(); i <= last; i++) {
- years += '<option value="' + i + '">' + i + '</option>';
+ years += '<option value="' + i + '">' + i + "</option>";
}
_dateYear.innerHTML = years;
_dateYear.value = year.toString();
_dateMonth.value = month.toString();
- _datePicker!.classList.add('active');
+ _datePicker!.classList.add("active");
}
/**
* Updates the date grid.
*/
function renderGrid(day?: number, month?: number, year?: number): void {
- const hasDay = (day !== undefined);
- const hasMonth = (month !== undefined);
+ const hasDay = day !== undefined;
+ const hasMonth = month !== undefined;
- if (typeof day !== 'number') {
- day = parseInt(day || _dateGrid.dataset.day || '0', 10);
+ if (typeof day !== "number") {
+ day = parseInt(day || _dateGrid.dataset.day || "0", 10);
}
- if (typeof month !== 'number') {
- month = parseInt(month || '0', 10);
+ if (typeof month !== "number") {
+ month = parseInt(month || "0", 10);
}
- if (typeof year !== 'number') {
- year = parseInt(year || '0', 10);
+ if (typeof year !== "number") {
+ year = parseInt(year || "0", 10);
}
// rebuild cells
if (hasMonth || year) {
- let rebuildMonths = (year !== 0);
+ let rebuildMonths = year !== 0;
// rebuild grid
const fragment = document.createDocumentFragment();
}
// check if current selection exceeds min/max date
- let date = new Date(year + '-' + ('0' + (month + 1).toString()).slice(-2) + '-' + ('0' + day.toString()).slice(-2));
+ let date = new Date(year + "-" + ("0" + (month + 1).toString()).slice(-2) + "-" + ("0" + day.toString()).slice(-2));
if (date < _minDate) {
year = _minDate.getFullYear();
month = _minDate.getMonth();
rebuildMonths = true;
}
- date = new Date(year + '-' + ('0' + (month + 1).toString()).slice(-2) + '-01');
+ date = new Date(year + "-" + ("0" + (month + 1).toString()).slice(-2) + "-01");
// shift until first displayed day equals first day of week
while (date.getDay() !== _firstDayOfWeek) {
const cell = _dateCells[i];
cell.textContent = date.getDate().toString();
- selectable = (date.getMonth() === month);
+ selectable = date.getMonth() === month;
if (selectable) {
if (date < comparableMinDate) selectable = false;
else if (date > _maxDate) selectable = false;
}
- cell.classList[selectable ? 'remove' : 'add']('otherMonth');
+ cell.classList[selectable ? "remove" : "add"]("otherMonth");
if (selectable) {
- cell.href = '#';
- cell.setAttribute('role', 'button');
+ cell.href = "#";
+ cell.setAttribute("role", "button");
cell.tabIndex = 0;
cell.title = DateUtil.formatDate(date);
- cell.setAttribute('aria-label', DateUtil.formatDate(date));
+ cell.setAttribute("aria-label", DateUtil.formatDate(date));
}
date.setDate(date.getDate() + 1);
for (let i = 0; i < 12; i++) {
const currentMonth = _dateMonth.children[i] as HTMLOptionElement;
- currentMonth.disabled = (year === _minDate.getFullYear() && +currentMonth.value < _minDate.getMonth()) || (year === _maxDate.getFullYear() && +currentMonth.value > _maxDate.getMonth());
+ currentMonth.disabled =
+ (year === _minDate.getFullYear() && +currentMonth.value < _minDate.getMonth()) ||
+ (year === _maxDate.getFullYear() && +currentMonth.value > _maxDate.getMonth());
}
- const nextMonth = new Date(year + '-' + ('0' + (month + 1).toString()).slice(-2) + '-01');
+ const nextMonth = new Date(year + "-" + ("0" + (month + 1).toString()).slice(-2) + "-01");
nextMonth.setMonth(nextMonth.getMonth() + 1);
- _dateMonthNext.classList[(nextMonth < _maxDate) ? 'add' : 'remove']('active');
+ _dateMonthNext.classList[nextMonth < _maxDate ? "add" : "remove"]("active");
- const previousMonth = new Date(year + '-' + ('0' + (month + 1).toString()).slice(-2) + '-01');
+ const previousMonth = new Date(year + "-" + ("0" + (month + 1).toString()).slice(-2) + "-01");
previousMonth.setDate(previousMonth.getDate() - 1);
- _dateMonthPrevious.classList[(previousMonth > _minDate) ? 'add' : 'remove']('active');
+ _dateMonthPrevious.classList[previousMonth > _minDate ? "add" : "remove"]("active");
}
}
for (let i = 0; i < 35; i++) {
const cell = _dateCells[i];
- cell.classList[(!cell.classList.contains('otherMonth') && +cell.textContent! === day) ? 'add' : 'remove']('active');
+ cell.classList[!cell.classList.contains("otherMonth") && +cell.textContent! === day ? "add" : "remove"]("active");
}
_dateGrid.dataset.day = day.toString();
const data = _data.get(_input!) as DatePickerData;
let date: Date;
- if (Core.stringToBool(_input!.dataset.empty || '')) {
+ if (Core.stringToBool(_input!.dataset.empty || "")) {
return;
}
+_dateGrid.dataset.month!,
+_dateGrid.dataset.day!,
+_dateHour.value,
- +_dateMinute.value,
+ +_dateMinute.value
);
} else {
- date = new Date(
- +_dateGrid.dataset.year!,
- +_dateGrid.dataset.month!,
- +_dateGrid.dataset.day!,
- );
+ date = new Date(+_dateGrid.dataset.year!, +_dateGrid.dataset.month!, +_dateGrid.dataset.day!);
}
DatePicker.setDate(_input!, date);
event.preventDefault();
const target = event.currentTarget as HTMLAnchorElement;
- if (target.classList.contains('otherMonth')) {
+ if (target.classList.contains("otherMonth")) {
return;
}
- _input!.dataset.empty = 'false';
+ _input!.dataset.empty = "false";
renderGrid(+target.textContent!);
* Validates given element or id if it represents an active date picker.
*/
function getElement(element: InputElementOrString): HTMLInputElement {
- if (typeof element === 'string') {
+ if (typeof element === "string") {
element = document.getElementById(element) as HTMLInputElement;
}
- if (!(element instanceof HTMLInputElement) || !element.classList.contains('inputDatePicker') || !_data.has(element)) {
+ if (!(element instanceof HTMLInputElement) || !element.classList.contains("inputDatePicker") || !_data.has(element)) {
throw new Error("Expected a valid date picker input element or id.");
}
}
function maintainFocus(event: FocusEvent): void {
- if (_datePicker === null || !_datePicker.classList.contains('active')) {
+ if (_datePicker === null || !_datePicker.classList.contains("active")) {
return;
}
sibling.focus();
_wasInsidePicker = false;
} else {
- _datePicker!.querySelector<HTMLElement>('.previous')!.focus();
+ _datePicker!.querySelector<HTMLElement>(".previous")!.focus();
}
} else {
_wasInsidePicker = true;
setup();
const now = new Date();
- document.querySelectorAll<HTMLInputElement>('input[type="date"]:not(.inputDatePicker), input[type="datetime"]:not(.inputDatePicker)').forEach(element => {
- element.classList.add('inputDatePicker');
- element.readOnly = true;
-
- const isDateTime = (element.type === 'datetime');
- const isTimeOnly = isDateTime && Core.stringToBool(element.dataset.timeOnly || '');
- const disableClear = Core.stringToBool(element.dataset.disableClear || '');
- const ignoreTimezone = isDateTime && Core.stringToBool(element.dataset.ignoreTimezone || '');
- const isBirthday = element.classList.contains('birthday');
-
- element.dataset.isDateTime = isDateTime ? 'true' : 'false';
- element.dataset.isTimeOnly = isTimeOnly ? 'true' : 'false';
-
- // convert value
- let date: Date | null = null;
- let value = element.value;
-
- // ignore the timezone, if the value is only a date (YYYY-MM-DD)
- const isDateOnly = /^\d+-\d+-\d+$/.test(value);
-
- if (value) {
- if (isTimeOnly) {
- date = new Date();
- const tmp = value.split(':');
- date.setHours(+tmp[0], +tmp[1]);
- } else {
- if (ignoreTimezone || isBirthday || isDateOnly) {
- let timezoneOffset = new Date(value).getTimezoneOffset();
- let timezone = (timezoneOffset > 0) ? '-' : '+'; // -120 equals GMT+0200
- timezoneOffset = Math.abs(timezoneOffset);
-
- const hours = (Math.floor(timezoneOffset / 60)).toString();
- const minutes = (timezoneOffset % 60).toString();
- timezone += (hours.length === 2) ? hours : '0' + hours;
- timezone += ':';
- timezone += (minutes.length === 2) ? minutes : '0' + minutes;
-
- if (isBirthday || isDateOnly) {
- value += 'T00:00:00' + timezone;
- } else {
- value = value.replace(/[+-][0-9]{2}:[0-9]{2}$/, timezone);
+ document
+ .querySelectorAll<HTMLInputElement>(
+ 'input[type="date"]:not(.inputDatePicker), input[type="datetime"]:not(.inputDatePicker)'
+ )
+ .forEach((element) => {
+ element.classList.add("inputDatePicker");
+ element.readOnly = true;
+
+ const isDateTime = element.type === "datetime";
+ const isTimeOnly = isDateTime && Core.stringToBool(element.dataset.timeOnly || "");
+ const disableClear = Core.stringToBool(element.dataset.disableClear || "");
+ const ignoreTimezone = isDateTime && Core.stringToBool(element.dataset.ignoreTimezone || "");
+ const isBirthday = element.classList.contains("birthday");
+
+ element.dataset.isDateTime = isDateTime ? "true" : "false";
+ element.dataset.isTimeOnly = isTimeOnly ? "true" : "false";
+
+ // convert value
+ let date: Date | null = null;
+ let value = element.value;
+
+ // ignore the timezone, if the value is only a date (YYYY-MM-DD)
+ const isDateOnly = /^\d+-\d+-\d+$/.test(value);
+
+ if (value) {
+ if (isTimeOnly) {
+ date = new Date();
+ const tmp = value.split(":");
+ date.setHours(+tmp[0], +tmp[1]);
+ } else {
+ if (ignoreTimezone || isBirthday || isDateOnly) {
+ let timezoneOffset = new Date(value).getTimezoneOffset();
+ let timezone = timezoneOffset > 0 ? "-" : "+"; // -120 equals GMT+0200
+ timezoneOffset = Math.abs(timezoneOffset);
+
+ const hours = Math.floor(timezoneOffset / 60).toString();
+ const minutes = (timezoneOffset % 60).toString();
+ timezone += hours.length === 2 ? hours : "0" + hours;
+ timezone += ":";
+ timezone += minutes.length === 2 ? minutes : "0" + minutes;
+
+ if (isBirthday || isDateOnly) {
+ value += "T00:00:00" + timezone;
+ } else {
+ value = value.replace(/[+-][0-9]{2}:[0-9]{2}$/, timezone);
+ }
}
- }
- date = new Date(value);
- }
+ date = new Date(value);
+ }
- const time = date.getTime();
+ const time = date.getTime();
- // check for invalid dates
- if (isNaN(time)) {
- value = '';
- } else {
- element.dataset.value = time.toString();
- const format = (isTimeOnly) ? 'formatTime' : ('formatDate' + (isDateTime ? 'Time' : ''));
- value = DateUtil[format](date);
+ // check for invalid dates
+ if (isNaN(time)) {
+ value = "";
+ } else {
+ element.dataset.value = time.toString();
+ const format = isTimeOnly ? "formatTime" : "formatDate" + (isDateTime ? "Time" : "");
+ value = DateUtil[format](date);
+ }
}
- }
- const isEmpty = (value.length === 0);
+ const isEmpty = value.length === 0;
- // handle birthday input
- if (isBirthday) {
- element.dataset.minDate = '120';
+ // handle birthday input
+ if (isBirthday) {
+ element.dataset.minDate = "120";
- // do not use 'now' here, all though it makes sense, it causes bad UX
- element.dataset.maxDate = new Date().getFullYear() + '-12-31';
- } else {
- if (element.min) {
- element.dataset.minDate = element.min;
- }
- if (element.max) {
- element.dataset.maxDate = element.max;
+ // do not use 'now' here, all though it makes sense, it causes bad UX
+ element.dataset.maxDate = new Date().getFullYear() + "-12-31";
+ } else {
+ if (element.min) {
+ element.dataset.minDate = element.min;
+ }
+ if (element.max) {
+ element.dataset.maxDate = element.max;
+ }
}
- }
- initDateRange(element, now, true);
- initDateRange(element, now, false);
+ initDateRange(element, now, true);
+ initDateRange(element, now, false);
- if ((element.dataset.minDate || '') === (element.dataset.maxDate || '')) {
- throw new Error("Minimum and maximum date cannot be the same (element id '" + element.id + "').");
- }
+ if ((element.dataset.minDate || "") === (element.dataset.maxDate || "")) {
+ throw new Error("Minimum and maximum date cannot be the same (element id '" + element.id + "').");
+ }
- // change type to prevent browser's datepicker to trigger
- element.type = 'text';
- element.value = value;
- element.dataset.empty = isEmpty ? 'true' : 'false';
+ // change type to prevent browser's datepicker to trigger
+ element.type = "text";
+ element.value = value;
+ element.dataset.empty = isEmpty ? "true" : "false";
- const placeholder = element.dataset.placeholder || '';
- if (placeholder) {
- element.placeholder = placeholder;
- }
+ const placeholder = element.dataset.placeholder || "";
+ if (placeholder) {
+ element.placeholder = placeholder;
+ }
- // add a hidden element to hold the actual date
- const shadowElement = document.createElement('input');
- shadowElement.id = element.id + 'DatePicker';
- shadowElement.name = element.name;
- shadowElement.type = 'hidden';
-
- if (date !== null) {
- if (isTimeOnly) {
- shadowElement.value = DateUtil.format(date, 'H:i');
- } else if (ignoreTimezone) {
- shadowElement.value = DateUtil.format(date, 'Y-m-dTH:i:s');
- } else {
- shadowElement.value = DateUtil.format(date, (isDateTime) ? 'c' : 'Y-m-d');
+ // add a hidden element to hold the actual date
+ const shadowElement = document.createElement("input");
+ shadowElement.id = element.id + "DatePicker";
+ shadowElement.name = element.name;
+ shadowElement.type = "hidden";
+
+ if (date !== null) {
+ if (isTimeOnly) {
+ shadowElement.value = DateUtil.format(date, "H:i");
+ } else if (ignoreTimezone) {
+ shadowElement.value = DateUtil.format(date, "Y-m-dTH:i:s");
+ } else {
+ shadowElement.value = DateUtil.format(date, isDateTime ? "c" : "Y-m-d");
+ }
}
- }
- element.parentNode!.insertBefore(shadowElement, element);
- element.removeAttribute('name');
+ element.parentNode!.insertBefore(shadowElement, element);
+ element.removeAttribute("name");
- element.addEventListener('click', open);
+ element.addEventListener("click", open);
- let clearButton: HTMLAnchorElement | null = null;
- if (!element.disabled) {
- // create input addon
- const container = document.createElement('div');
- container.className = 'inputAddon';
+ let clearButton: HTMLAnchorElement | null = null;
+ if (!element.disabled) {
+ // create input addon
+ const container = document.createElement("div");
+ container.className = "inputAddon";
- clearButton = document.createElement('a');
+ clearButton = document.createElement("a");
- clearButton.className = 'inputSuffix button jsTooltip';
- clearButton.href = '#';
- clearButton.setAttribute('role', 'button');
- clearButton.tabIndex = 0;
- clearButton.title = Language.get('wcf.date.datePicker');
- clearButton.setAttribute('aria-label', Language.get('wcf.date.datePicker'));
- clearButton.setAttribute('aria-haspopup', 'true');
- clearButton.setAttribute('aria-expanded', 'false');
- clearButton.addEventListener('click', open);
- container.appendChild(clearButton);
+ clearButton.className = "inputSuffix button jsTooltip";
+ clearButton.href = "#";
+ clearButton.setAttribute("role", "button");
+ clearButton.tabIndex = 0;
+ clearButton.title = Language.get("wcf.date.datePicker");
+ clearButton.setAttribute("aria-label", Language.get("wcf.date.datePicker"));
+ clearButton.setAttribute("aria-haspopup", "true");
+ clearButton.setAttribute("aria-expanded", "false");
+ clearButton.addEventListener("click", open);
+ container.appendChild(clearButton);
- let icon = document.createElement('span');
- icon.className = 'icon icon16 fa-calendar';
- clearButton.appendChild(icon);
+ let icon = document.createElement("span");
+ icon.className = "icon icon16 fa-calendar";
+ clearButton.appendChild(icon);
- element.parentNode!.insertBefore(container, element);
- container.insertBefore(element, clearButton);
+ element.parentNode!.insertBefore(container, element);
+ container.insertBefore(element, clearButton);
- if (!disableClear) {
- const button = document.createElement('a');
- button.className = 'inputSuffix button';
- button.addEventListener('click', this.clear.bind(this, element));
- if (isEmpty) button.style.setProperty('visibility', 'hidden', '');
+ if (!disableClear) {
+ const button = document.createElement("a");
+ button.className = "inputSuffix button";
+ button.addEventListener("click", this.clear.bind(this, element));
+ if (isEmpty) button.style.setProperty("visibility", "hidden", "");
- container.appendChild(button);
+ container.appendChild(button);
- icon = document.createElement('span');
- icon.className = 'icon icon16 fa-times';
- button.appendChild(icon);
+ icon = document.createElement("span");
+ icon.className = "icon icon16 fa-times";
+ button.appendChild(icon);
+ }
}
- }
- // check if the date input has one of the following classes set otherwise default to 'short'
- const knownClasses = ['tiny', 'short', 'medium', 'long'];
- let hasClass = false;
- for (let j = 0; j < 4; j++) {
- if (element.classList.contains(knownClasses[j])) {
- hasClass = true;
+ // check if the date input has one of the following classes set otherwise default to 'short'
+ const knownClasses = ["tiny", "short", "medium", "long"];
+ let hasClass = false;
+ for (let j = 0; j < 4; j++) {
+ if (element.classList.contains(knownClasses[j])) {
+ hasClass = true;
+ }
}
- }
- if (!hasClass) {
- element.classList.add('short');
- }
+ if (!hasClass) {
+ element.classList.add("short");
+ }
- _data.set(element, {
- clearButton,
- shadow: shadowElement,
+ _data.set(element, {
+ clearButton,
+ shadow: shadowElement,
- disableClear,
- isDateTime,
- isEmpty,
- isTimeOnly,
- ignoreTimezone,
+ disableClear,
+ isDateTime,
+ isEmpty,
+ isTimeOnly,
+ ignoreTimezone,
- onClose: null,
+ onClose: null,
+ });
});
- });
},
/**
previousMonth(event: MouseEvent): void {
event.preventDefault();
- if (_dateMonth.value === '0') {
- _dateMonth.value = '11';
+ if (_dateMonth.value === "0") {
+ _dateMonth.value = "11";
_dateYear.value = (+_dateYear.value - 1).toString();
} else {
_dateMonth.value = (+_dateMonth.value - 1).toString();
nextMonth(event: MouseEvent): void {
event.preventDefault();
- if (_dateMonth.value === '11') {
- _dateMonth.value = '0';
+ if (_dateMonth.value === "11") {
+ _dateMonth.value = "0";
_dateYear.value = (+_dateYear.value + 1).toString();
} else {
_dateMonth.value = (+_dateMonth.value + 1).toString();
getDate(element: InputElementOrString): Date | null {
element = getElement(element);
- const value = element.dataset.value || '';
+ const value = element.dataset.value || "";
if (value) {
return new Date(+value);
}
element.dataset.value = date.getTime().toString();
- let format = '';
+ let format = "";
let value: string;
if (data.isDateTime) {
if (data.isTimeOnly) {
value = DateUtil.formatTime(date);
- format = 'H:i';
+ format = "H:i";
} else if (data.ignoreTimezone) {
value = DateUtil.formatDateTime(date);
- format = 'Y-m-dTH:i:s';
+ format = "Y-m-dTH:i:s";
} else {
value = DateUtil.formatDateTime(date);
- format = 'c';
+ format = "c";
}
} else {
value = DateUtil.formatDate(date);
- format = 'Y-m-d';
+ format = "Y-m-d";
}
element.value = value;
// show clear button
if (!data.disableClear) {
- data.clearButton!.style.removeProperty('visibility');
+ data.clearButton!.style.removeProperty("visibility");
}
},
return data.shadow.value;
}
- return '';
+ return "";
},
/**
element = getElement(element);
const data = _data.get(element) as DatePickerData;
- element.removeAttribute('data-value');
- element.value = '';
+ element.removeAttribute("data-value");
+ element.value = "";
if (!data.disableClear) {
- data.clearButton!.style.setProperty('visibility', 'hidden', '');
+ data.clearButton!.style.setProperty("visibility", "hidden", "");
}
data.isEmpty = true;
- data.shadow.value = '';
+ data.shadow.value = "";
},
/**
container.parentNode!.insertBefore(element, container);
container.remove();
- element.type = 'date' + (data.isDateTime ? 'time' : '');
+ element.type = "date" + (data.isDateTime ? "time" : "");
element.name = data.shadow.name;
element.value = data.shadow.value;
- element.removeAttribute('data-value');
- element.removeEventListener('click', open);
+ element.removeAttribute("data-value");
+ element.removeEventListener("click", open);
data.shadow.remove();
- element.classList.remove('inputDatePicker');
+ element.classList.remove("inputDatePicker");
element.readOnly = false;
_data.delete(element);
},
* @module WoltLabSuite/Core/Date/Time/Relative
*/
-import * as Core from '../../Core';
-import * as DateUtil from '../Util';
-import DomChangeListener from '../../Dom/Change/Listener';
-import * as Language from '../../Language';
-import RepeatingTimer from '../../Timer/Repeating';
+import * as Core from "../../Core";
+import * as DateUtil from "../Util";
+import DomChangeListener from "../../Dom/Change/Listener";
+import * as Language from "../../Language";
+import RepeatingTimer from "../../Timer/Repeating";
let _isActive = true;
let _isPending = false;
let _offset: number;
-
function onVisibilityChange(): void {
if (document.hidden) {
_isActive = false;
const timestamp = (date.getTime() - date.getMilliseconds()) / 1_000;
if (_offset === null) _offset = timestamp - window.TIME_NOW;
- document.querySelectorAll('time').forEach(element => {
+ document.querySelectorAll("time").forEach((element) => {
rebuild(element, date, timestamp);
});
}
function rebuild(element: HTMLTimeElement, date: Date, timestamp: number): void {
- if (!element.classList.contains('datetime') || Core.stringToBool(element.dataset.isFutureDate || '')) {
+ if (!element.classList.contains("datetime") || Core.stringToBool(element.dataset.isFutureDate || "")) {
return;
}
const elOffset = element.dataset.offset!;
if (!element.title) {
- element.title = Language.get('wcf.date.dateTimeFormat').replace(/%date%/, elDate).replace(/%time%/, elTime);
+ element.title = Language.get("wcf.date.dateTimeFormat")
+ .replace(/%date%/, elDate)
+ .replace(/%time%/, elTime);
}
// timestamp is less than 60 seconds ago
- if (elTimestamp >= timestamp || timestamp < (elTimestamp + 60)) {
- element.textContent = Language.get('wcf.date.relative.now');
+ if (elTimestamp >= timestamp || timestamp < elTimestamp + 60) {
+ element.textContent = Language.get("wcf.date.relative.now");
}
// timestamp is less than 60 minutes ago (display 1 hour ago rather than 60 minutes ago)
- else if (timestamp < (elTimestamp + 3540)) {
+ else if (timestamp < elTimestamp + 3540) {
const minutes = Math.max(Math.round((timestamp - elTimestamp) / 60), 1);
- element.textContent = Language.get('wcf.date.relative.minutes', {minutes: minutes});
+ element.textContent = Language.get("wcf.date.relative.minutes", { minutes: minutes });
}
// timestamp is less than 24 hours ago
- else if (timestamp < (elTimestamp + 86400)) {
+ else if (timestamp < elTimestamp + 86400) {
const hours = Math.round((timestamp - elTimestamp) / 3600);
- element.textContent = Language.get('wcf.date.relative.hours', {hours: hours});
+ element.textContent = Language.get("wcf.date.relative.hours", { hours: hours });
}
// timestamp is less than 6 days ago
- else if (timestamp < (elTimestamp + 518400)) {
+ else if (timestamp < elTimestamp + 518400) {
const midnight = new Date(date.getFullYear(), date.getMonth(), date.getDate());
const days = Math.ceil((midnight.getTime() / 1000 - elTimestamp) / 86400);
// get day of week
- const dateObj = DateUtil.getTimezoneDate((elTimestamp * 1000), parseInt(elOffset, 10) * 1000);
+ const dateObj = DateUtil.getTimezoneDate(elTimestamp * 1000, parseInt(elOffset, 10) * 1000);
const dow = dateObj.getDay();
- const day = Language.get('__days')[dow];
+ const day = Language.get("__days")[dow];
- element.textContent = Language.get('wcf.date.relative.pastDays', {days: days, day: day, time: elTime});
+ element.textContent = Language.get("wcf.date.relative.pastDays", { days: days, day: day, time: elTime });
}
// timestamp is between ~700 million years BC and last week
else {
- element.textContent = Language.get('wcf.date.shortDateTimeFormat').replace(/%date%/, elDate).replace(/%time%/, elTime);
+ element.textContent = Language.get("wcf.date.shortDateTimeFormat")
+ .replace(/%date%/, elDate)
+ .replace(/%time%/, elTime);
}
}
export function setup(): void {
new RepeatingTimer(refresh, 60_000);
- DomChangeListener.add('WoltLabSuite/Core/Date/Time/Relative', refresh);
+ DomChangeListener.add("WoltLabSuite/Core/Date/Time/Relative", refresh);
- document.addEventListener('visibilitychange', onVisibilityChange);
+ document.addEventListener("visibilitychange", onVisibilityChange);
}
* @module WoltLabSuite/Core/Date/Util
*/
-import * as Language from '../Language';
+import * as Language from "../Language";
/**
* Returns the formatted date.
*/
export function formatDate(date: Date): string {
- return format(date, Language.get('wcf.date.dateFormat'));
+ return format(date, Language.get("wcf.date.dateFormat"));
}
/**
* Returns the formatted time.
*/
export function formatTime(date: Date): string {
- return format(date, Language.get('wcf.date.timeFormat'));
+ return format(date, Language.get("wcf.date.timeFormat"));
}
/**
* Returns the formatted date time.
*/
export function formatDateTime(date: Date): string {
- const dateTimeFormat = Language.get('wcf.date.dateTimeFormat');
- const dateFormat = Language.get('wcf.date.dateFormat');
- const timeFormat = Language.get('wcf.date.timeFormat');
+ const dateTimeFormat = Language.get("wcf.date.dateTimeFormat");
+ const dateFormat = Language.get("wcf.date.dateFormat");
+ const timeFormat = Language.get("wcf.date.timeFormat");
return format(date, dateTimeFormat.replace(/%date%/, dateFormat).replace(/%time%/, timeFormat));
}
*/
export function format(date: Date, format: string): string {
let char: string;
- let out = '';
+ let out = "";
// ISO 8601 date, best recognition by PHP's strtotime()
- if (format === 'c') {
- format = 'Y-m-dTH:i:sP';
+ if (format === "c") {
+ format = "Y-m-dTH:i:sP";
}
for (let i = 0, length = format.length; i < length; i++) {
switch (format[i]) {
// seconds
- case 's':
+ case "s":
// `00` through `59`
- char = ('0' + date.getSeconds().toString()).slice(-2);
+ char = ("0" + date.getSeconds().toString()).slice(-2);
break;
// minutes
- case 'i':
+ case "i":
// `00` through `59`
- char = date.getMinutes().toString().padStart(2, '0');
+ char = date.getMinutes().toString().padStart(2, "0");
break;
// hours
- case 'a':
+ case "a":
// `am` or `pm`
- char = (date.getHours() > 11) ? 'pm' : 'am';
+ char = date.getHours() > 11 ? "pm" : "am";
break;
- case 'g':
+ case "g":
// `1` through `12`
hours = date.getHours();
- if (hours === 0) char = '12';
+ if (hours === 0) char = "12";
else if (hours > 12) char = (hours - 12).toString();
else char = hours.toString();
break;
- case 'h':
+ case "h":
// `01` through `12`
hours = date.getHours();
- if (hours === 0) char = '12';
+ if (hours === 0) char = "12";
else if (hours > 12) char = (hours - 12).toString();
else char = hours.toString();
- char = char.padStart(2, '0');
+ char = char.padStart(2, "0");
break;
- case 'A':
+ case "A":
// `AM` or `PM`
- char = (date.getHours() > 11) ? 'PM' : 'AM';
+ char = date.getHours() > 11 ? "PM" : "AM";
break;
- case 'G':
+ case "G":
// `0` through `23`
char = date.getHours().toString();
break;
- case 'H':
+ case "H":
// `00` through `23`
- char = date.getHours().toString().padStart(2, '0');
+ char = date.getHours().toString().padStart(2, "0");
break;
// day
- case 'd':
+ case "d":
// `01` through `31`
- char = date.getDate().toString().padStart(2, '0');
+ char = date.getDate().toString().padStart(2, "0");
break;
- case 'j':
+ case "j":
// `1` through `31`
char = date.getDate().toString();
break;
- case 'l':
+ case "l":
// `Monday` through `Sunday` (localized)
- char = Language.get('__days')[date.getDay()];
+ char = Language.get("__days")[date.getDay()];
break;
- case 'D':
+ case "D":
// `Mon` through `Sun` (localized)
- char = Language.get('__daysShort')[date.getDay()];
+ char = Language.get("__daysShort")[date.getDay()];
break;
- case 'S':
+ case "S":
// ignore english ordinal suffix
- char = '';
+ char = "";
break;
// month
- case 'm':
+ case "m":
// `01` through `12`
- char = (date.getMonth() + 1).toString().padStart(2, '0');
+ char = (date.getMonth() + 1).toString().padStart(2, "0");
break;
- case 'n':
+ case "n":
// `1` through `12`
char = (date.getMonth() + 1).toString();
break;
- case 'F':
+ case "F":
// `January` through `December` (localized)
- char = Language.get('__months')[date.getMonth()];
+ char = Language.get("__months")[date.getMonth()];
break;
- case 'M':
+ case "M":
// `Jan` through `Dec` (localized)
- char = Language.get('__monthsShort')[date.getMonth()];
+ char = Language.get("__monthsShort")[date.getMonth()];
break;
// year
- case 'y':
+ case "y":
// `00` through `99`
char = date.getFullYear().toString().substr(2);
break;
- case 'Y':
+ case "Y":
// Examples: `1988` or `2015`
char = date.getFullYear().toString();
break;
// timezone
- case 'P':
+ case "P":
let offset = date.getTimezoneOffset();
- char = (offset > 0) ? '-' : '+';
+ char = offset > 0 ? "-" : "+";
offset = Math.abs(offset);
- char += ('0' + (~~(offset / 60)).toString()).slice(-2);
- char += ':';
- char += ('0' + (offset % 60).toString()).slice(-2);
+ char += ("0" + (~~(offset / 60)).toString()).slice(-2);
+ char += ":";
+ char += ("0" + (offset % 60).toString()).slice(-2);
break;
// specials
- case 'r':
+ case "r":
char = date.toString();
break;
- case 'U':
+ case "U":
char = Math.round(date.getTime() / 1000).toString();
break;
// escape sequence
- case '\\':
- char = '';
+ case "\\":
+ char = "";
if (i + 1 < length) {
char = format[++i];
}
date = new Date();
}
- return Math.round(Date.UTC(
- date.getUTCFullYear(),
- date.getUTCMonth(),
- date.getUTCDay(),
- date.getUTCHours(),
- date.getUTCMinutes(),
- date.getUTCSeconds(),
- ) / 1000);
+ return Math.round(
+ Date.UTC(
+ date.getUTCFullYear(),
+ date.getUTCMonth(),
+ date.getUTCDay(),
+ date.getUTCHours(),
+ date.getUTCMinutes(),
+ date.getUTCSeconds()
+ ) / 1000
+ );
}
/**
* (for dates not in the future) after the DOM change listener has been triggered.
*/
export function getTimeElement(date: Date): HTMLElement {
- const time = document.createElement('time');
- time.className = 'datetime';
+ const time = document.createElement("time");
+ time.className = "datetime";
const formattedDate = formatDate(date);
const formattedTime = formatTime(date);
- time.setAttribute('datetime', format(date, 'c'));
+ time.setAttribute("datetime", format(date, "c"));
time.dataset.timestamp = ((date.getTime() - date.getMilliseconds()) / 1_000).toString();
time.dataset.date = formattedDate;
time.dataset.time = formattedTime;
time.dataset.offset = (date.getTimezoneOffset() * 60).toString(); // PHP returns minutes, JavaScript returns seconds
if (date.getTime() > Date.now()) {
- time.dataset.isFutureDate = 'true';
+ time.dataset.isFutureDate = "true";
- time.textContent = Language.get('wcf.date.dateTimeFormat')
- .replace('%time%', formattedTime)
- .replace('%date%', formattedDate);
+ time.textContent = Language.get("wcf.date.dateTimeFormat")
+ .replace("%time%", formattedTime)
+ .replace("%date%", formattedDate);
}
return time;
const date = new Date(timestamp);
const localOffset = date.getTimezoneOffset() * 60_000;
- return new Date((timestamp + localOffset + offset));
+ return new Date(timestamp + localOffset + offset);
}
function _updateConfig() {
if (window.sessionStorage) {
- window.sessionStorage.setItem('__wsc_devtools_config', JSON.stringify(_settings));
+ window.sessionStorage.setItem("__wsc_devtools_config", JSON.stringify(_settings));
}
}
* Prints the list of available commands.
*/
help(): void {
- window.console.log('');
- window.console.log('%cAvailable commands:', 'text-decoration: underline');
+ window.console.log("");
+ window.console.log("%cAvailable commands:", "text-decoration: underline");
const commands: string[] = [];
for (const cmd in Devtools) {
- if (cmd !== '_internal_' && Devtools.hasOwnProperty(cmd)) {
+ if (cmd !== "_internal_" && Devtools.hasOwnProperty(cmd)) {
commands.push(cmd);
}
}
commands.sort().forEach(function (cmd) {
- window.console.log('\tDevtools.' + cmd + '()');
+ window.console.log("\tDevtools." + cmd + "()");
});
- window.console.log('');
+ window.console.log("");
},
/**
_settings.editorAutosave = forceDisable ? false : !_settings.editorAutosave;
_updateConfig();
- window.console.log('%c\tEditor autosave ' + (_settings.editorAutosave ? 'enabled' : 'disabled'), 'font-style: italic');
+ window.console.log(
+ "%c\tEditor autosave " + (_settings.editorAutosave ? "enabled" : "disabled"),
+ "font-style: italic"
+ );
},
/**
_settings.eventLogging = forceEnable ? true : !_settings.eventLogging;
_updateConfig();
- window.console.log('%c\tEvent logging ' + (_settings.eventLogging ? 'enabled' : 'disabled'), 'font-style: italic');
+ window.console.log("%c\tEvent logging " + (_settings.eventLogging ? "enabled" : "disabled"), "font-style: italic");
},
/**
enable(): void {
window.Devtools = Devtools;
- window.console.log('%cDevtools for WoltLab Suite loaded', 'font-weight: bold');
+ window.console.log("%cDevtools for WoltLab Suite loaded", "font-weight: bold");
if (window.sessionStorage) {
- const settings = window.sessionStorage.getItem('__wsc_devtools_config');
+ const settings = window.sessionStorage.getItem("__wsc_devtools_config");
try {
if (settings !== null) {
_settings = JSON.parse(settings);
}
- } catch (e) {
- }
+ } catch (e) {}
if (!_settings.editorAutosave) Devtools.toggleEditorAutosave(true);
if (_settings.eventLogging) Devtools.toggleEventLogging(true);
}
- window.console.log('Settings are saved per browser session, enter `Devtools.help()` to learn more.');
- window.console.log('');
+ window.console.log("Settings are saved per browser session, enter `Devtools.help()` to learn more.");
+ window.console.log("");
},
editorAutosave(): boolean {
eventLog(identifier: string, action: string): void {
if (_settings.eventLogging) {
- window.console.log('[Devtools.EventLogging] Firing event: ' + action + ' @ ' + identifier);
+ window.console.log("[Devtools.EventLogging] Firing event: " + action + " @ " + identifier);
}
},
},
* value as first parameter and the key name second.
*/
forEach(callback: (value: any, key: string) => void): void {
- if (typeof callback !== 'function') {
- throw new TypeError('forEach() expects a callback as first parameter.');
+ if (typeof callback !== "function") {
+ throw new TypeError("forEach() expects a callback as first parameter.");
}
this._dictionary.forEach(callback);
*/
toObject(): object {
const object = {};
- this._dictionary.forEach((value, key) => object[key] = value);
+ this._dictionary.forEach((value, key) => (object[key] = value));
return object;
}
* @module WoltLabSuite/Core/Dom/Change/Listener
*/
-import CallbackList from '../../CallbackList';
+import CallbackList from "../../CallbackList";
const _callbackList = new CallbackList();
let _hot = false;
try {
_hot = true;
- _callbackList.forEach(null, callback => callback());
+ _callbackList.forEach(null, (callback) => callback());
} finally {
_hot = false;
}
},
};
-export = DomChangeListener
+export = DomChangeListener;
function _getChildren(element: Element, type: Type, value: string): Element[] {
if (!(element instanceof Element)) {
- throw new TypeError('Expected a valid element as first argument.');
+ throw new TypeError("Expected a valid element as first argument.");
}
const children: Element[] = [];
function _getParent(element: Element, type: Type, value: string, untilElement?: Element): Element | null {
if (!(element instanceof Element)) {
- throw new TypeError('Expected a valid element as first argument.');
+ throw new TypeError("Expected a valid element as first argument.");
}
let target = element.parentNode;
function _getSibling(element: Element, siblingType: string, type: Type, value: string): Element | null {
if (!(element instanceof Element)) {
- throw new TypeError('Expected a valid element as first argument.');
+ throw new TypeError("Expected a valid element as first argument.");
}
if (element instanceof Element) {
* @deprecated 5.4 Use `element.nextElementSibling` instead.
*/
export function next(element: Element): Element | null {
- return _getSibling(element, 'nextElementSibling', Type.None, '');
+ return _getSibling(element, "nextElementSibling", Type.None, "");
}
/**
* Returns the next element sibling that matches the given selector.
*/
export function nextBySel(element: Element, selector: string): Element | null {
- return _getSibling(element, 'nextElementSibling', Type.Selector, selector);
+ return _getSibling(element, "nextElementSibling", Type.Selector, selector);
}
/**
* Returns the next element sibling with given CSS class.
*/
export function nextByClass(element: Element, className: string): Element | null {
- return _getSibling(element, 'nextElementSibling', Type.ClassName, className);
+ return _getSibling(element, "nextElementSibling", Type.ClassName, className);
}
/**
* Returns the next element sibling with given CSS class.
*/
export function nextByTag(element: Element, tagName: string): Element | null {
- return _getSibling(element, 'nextElementSibling', Type.TagName, tagName);
+ return _getSibling(element, "nextElementSibling", Type.TagName, tagName);
}
/**
* @deprecated 5.4 Use `element.previousElementSibling` instead.
*/
export function prev(element: Element): Element | null {
- return _getSibling(element, 'previousElementSibling', Type.None, '');
+ return _getSibling(element, "previousElementSibling", Type.None, "");
}
/**
* Returns the previous element sibling that matches the given selector.
*/
export function prevBySel(element: Element, selector: string): Element | null {
- return _getSibling(element, 'previousElementSibling', Type.Selector, selector);
+ return _getSibling(element, "previousElementSibling", Type.Selector, selector);
}
/**
* Returns the previous element sibling with given CSS class.
*/
export function prevByClass(element: Element, className: string): Element | null {
- return _getSibling(element, 'previousElementSibling', Type.ClassName, className);
+ return _getSibling(element, "previousElementSibling", Type.ClassName, className);
}
/**
* Returns the previous element sibling with given CSS class.
*/
export function prevByTag(element: Element, tagName: string): Element | null {
- return _getSibling(element, 'previousElementSibling', Type.TagName, tagName);
+ return _getSibling(element, "previousElementSibling", Type.TagName, tagName);
}
* @module WoltLabSuite/Core/Dom/Util
*/
-import * as StringUtil from '../StringUtil';
+import * as StringUtil from "../StringUtil";
function _isBoundaryNode(element: Element, ancestor: Element, position: string): boolean {
if (!ancestor.contains(element)) {
- throw new Error('Ancestor element does not contain target element.');
+ throw new Error("Ancestor element does not contain target element.");
}
let node: Node;
let target: Node | null = element;
- const whichSibling = position + 'Sibling';
+ const whichSibling = position + "Sibling";
while (target !== null && target !== ancestor) {
- if (target[position + 'ElementSibling'] !== null) {
+ if (target[position + "ElementSibling"] !== null) {
return false;
} else if (target[whichSibling]) {
node = target[whichSibling];
while (node) {
- if (node.textContent!.trim() !== '') {
+ if (node.textContent!.trim() !== "") {
return false;
}
* Returns a DocumentFragment containing the provided HTML string as DOM nodes.
*/
createFragmentFromHtml(html: string): DocumentFragment {
- const tmp = document.createElement('div');
+ const tmp = document.createElement("div");
this.setInnerHtml(tmp, html);
const fragment = document.createDocumentFragment();
let elementId: string;
do {
- elementId = 'wcf' + _idCounter++;
- }
- while (document.getElementById(elementId) !== null);
+ elementId = "wcf" + _idCounter++;
+ } while (document.getElementById(elementId) !== null);
return elementId;
},
*/
identify(element: Element): string {
if (!(element instanceof Element)) {
- throw new TypeError('Expected a valid DOM element as argument.');
+ throw new TypeError("Expected a valid DOM element as argument.");
}
let id = element.id;
* @deprecated 5.3 Use `parent.insertAdjacentElement('afterbegin', element)` instead.
*/
prepend(element: Element, parent: Element): void {
- parent.insertAdjacentElement('afterbegin', element);
+ parent.insertAdjacentElement("afterbegin", element);
},
/**
* @deprecated 5.3 Use `element.insertAdjacentElement('afterend', newElement)` instead.
*/
insertAfter(newElement: Element, element: Element): void {
- element.insertAdjacentElement('afterend', newElement);
+ element.insertAdjacentElement("afterend", newElement);
},
/**
if (/ !important$/.test(styles[property])) {
important = true;
- styles[property] = styles[property].replace(/ !important$/, '');
+ styles[property] = styles[property].replace(/ !important$/, "");
} else {
important = false;
}
// for a set style property with priority = important, some browsers are
// not able to overwrite it with a property != important; removing the
// property first solves this issue
- if (element.style.getPropertyPriority(property) === 'important' && !important) {
+ if (element.style.getPropertyPriority(property) === "important" && !important) {
element.style.removeProperty(property);
}
- element.style.setProperty(property, styles[property], (important ? 'important' : ''));
+ element.style.setProperty(property, styles[property], important ? "important" : "");
}
}
},
setInnerHtml(element: Element, innerHtml: string): void {
element.innerHTML = innerHtml;
- const scripts = element.querySelectorAll<HTMLScriptElement>('script');
+ const scripts = element.querySelectorAll<HTMLScriptElement>("script");
for (let i = 0, length = scripts.length; i < length; i++) {
const script = scripts[i];
- const newScript = document.createElement('script');
+ const newScript = document.createElement("script");
if (script.src) {
newScript.src = script.src;
} else {
* @param insertMethod
*/
insertHtml(html: string, referenceElement: Element, insertMethod: string): void {
- const element = document.createElement('div');
+ const element = document.createElement("div");
this.setInnerHtml(element, html);
if (!element.childNodes.length) {
let node = element.childNodes[0] as Element;
switch (insertMethod) {
- case 'append':
+ case "append":
referenceElement.appendChild(node);
break;
- case 'after':
+ case "after":
this.insertAfter(node, referenceElement);
break;
- case 'prepend':
+ case "prepend":
this.prepend(node, referenceElement);
break;
- case 'before':
+ case "before":
if (referenceElement.parentNode === null) {
- throw new Error('The reference element has no parent, but the insert position was set to \'before\'.');
+ throw new Error("The reference element has no parent, but the insert position was set to 'before'.");
}
referenceElement.parentNode.insertBefore(node, referenceElement);
break;
default:
- throw new Error('Unknown insert method \'' + insertMethod + '\'.');
+ throw new Error("Unknown insert method '" + insertMethod + "'.");
}
let tmp;
*
* @deprecated 5.4 Use `element.dataset` instead.
*/
- getDataAttributes(element: Element, prefix?: string, camelCaseName?: boolean, idToUpperCase?: boolean): DataAttributes {
- prefix = prefix || '';
- if (prefix.indexOf('data-') !== 0) prefix = 'data-' + prefix;
- camelCaseName = (camelCaseName === true);
- idToUpperCase = (idToUpperCase === true);
+ getDataAttributes(
+ element: Element,
+ prefix?: string,
+ camelCaseName?: boolean,
+ idToUpperCase?: boolean
+ ): DataAttributes {
+ prefix = prefix || "";
+ if (prefix.indexOf("data-") !== 0) prefix = "data-" + prefix;
+ camelCaseName = camelCaseName === true;
+ idToUpperCase = idToUpperCase === true;
const attributes = {};
for (let i = 0, length = element.attributes.length; i < length; i++) {
const attribute = element.attributes[i];
if (attribute.name.indexOf(prefix) === 0) {
- let name = attribute.name.replace(new RegExp('^' + prefix), '');
+ let name = attribute.name.replace(new RegExp("^" + prefix), "");
if (camelCaseName) {
- let tmp = name.split('-');
- name = '';
+ let tmp = name.split("-");
+ name = "";
for (let j = 0, innerLength = tmp.length; j < innerLength; j++) {
if (name.length) {
- if (idToUpperCase && tmp[j] === 'id') {
- tmp[j] = 'ID';
+ if (idToUpperCase && tmp[j] === "id") {
+ tmp[j] = "ID";
} else {
tmp[j] = StringUtil.ucfirst(tmp[j]);
}
*/
unwrapChildNodes(element: Element): void {
if (element.parentNode === null) {
- throw new Error('The element has no parent.');
+ throw new Error("The element has no parent.");
}
let parent = element.parentNode;
*/
replaceElement(oldElement: Element, newElement: Element): void {
if (oldElement.parentNode === null) {
- throw new Error('The old element has no parent.');
+ throw new Error("The old element has no parent.");
}
while (oldElement.childNodes.length) {
* a node without any content nor elements before it or its parent nodes.
*/
isAtNodeStart(element: Element, ancestor: Element): boolean {
- return _isBoundaryNode(element, ancestor, 'previous');
+ return _isBoundaryNode(element, ancestor, "previous");
},
/**
* a node without any content nor elements after it or its parent nodes.
*/
isAtNodeEnd(element: Element, ancestor: Element): boolean {
- return _isBoundaryNode(element, ancestor, 'next');
+ return _isBoundaryNode(element, ancestor, "next");
},
/**
*/
getFixedParent(element: HTMLElement): Element | null {
while (element && element !== document.body) {
- if (window.getComputedStyle(element).getPropertyValue('position') === 'fixed') {
+ if (window.getComputedStyle(element).getPropertyValue("position") === "fixed") {
return element;
}
* Shorthand function to hide an element by setting its 'display' value to 'none'.
*/
hide(element: HTMLElement): void {
- element.style.setProperty('display', 'none', '');
+ element.style.setProperty("display", "none", "");
},
/**
* Shorthand function to show an element previously hidden by using `hide()`.
*/
show(element: HTMLElement): void {
- element.style.removeProperty('display');
+ element.style.removeProperty("display");
},
/**
* value to 'none'.
*/
isHidden(element: HTMLElement): boolean {
- return element.style.getPropertyValue('display') === 'none';
+ return element.style.getPropertyValue("display") === "none";
},
/**
innerError(element: HTMLElement, errorMessage?: string | false | null, isHtml?: boolean): HTMLElement | null {
const parent = element.parentNode;
if (parent === null) {
- throw new Error('Only elements that have a parent element or document are valid.');
+ throw new Error("Only elements that have a parent element or document are valid.");
}
- if (typeof errorMessage !== 'string') {
+ if (typeof errorMessage !== "string") {
if (!errorMessage) {
- errorMessage = '';
+ errorMessage = "";
} else {
- throw new TypeError('The error message must be a string; `false`, `null` or `undefined` can be used as a substitute for an empty string.');
+ throw new TypeError(
+ "The error message must be a string; `false`, `null` or `undefined` can be used as a substitute for an empty string."
+ );
}
}
let innerError = element.nextElementSibling;
- if (innerError === null || innerError.nodeName !== 'SMALL' || !innerError.classList.contains('innerError')) {
- if (errorMessage === '') {
+ if (innerError === null || innerError.nodeName !== "SMALL" || !innerError.classList.contains("innerError")) {
+ if (errorMessage === "") {
innerError = null;
} else {
- innerError = document.createElement('small');
- innerError.className = 'innerError';
+ innerError = document.createElement("small");
+ innerError.className = "innerError";
parent.insertBefore(innerError, element.nextSibling);
}
}
- if (errorMessage === '') {
+ if (errorMessage === "") {
if (innerError !== null) {
innerError.remove();
innerError = null;
}
} else {
- innerError![isHtml ? 'innerHTML' : 'textContent'] = errorMessage;
+ innerError![isHtml ? "innerHTML" : "textContent"] = errorMessage;
}
return innerError as HTMLElement | null;
* @module WoltLabSuite/Core/Environment
*/
-let _browser = 'other';
-let _editor = 'none';
-let _platform = 'desktop';
+let _browser = "other";
+let _editor = "none";
+let _platform = "desktop";
let _touch = false;
/**
* Determines environment variables.
*/
export function setup(): void {
- if (typeof (window as any).chrome === 'object') {
+ if (typeof (window as any).chrome === "object") {
// this detects Opera as well, we could check for window.opr if we need to
- _browser = 'chrome';
+ _browser = "chrome";
} else {
const styles = window.getComputedStyle(document.documentElement);
for (let i = 0, length = styles.length; i < length; i++) {
const property = styles[i];
- if (property.indexOf('-ms-') === 0) {
+ if (property.indexOf("-ms-") === 0) {
// it is tempting to use 'msie', but it wouldn't really represent 'Edge'
- _browser = 'microsoft';
- } else if (property.indexOf('-moz-') === 0) {
- _browser = 'firefox';
- } else if (_browser !== 'firefox' && property.indexOf('-webkit-') === 0) {
- _browser = 'safari';
+ _browser = "microsoft";
+ } else if (property.indexOf("-moz-") === 0) {
+ _browser = "firefox";
+ } else if (_browser !== "firefox" && property.indexOf("-webkit-") === 0) {
+ _browser = "safari";
}
}
}
const ua = window.navigator.userAgent.toLowerCase();
- if (ua.indexOf('crios') !== -1) {
- _browser = 'chrome';
- _platform = 'ios';
+ if (ua.indexOf("crios") !== -1) {
+ _browser = "chrome";
+ _platform = "ios";
} else if (/(?:iphone|ipad|ipod)/.test(ua)) {
- _browser = 'safari';
- _platform = 'ios';
- } else if (ua.indexOf('android') !== -1) {
- _platform = 'android';
- } else if (ua.indexOf('iemobile') !== -1) {
- _browser = 'microsoft';
- _platform = 'windows';
+ _browser = "safari";
+ _platform = "ios";
+ } else if (ua.indexOf("android") !== -1) {
+ _platform = "android";
+ } else if (ua.indexOf("iemobile") !== -1) {
+ _browser = "microsoft";
+ _platform = "windows";
}
- if (_platform === 'desktop' && (ua.indexOf('mobile') !== -1 || ua.indexOf('tablet') !== -1)) {
- _platform = 'mobile';
+ if (_platform === "desktop" && (ua.indexOf("mobile") !== -1 || ua.indexOf("tablet") !== -1)) {
+ _platform = "mobile";
}
- _editor = 'redactor';
- _touch = (('ontouchstart' in window) || (('msMaxTouchPoints' in window.navigator) && window.navigator.msMaxTouchPoints > 0) || (window as any).DocumentTouch && document instanceof (window as any).DocumentTouch);
+ _editor = "redactor";
+ _touch =
+ "ontouchstart" in window ||
+ ("msMaxTouchPoints" in window.navigator && window.navigator.msMaxTouchPoints > 0) ||
+ ((window as any).DocumentTouch && document instanceof (window as any).DocumentTouch);
// The iPad Pro 12.9" masquerades as a desktop browser.
- if (window.navigator.platform === 'MacIntel' && window.navigator.maxTouchPoints > 1) {
- _browser = 'safari';
- _platform = 'ios';
+ if (window.navigator.platform === "MacIntel" && window.navigator.maxTouchPoints > 1) {
+ _browser = "safari";
+ _platform = "ios";
}
}
* @module WoltLabSuite/Core/Event/Handler
*/
-import * as Core from '../Core';
-import Devtools from '../Devtools';
+import * as Core from "../Core";
+import Devtools from "../Devtools";
type Identifier = string;
type Action = string;
* Registers an event listener.
*/
export function add(identifier: Identifier, action: Action, callback: Callback): Uuid {
- if (typeof callback !== 'function') {
+ if (typeof callback !== "function") {
throw new TypeError(`Expected a valid callback for '${action}'@'${identifier}'.`);
}
data = data || {};
- _listeners.get(identifier)
+ _listeners
+ .get(identifier)
?.get(action)
- ?.forEach(callback => callback(data));
+ ?.forEach((callback) => callback(data));
}
/**
* Removes an event listener, requires the uuid returned by add().
*/
export function remove(identifier: Identifier, action: Action, uuid: Uuid): void {
- _listeners.get(identifier)
- ?.get(action)
- ?.delete(uuid);
+ _listeners.get(identifier)?.get(action)?.delete(uuid);
}
/**
* remove all listeners for this identifier.
*/
export function removeAll(identifier: Identifier, action?: Action): void {
- if (typeof action !== 'string') action = undefined;
+ if (typeof action !== "string") action = undefined;
const actions = _listeners.get(identifier);
if (actions === undefined) {
return;
}
- suffix = '_' + suffix;
+ suffix = "_" + suffix;
const length = suffix.length * -1;
actions.forEach((callbacks, action) => {
if (action.substr(length) === suffix) {
* @deprecated 5.4 Use `event.key === "ArrowDown"` instead.
*/
export function ArrowDown(event: KeyboardEvent): boolean {
- return _test(event, 'ArrowDown', 40);
+ return _test(event, "ArrowDown", 40);
}
/**
* @deprecated 5.4 Use `event.key === "ArrowLeft"` instead.
*/
export function ArrowLeft(event: KeyboardEvent): boolean {
- return _test(event, 'ArrowLeft', 37);
+ return _test(event, "ArrowLeft", 37);
}
/**
* @deprecated 5.4 Use `event.key === "ArrowRight"` instead.
*/
export function ArrowRight(event: KeyboardEvent): boolean {
- return _test(event, 'ArrowRight', 39);
+ return _test(event, "ArrowRight", 39);
}
/**
* @deprecated 5.4 Use `event.key === "ArrowUp"` instead.
*/
export function ArrowUp(event: KeyboardEvent): boolean {
- return _test(event, 'ArrowUp', 38);
+ return _test(event, "ArrowUp", 38);
}
/**
* @deprecated 5.4 Use `event.key === ","` instead.
*/
export function Comma(event: KeyboardEvent): boolean {
- return _test(event, ',', 44);
+ return _test(event, ",", 44);
}
/**
* @deprecated 5.4 Use `event.key === "End"` instead.
*/
export function End(event: KeyboardEvent): boolean {
- return _test(event, 'End', 35);
+ return _test(event, "End", 35);
}
/**
* @deprecated 5.4 Use `event.key === "Enter"` instead.
*/
export function Enter(event: KeyboardEvent): boolean {
- return _test(event, 'Enter', 13);
+ return _test(event, "Enter", 13);
}
/**
* @deprecated 5.4 Use `event.key === "Escape"` instead.
*/
export function Escape(event: KeyboardEvent): boolean {
- return _test(event, 'Escape', 27);
+ return _test(event, "Escape", 27);
}
/**
* @deprecated 5.4 Use `event.key === "Home"` instead.
*/
export function Home(event: KeyboardEvent): boolean {
- return _test(event, 'Home', 36);
+ return _test(event, "Home", 36);
}
/**
* @deprecated 5.4 Use `event.key === "Space"` instead.
*/
export function Space(event: KeyboardEvent): boolean {
- return _test(event, 'Space', 32);
+ return _test(event, "Space", 32);
}
/**
* @deprecated 5.4 Use `event.key === "Tab"` instead.
*/
export function Tab(event: KeyboardEvent): boolean {
- return _test(event, 'Tab', 9);
+ return _test(event, "Tab", 9);
}
* @module WoltLabSuite/Core/FileUtil
*/
-import * as StringUtil from './StringUtil';
-
-const _fileExtensionIconMapping = new Map<string, string>(Object.entries({
- // archive
- zip: 'archive',
- rar: 'archive',
- tar: 'archive',
- gz: 'archive',
-
- // audio
- mp3: 'audio',
- ogg: 'audio',
- wav: 'audio',
-
- // code
- php: 'code',
- html: 'code',
- htm: 'code',
- tpl: 'code',
- js: 'code',
-
- // excel
- xls: 'excel',
- ods: 'excel',
- xlsx: 'excel',
-
- // image
- gif: 'image',
- jpg: 'image',
- jpeg: 'image',
- png: 'image',
- bmp: 'image',
- webp: 'image',
-
- // video
- avi: 'video',
- wmv: 'video',
- mov: 'video',
- mp4: 'video',
- mpg: 'video',
- mpeg: 'video',
- flv: 'video',
-
- // pdf
- pdf: 'pdf',
-
- // powerpoint
- ppt: 'powerpoint',
- pptx: 'powerpoint',
-
- // text
- txt: 'text',
-
- // word
- doc: 'word',
- docx: 'word',
- odt: 'word',
-}));
-
-const _mimeTypeExtensionMapping = new Map<string, string>(Object.entries({
- // archive
- 'application/zip': 'zip',
- 'application/x-zip-compressed': 'zip',
- 'application/rar': 'rar',
- 'application/vnd.rar': 'rar',
- 'application/x-rar-compressed': 'rar',
- 'application/x-tar': 'tar',
- 'application/x-gzip': 'gz',
- 'application/gzip': 'gz',
-
- // audio
- 'audio/mpeg': 'mp3',
- 'audio/mp3': 'mp3',
- 'audio/ogg': 'ogg',
- 'audio/x-wav': 'wav',
-
- // code
- 'application/x-php': 'php',
- 'text/html': 'html',
- 'application/javascript': 'js',
-
- // excel
- 'application/vnd.ms-excel': 'xls',
- 'application/vnd.oasis.opendocument.spreadsheet': 'ods',
- 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',
-
- // image
- 'image/gif': 'gif',
- 'image/jpeg': 'jpg',
- 'image/png': 'png',
- 'image/x-ms-bmp': 'bmp',
- 'image/bmp': 'bmp',
- 'image/webp': 'webp',
-
- // video
- 'video/x-msvideo': 'avi',
- 'video/x-ms-wmv': 'wmv',
- 'video/quicktime': 'mov',
- 'video/mp4': 'mp4',
- 'video/mpeg': 'mpg',
- 'video/x-flv': 'flv',
-
- // pdf
- 'application/pdf': 'pdf',
-
- // powerpoint
- 'application/vnd.ms-powerpoint': 'ppt',
- 'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'pptx',
-
- // text
- 'text/plain': 'txt',
-
- // word
- 'application/msword': 'doc',
- 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
- 'application/vnd.oasis.opendocument.text': 'odt',
-}));
+import * as StringUtil from "./StringUtil";
+
+const _fileExtensionIconMapping = new Map<string, string>(
+ Object.entries({
+ // archive
+ zip: "archive",
+ rar: "archive",
+ tar: "archive",
+ gz: "archive",
+
+ // audio
+ mp3: "audio",
+ ogg: "audio",
+ wav: "audio",
+
+ // code
+ php: "code",
+ html: "code",
+ htm: "code",
+ tpl: "code",
+ js: "code",
+
+ // excel
+ xls: "excel",
+ ods: "excel",
+ xlsx: "excel",
+
+ // image
+ gif: "image",
+ jpg: "image",
+ jpeg: "image",
+ png: "image",
+ bmp: "image",
+ webp: "image",
+
+ // video
+ avi: "video",
+ wmv: "video",
+ mov: "video",
+ mp4: "video",
+ mpg: "video",
+ mpeg: "video",
+ flv: "video",
+
+ // pdf
+ pdf: "pdf",
+
+ // powerpoint
+ ppt: "powerpoint",
+ pptx: "powerpoint",
+
+ // text
+ txt: "text",
+
+ // word
+ doc: "word",
+ docx: "word",
+ odt: "word",
+ })
+);
+
+const _mimeTypeExtensionMapping = new Map<string, string>(
+ Object.entries({
+ // archive
+ "application/zip": "zip",
+ "application/x-zip-compressed": "zip",
+ "application/rar": "rar",
+ "application/vnd.rar": "rar",
+ "application/x-rar-compressed": "rar",
+ "application/x-tar": "tar",
+ "application/x-gzip": "gz",
+ "application/gzip": "gz",
+
+ // audio
+ "audio/mpeg": "mp3",
+ "audio/mp3": "mp3",
+ "audio/ogg": "ogg",
+ "audio/x-wav": "wav",
+
+ // code
+ "application/x-php": "php",
+ "text/html": "html",
+ "application/javascript": "js",
+
+ // excel
+ "application/vnd.ms-excel": "xls",
+ "application/vnd.oasis.opendocument.spreadsheet": "ods",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlsx",
+
+ // image
+ "image/gif": "gif",
+ "image/jpeg": "jpg",
+ "image/png": "png",
+ "image/x-ms-bmp": "bmp",
+ "image/bmp": "bmp",
+ "image/webp": "webp",
+
+ // video
+ "video/x-msvideo": "avi",
+ "video/x-ms-wmv": "wmv",
+ "video/quicktime": "mov",
+ "video/mp4": "mp4",
+ "video/mpeg": "mpg",
+ "video/x-flv": "flv",
+
+ // pdf
+ "application/pdf": "pdf",
+
+ // powerpoint
+ "application/vnd.ms-powerpoint": "ppt",
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation": "pptx",
+
+ // text
+ "text/plain": "txt",
+
+ // word
+ "application/msword": "doc",
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "docx",
+ "application/vnd.oasis.opendocument.text": "odt",
+ })
+);
/**
* Formats the given filesize.
precision = 2;
}
- let symbol = 'Byte';
+ let symbol = "Byte";
if (byte >= 1000) {
byte /= 1000;
- symbol = 'kB';
+ symbol = "kB";
}
if (byte >= 1000) {
byte /= 1000;
- symbol = 'MB';
+ symbol = "MB";
}
if (byte >= 1000) {
byte /= 1000;
- symbol = 'GB';
+ symbol = "GB";
}
if (byte >= 1000) {
byte /= 1000;
- symbol = 'TB';
+ symbol = "TB";
}
- return StringUtil.formatNumeric(byte, -precision) + ' ' + symbol;
+ return StringUtil.formatNumeric(byte, -precision) + " " + symbol;
}
/**
* will be returned by this method.
*/
export function getIconNameByFilename(filename: string): string {
- const lastDotPosition = filename.lastIndexOf('.');
+ const lastDotPosition = filename.lastIndexOf(".");
if (lastDotPosition !== -1) {
const extension = filename.substr(lastDotPosition + 1);
}
}
- return '';
+ return "";
}
/**
*/
export function getExtensionByMimeType(mimetype: string): string {
if (_mimeTypeExtensionMapping.has(mimetype)) {
- return '.' + _mimeTypeExtensionMapping.get(mimetype);
+ return "." + _mimeTypeExtensionMapping.get(mimetype);
}
- return '';
+ return "";
}
-
/**
* Constructs a File object from a Blob
*
export function blobToFile(blob: Blob, filename: string): File {
const ext = getExtensionByMimeType(blob.type);
- return new File([blob], filename + ext, {type: blob.type});
+ return new File([blob], filename + ext, { type: blob.type });
}
* @module WoltLabSuite/Core/I18n/Plural
*/
-import * as StringUtil from '../StringUtil';
+import * as StringUtil from "../StringUtil";
-const PLURAL_FEW = 'few';
-const PLURAL_MANY = 'many';
-const PLURAL_ONE = 'one';
-const PLURAL_OTHER = 'other';
-const PLURAL_TWO = 'two';
-const PLURAL_ZERO = 'zero';
+const PLURAL_FEW = "few";
+const PLURAL_MANY = "many";
+const PLURAL_ONE = "one";
+const PLURAL_OTHER = "other";
+const PLURAL_TWO = "two";
+const PLURAL_ZERO = "zero";
const Plural = {
/**
}
// Fallback: handle unknown languages as English
- if (typeof Plural[languageCode] !== 'function') {
- languageCode = 'en';
+ if (typeof Plural[languageCode] !== "function") {
+ languageCode = "en";
}
const category = Plural[languageCode](value);
* @see wcf\system\template\plugin\PluralFunctionTemplatePlugin::execute()
*/
getCategoryFromTemplateParameters(parameters: object): string {
- if (!parameters['value']) {
- throw new Error('Missing parameter value');
+ if (!parameters["value"]) {
+ throw new Error("Missing parameter value");
}
- if (!parameters['other']) {
- throw new Error('Missing parameter other');
+ if (!parameters["other"]) {
+ throw new Error("Missing parameter other");
}
- let value = parameters['value'];
+ let value = parameters["value"];
if (Array.isArray(value)) {
value = value.length;
}
}
const string = parameters[category];
- if (string.indexOf('#') !== -1) {
- return string.replace('#', StringUtil.formatNumeric(value));
+ if (string.indexOf("#") !== -1) {
+ return string.replace("#", StringUtil.formatNumeric(value));
}
return string;
*/
getF(n: number): number {
const tmp = n.toString();
- const pos = tmp.indexOf('.');
+ const pos = tmp.indexOf(".");
if (pos === -1) {
return 0;
}
* `v` represents the number of digits of the fractional part (1.234 yields 3)
*/
getV(n: number): number {
- return n.toString().replace(/^[^.]*\.?/, '').length;
+ return n.toString().replace(/^[^.]*\.?/, "").length;
},
// Afrikaans
},
// Tibetan
- bo(n: number) {
- },
+ bo(n: number) {},
// Bosnian
bs(n: number): string | undefined {
const fMod100 = f % 100;
if ((v == 0 && mod10 == 1 && mod100 != 11) || (fMod10 == 1 && fMod100 != 11)) return PLURAL_ONE;
- if ((v == 0 && mod10 >= 2 && mod10 <= 4 && mod100 >= 12 && mod100 <= 14)
- || (fMod10 >= 2 && fMod10 <= 4 && fMod100 >= 12 && fMod100 <= 14)) return PLURAL_FEW;
+ if (
+ (v == 0 && mod10 >= 2 && mod10 <= 4 && mod100 >= 12 && mod100 <= 14) ||
+ (fMod10 >= 2 && fMod10 <= 4 && fMod100 >= 12 && fMod100 <= 14)
+ )
+ return PLURAL_FEW;
},
// Czech
},
// Indonesian
- id(n: number) {
- },
+ id(n: number) {},
// Icelandic
is(n: number): string | undefined {
const f = Plural.getF(n);
- if (f === 0 && n % 10 === 1 && !(n % 100 === 11) || !(f === 0)) return PLURAL_ONE;
+ if ((f === 0 && n % 10 === 1 && !(n % 100 === 11)) || !(f === 0)) return PLURAL_ONE;
},
// Japanese
- ja(n: number) {
- },
+ ja(n: number) {},
// Javanese
- jv(n: number) {
- },
+ jv(n: number) {},
// Georgian
ka(n: number): string | undefined {
},
// Khmer
- km(n: number) {
- },
+ km(n: number) {},
// Kannada
kn(n: number): string | undefined {
},
// Korean
- ko(n: number) {
- },
+ ko(n: number) {},
// Kurdish
ku(n: number): string | undefined {
},
// Lao
- lo(n: number) {
- },
+ lo(n: number) {},
// Lithuanian
lt(n: number): string | undefined {
const fMod100 = f % 100;
if (mod10 == 0 || (mod100 >= 11 && mod100 <= 19) || (v == 2 && fMod100 >= 11 && fMod100 <= 19)) return PLURAL_ZERO;
- if ((mod10 == 1 && mod100 != 11) || (v == 2 && fMod10 == 1 && fMod100 != 11) || (v != 2 && fMod10 == 1)) return PLURAL_ONE;
+ if ((mod10 == 1 && mod100 != 11) || (v == 2 && fMod10 == 1 && fMod100 != 11) || (v != 2 && fMod10 == 1))
+ return PLURAL_ONE;
},
// Macedonian
if (n == 1) return PLURAL_ONE;
},
- // Mongolian
+ // Mongolian
mn(n: number): string | undefined {
if (n == 1) return PLURAL_ONE;
},
- // Marathi
+ // Marathi
mr(n: number): string | undefined {
if (n == 1) return PLURAL_ONE;
},
- // Malay
- ms(n: number) {
- },
+ // Malay
+ ms(n: number) {},
- // Maltese
+ // Maltese
mt(n: number): string | undefined {
const mod100 = n % 100;
},
// Burmese
- my(n: number) {
- },
+ my(n: number) {},
// Norwegian
no(n: number): string | undefined {
if (n == 1 && v == 0) return PLURAL_ONE;
if (v == 0 && mod10 >= 2 && mod10 <= 4 && !(mod100 >= 12 && mod100 <= 14)) return PLURAL_FEW;
- if (v == 0 && ((n != 1 && mod10 >= 0 && mod10 <= 1) || (mod10 >= 5 && mod10 <= 9) || (mod100 >= 12 && mod100 <= 14))) return PLURAL_MANY;
+ if (
+ v == 0 &&
+ ((n != 1 && mod10 >= 0 && mod10 <= 1) || (mod10 >= 5 && mod10 <= 9) || (mod100 >= 12 && mod100 <= 14))
+ )
+ return PLURAL_MANY;
},
// Pashto
},
// Tajik
- tg(n: number) {
- },
+ tg(n: number) {},
// Thai
- th(n: number) {
- },
+ th(n: number) {},
// Turkmen
tk(n: number): string | undefined {
},
// Vietnamese
- vi(n: number) {
- },
+ vi(n: number) {},
// Chinese
- zh(n: number) {
- },
+ zh(n: number) {},
};
-export = Plural
+export = Plural;
* @module WoltLabSuite/Core/Language
*/
-import Template from './Template';
+import Template from "./Template";
const _languageItems = new Map<string, string | Template>();
* Adds all the language items in the given object to the store.
*/
export function addObject(object: LanguageItems): void {
- Object.keys(object).forEach(key => {
+ Object.keys(object).forEach((key) => {
_languageItems.set(key, object[key]);
});
}
}
// fetch Template, as it cannot be provided because of a circular dependency
- if (Template === undefined) { //@ts-ignore
- Template = require('./Template');
+ if (Template === undefined) {
+ //@ts-ignore
+ Template = require("./Template");
}
- if (typeof value === 'string') {
+ if (typeof value === "string") {
// lazily convert to WCF.Template
try {
_languageItems.set(key, new Template(value));
} catch (e) {
- _languageItems.set(key, new Template('{literal}' + value.replace(/{\/literal}/g, '{/literal}{ldelim}/literal}{literal}') + '{/literal}'));
+ _languageItems.set(
+ key,
+ new Template("{literal}" + value.replace(/{\/literal}/g, "{/literal}{ldelim}/literal}{literal}") + "{/literal}")
+ );
}
value = _languageItems.get(key);
}
interface LanguageItems {
[key: string]: string;
-}
+}
*/
export function round(value: number, exp: number): number {
// If the exp is undefined or zero...
- if (typeof exp === 'undefined' || +exp === 0) {
+ if (typeof exp === "undefined" || +exp === 0) {
return Math.round(value);
}
value = +value;
exp = +exp;
// If the value is not a number or the exp is not an integer...
- if (isNaN(value) || !(typeof (exp as any) === 'number' && exp % 1 === 0)) {
+ if (isNaN(value) || !(typeof (exp as any) === "number" && exp % 1 === 0)) {
return NaN;
}
// Shift
- let tmp = value.toString().split('e');
- value = Math.round(+(tmp[0] + 'e' + (tmp[1] ? (+tmp[1] - exp) : -exp)));
+ let tmp = value.toString().split("e");
+ value = Math.round(+(tmp[0] + "e" + (tmp[1] ? +tmp[1] - exp : -exp)));
// Shift back
- tmp = value.toString().split('e');
- return +(tmp[0] + 'e' + (tmp[1] ? (+tmp[1] + exp) : exp));
+ tmp = value.toString().split("e");
+ return +(tmp[0] + "e" + (tmp[1] ? +tmp[1] + exp : exp));
}
-
* Sets a new key with given value, will overwrite an existing key.
*/
set(key: object, value: object): void {
- if (typeof key !== 'object' || key === null) {
- throw new TypeError('Only objects can be used as key');
+ if (typeof key !== "object" || key === null) {
+ throw new TypeError("Only objects can be used as key");
}
- if (typeof value !== 'object' || value === null) {
- throw new TypeError('Only objects can be used as value');
+ if (typeof value !== "object" || value === null) {
+ throw new TypeError("Only objects can be used as value");
}
this._map.set(key, value);
*/
delete(key: object): void {
this._map.delete(key);
-
}
/**
return this._map.has(key);
}
-
/**
* Retrieves a value by key, returns undefined if there is no match.
*/
}
}
-export = ObjectMap
+export = ObjectMap;
* Adds a single permission to the store.
*/
export function add(permission: string, value: boolean): void {
- if (typeof (value as any) !== 'boolean') {
- throw new TypeError('The permission value has to be boolean.');
+ if (typeof (value as any) !== "boolean") {
+ throw new TypeError("The permission value has to be boolean.");
}
_permissions.set(permission, value);
}
}
-
/**
* Returns the value of a permission.
*
* @module WoltLabSuite/Core/StringUtil
*/
-import * as Language from './Language';
-import * as NumberUtil from './NumberUtil';
+import * as Language from "./Language";
+import * as NumberUtil from "./NumberUtil";
/**
* Adds thousands separators to a given number.
*/
export function addThousandsSeparator(number: number): string {
// Fetch Language, as it cannot be provided because of a circular dependency
- if (Language === undefined) { //@ts-ignore
- Language = require('./Language');
+ if (Language === undefined) {
+ //@ts-ignore
+ Language = require("./Language");
}
- return String(number).replace(/(^-?\d{1,3}|\d{3})(?=(?:\d{3})+(?:$|\.))/g, '$1' + Language.get('wcf.global.thousandsSeparator'));
+ return String(number).replace(
+ /(^-?\d{1,3}|\d{3})(?=(?:\d{3})+(?:$|\.))/g,
+ "$1" + Language.get("wcf.global.thousandsSeparator")
+ );
}
/**
* Escapes special HTML-characters within a string
*/
export function escapeHTML(string: string): string {
- return String(string).replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
+ return String(string).replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
}
/**
* @see https://github.com/sstephenson/prototype/blob/master/src/prototype/lang/regexp.js#L25
*/
export function escapeRegExp(string: string): string {
- return String(string).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
+ return String(string).replace(/([.*+?^=!:${}()|[\]\/\\])/g, "\\$1");
}
/**
*/
export function formatNumeric(number: number, decimalPlaces?: number): string {
// Fetch Language, as it cannot be provided because of a circular dependency
- if (Language === undefined) { //@ts-ignore
- Language = require('./Language');
+ if (Language === undefined) {
+ //@ts-ignore
+ Language = require("./Language");
}
let tmp = NumberUtil.round(number, decimalPlaces || -2).toString();
- const numberParts = tmp.split('.');
+ const numberParts = tmp.split(".");
tmp = addThousandsSeparator(+numberParts[0]);
- if (numberParts.length > 1) tmp += Language.get('wcf.global.decimalPoint') + numberParts[1];
+ if (numberParts.length > 1) tmp += Language.get("wcf.global.decimalPoint") + numberParts[1];
- tmp = tmp.replace('-', '\u2212');
+ tmp = tmp.replace("-", "\u2212");
return tmp;
}
* Unescapes special HTML-characters within a string.
*/
export function unescapeHTML(string: string): string {
- return String(string).replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
+ return String(string)
+ .replace(/&/g, "&")
+ .replace(/"/g, '"')
+ .replace(/</g, "<")
+ .replace(/>/g, ">");
}
/**
* Shortens numbers larger than 1000 by using unit suffixes.
*/
export function shortUnit(number: number): string {
- let unitSuffix = '';
+ let unitSuffix = "";
if (number >= 1000000) {
number /= 1000000;
number = NumberUtil.round(number, -1);
}
- unitSuffix = 'M';
+ unitSuffix = "M";
} else if (number >= 1000) {
number /= 1000;
number = NumberUtil.round(number, -1);
}
- unitSuffix = 'k';
+ unitSuffix = "k";
}
return formatNumeric(number) + unitSuffix;
* @module WoltLabSuite/Core/Template
*/
-import * as parser from './Template.grammar';
-import * as StringUtil from './StringUtil';
-import * as Language from './Language';
-import * as I18nPlural from './I18n/Plural';
+import * as parser from "./Template.grammar";
+import * as StringUtil from "./StringUtil";
+import * as Language from "./Language";
+import * as I18nPlural from "./I18n/Plural";
// @todo: still required?
// work around bug in AMD module generation of Jison
class Template {
constructor(template: string) {
// Fetch Language/StringUtil, as it cannot be provided because of a circular dependency
- if (Language === undefined) { //@ts-ignore
- Language = require('./Language');
+ if (Language === undefined) {
+ //@ts-ignore
+ Language = require("./Language");
}
- if (StringUtil === undefined) { //@ts-ignore
- StringUtil = require('./StringUtil');
+ if (StringUtil === undefined) {
+ //@ts-ignore
+ StringUtil = require("./StringUtil");
}
try {
template = parser.parse(template) as string;
- template = 'var tmp = {};\n'
- + 'for (var key in v) tmp[key] = v[key];\n'
- + 'v = tmp;\n'
- + 'v.__wcf = window.WCF; v.__window = window;\n'
- + 'return ' + template;
+ template =
+ "var tmp = {};\n" +
+ "for (var key in v) tmp[key] = v[key];\n" +
+ "v = tmp;\n" +
+ "v.__wcf = window.WCF; v.__window = window;\n" +
+ "return " +
+ template;
- this.fetch = new Function('StringUtil', 'Language', 'I18nPlural', 'v', template).bind(undefined, StringUtil, Language, I18nPlural);
+ this.fetch = new Function("StringUtil", "Language", "I18nPlural", "v", template).bind(
+ undefined,
+ StringUtil,
+ Language,
+ I18nPlural
+ );
} catch (e) {
console.debug(e.message);
throw e;
*/
fetch(v: object): string {
// this will be replaced in the init function
- throw new Error('This Template is not initialized.');
+ throw new Error("This Template is not initialized.");
}
}
-Object.defineProperty(Template, 'callbacks', {
+Object.defineProperty(Template, "callbacks", {
enumerable: false,
configurable: false,
get: function () {
- throw new Error('WCF.Template.callbacks is no longer supported');
+ throw new Error("WCF.Template.callbacks is no longer supported");
},
set: function (value) {
- throw new Error('WCF.Template.callbacks is no longer supported');
+ throw new Error("WCF.Template.callbacks is no longer supported");
},
});
* The `callback` will be passed the owning instance of `Repeating`.
*/
constructor(callback: (timer: RepeatingTimer) => void, delta: number) {
- if (typeof callback !== 'function') {
+ if (typeof callback !== "function") {
throw new TypeError("Expected a valid callback as first argument.");
}
if (delta < 0 || delta > 86_400 * 1_000) {
-import * as Language from '../../Language';
-import * as StringUtil from '../../StringUtil';
-import DomChangeListener from '../../Dom/Change/Listener';
-import DomUtil from '../../Dom/Util';
-import UiUserSearchInput from '../User/Search/Input';
+import * as Language from "../../Language";
+import * as StringUtil from "../../StringUtil";
+import DomChangeListener from "../../Dom/Change/Listener";
+import DomUtil from "../../Dom/Util";
+import UiUserSearchInput from "../User/Search/Input";
class UiAclSimple {
private readonly aclListContainer: HTMLElement;
private readonly searchInput: UiUserSearchInput;
constructor(prefix?: string, inputName?: string) {
- this.prefix = prefix || '';
- this.inputName = inputName || 'aclValues';
+ this.prefix = prefix || "";
+ this.inputName = inputName || "aclValues";
- const container = document.getElementById(this.prefix + 'aclInputContainer')!;
+ const container = document.getElementById(this.prefix + "aclInputContainer")!;
- const allowAll = document.getElementById(this.prefix + 'aclAllowAll') as HTMLInputElement;
- allowAll.addEventListener('change', () => {
+ const allowAll = document.getElementById(this.prefix + "aclAllowAll") as HTMLInputElement;
+ allowAll.addEventListener("change", () => {
DomUtil.hide(container);
});
- const denyAll = document.getElementById(this.prefix + 'aclAllowAll_no')!;
- denyAll.addEventListener('change', () => {
+ const denyAll = document.getElementById(this.prefix + "aclAllowAll_no")!;
+ denyAll.addEventListener("change", () => {
DomUtil.show(container);
});
- this.list = document.getElementById(this.prefix + 'aclAccessList') as HTMLUListElement;
- this.list.addEventListener('click', this.removeItem.bind(this));
+ this.list = document.getElementById(this.prefix + "aclAccessList") as HTMLUListElement;
+ this.list.addEventListener("click", this.removeItem.bind(this));
const excludedSearchValues: string[] = [];
- this.list.querySelectorAll('.aclLabel').forEach(label => {
+ this.list.querySelectorAll(".aclLabel").forEach((label) => {
excludedSearchValues.push(label.textContent!);
});
- this.searchInput = new UiUserSearchInput(document.getElementById(this.prefix + 'aclSearchInput'), {
+ this.searchInput = new UiUserSearchInput(document.getElementById(this.prefix + "aclSearchInput"), {
callbackSelect: this.select.bind(this),
includeUserGroups: true,
excludedSearchValues: excludedSearchValues,
preventSubmit: true,
});
- this.aclListContainer = document.getElementById(this.prefix + 'aclListContainer')!;
+ this.aclListContainer = document.getElementById(this.prefix + "aclListContainer")!;
DomChangeListener.trigger();
}
const label = listItem.dataset.label!;
const objectId = listItem.dataset.objectId!;
- const iconName = type === 'group' ? 'users' : 'user';
+ const iconName = type === "group" ? "users" : "user";
const html = `<span class="icon icon16 fa-${iconName}"></span>
<span class="aclLabel">${StringUtil.escapeHTML(label)}</span>
- <span class="icon icon16 fa-times pointer jsTooltip" title="${Language.get('wcf.global.button.delete')}"></span>
+ <span class="icon icon16 fa-times pointer jsTooltip" title="${Language.get("wcf.global.button.delete")}"></span>
<input type="hidden" name="${this.inputName}[${type}][]" value="${objectId}">`;
- const item = document.createElement('li');
+ const item = document.createElement("li");
item.innerHTML = html;
- const firstUser = this.list.querySelector('.fa-user');
+ const firstUser = this.list.querySelector(".fa-user");
if (firstUser === null) {
this.list.appendChild(item);
} else {
private removeItem(event: MouseEvent): void {
const target = event.target as HTMLElement;
- if (target.classList.contains('fa-times')) {
+ if (target.classList.contains("fa-times")) {
const parent = target.parentElement!;
- const label = parent.querySelector('.aclLabel')!;
+ const label = parent.querySelector(".aclLabel")!;
this.searchInput.removeExcludedSearchValues(label.textContent!);
- parent.remove()
+ parent.remove();
if (this.list.childElementCount === 0) {
DomUtil.hide(this.aclListContainer);
}
}
-export = UiAclSimple
+export = UiAclSimple;
* @module WoltLabSuite/Core/Ui/Alignment
*/
-import * as Core from '../Core';
-import * as DomTraverse from '../Dom/Traverse';
-import DomUtil from '../Dom/Util';
-import * as Language from '../Language';
+import * as Core from "../Core";
+import * as DomTraverse from "../Dom/Traverse";
+import DomUtil from "../Dom/Util";
+import * as Language from "../Language";
-type HorizontalAlignment = 'center' | 'left' | 'right';
-type VerticalAlignment = 'bottom' | 'top';
-type Offset = number | 'auto';
+type HorizontalAlignment = "center" | "left" | "right";
+type VerticalAlignment = "bottom" | "top";
+type Offset = number | "auto";
interface HorizontalResult {
align: HorizontalAlignment;
* @param {int} windowWidth window width
* @returns {Object<string, *>} calculation results
*/
-function tryAlignmentHorizontal(alignment: HorizontalAlignment, elDimensions, refDimensions, refOffsets, windowWidth): HorizontalResult {
- let left: Offset = 'auto';
- let right: Offset = 'auto';
+function tryAlignmentHorizontal(
+ alignment: HorizontalAlignment,
+ elDimensions,
+ refDimensions,
+ refOffsets,
+ windowWidth
+): HorizontalResult {
+ let left: Offset = "auto";
+ let right: Offset = "auto";
let result = true;
- if (alignment === 'left') {
+ if (alignment === "left") {
left = refOffsets.left;
if (left + elDimensions.width > windowWidth) {
result = false;
}
- } else if (alignment === 'right') {
+ } else if (alignment === "right") {
if (refOffsets.left + refDimensions.width < elDimensions.width) {
result = false;
} else {
}
}
} else {
- left = refOffsets.left + (refDimensions.width / 2) - (elDimensions.width / 2);
+ left = refOffsets.left + refDimensions.width / 2 - elDimensions.width / 2;
left = ~~left;
if (left < 0 || left + elDimensions.width > windowWidth) {
* @param {int} verticalOffset desired gap between element and reference element
* @returns {object<string, *>} calculation results
*/
-function tryAlignmentVertical(alignment: VerticalAlignment, elDimensions, refDimensions, refOffsets, windowHeight, verticalOffset): VerticalResult {
- let bottom: Offset = 'auto';
- let top: Offset = 'auto';
+function tryAlignmentVertical(
+ alignment: VerticalAlignment,
+ elDimensions,
+ refDimensions,
+ refOffsets,
+ windowHeight,
+ verticalOffset
+): VerticalResult {
+ let bottom: Offset = "auto";
+ let top: Offset = "auto";
let result = true;
let pageHeaderOffset = 50;
- const pageHeaderPanel = document.getElementById('pageHeaderPanel');
+ const pageHeaderPanel = document.getElementById("pageHeaderPanel");
if (pageHeaderPanel !== null) {
const position = window.getComputedStyle(pageHeaderPanel).position;
- if (position === 'fixed' || position === 'static') {
+ if (position === "fixed" || position === "static") {
pageHeaderOffset = pageHeaderPanel.offsetHeight;
} else {
pageHeaderOffset = 0;
}
}
- if (alignment === 'top') {
+ if (alignment === "top") {
const bodyHeight = document.body.clientHeight;
- bottom = (bodyHeight - refOffsets.top) + verticalOffset;
+ bottom = bodyHeight - refOffsets.top + verticalOffset;
if (bodyHeight - (bottom + elDimensions.height) < (window.scrollY || window.pageYOffset) + pageHeaderOffset) {
result = false;
}
* @param {Object<string, *>} options list of options to alter the behavior
*/
export function set(element: HTMLElement, referenceElement: HTMLElement, options?: AlignmentOptions): void {
- options = Core.extend({
- // offset to reference element
- verticalOffset: 0,
- // align the pointer element, expects .elementPointer as a direct child of given element
- pointer: false,
- // use static pointer positions, expects two items: class to move it to the bottom and the second to move it to the right
- pointerClassNames: [],
- // alternate element used to calculate dimensions
- refDimensionsElement: null,
- // preferred alignment, possible values: left/right/center and top/bottom
- horizontal: 'left',
- vertical: 'bottom',
- // allow flipping over axis, possible values: both, horizontal, vertical and none
- allowFlip: 'both',
- }, options || {}) as AlignmentOptions;
+ options = Core.extend(
+ {
+ // offset to reference element
+ verticalOffset: 0,
+ // align the pointer element, expects .elementPointer as a direct child of given element
+ pointer: false,
+ // use static pointer positions, expects two items: class to move it to the bottom and the second to move it to the right
+ pointerClassNames: [],
+ // alternate element used to calculate dimensions
+ refDimensionsElement: null,
+ // preferred alignment, possible values: left/right/center and top/bottom
+ horizontal: "left",
+ vertical: "bottom",
+ // allow flipping over axis, possible values: both, horizontal, vertical and none
+ allowFlip: "both",
+ },
+ options || {}
+ ) as AlignmentOptions;
if (!Array.isArray(options.pointerClassNames) || options.pointerClassNames.length !== (options.pointer ? 1 : 2)) {
options.pointerClassNames = [];
}
- if (['left', 'right', 'center'].indexOf(options.horizontal!) === -1) {
- options.horizontal = 'left';
+ if (["left", "right", "center"].indexOf(options.horizontal!) === -1) {
+ options.horizontal = "left";
}
- if (options.vertical !== 'bottom') {
- options.vertical = 'top';
+ if (options.vertical !== "bottom") {
+ options.vertical = "top";
}
- if (['both', 'horizontal', 'vertical', 'none'].indexOf(options.allowFlip!) === -1) {
- options.allowFlip = 'both';
+ if (["both", "horizontal", "vertical", "none"].indexOf(options.allowFlip!) === -1) {
+ options.allowFlip = "both";
}
// Place the element in the upper left corner to prevent calculation issues due to possible scrollbars.
DomUtil.setStyles(element, {
- bottom: 'auto !important',
- left: '0 !important',
- right: 'auto !important',
- top: '0 !important',
- visibility: 'hidden !important',
+ bottom: "auto !important",
+ left: "0 !important",
+ right: "auto !important",
+ top: "0 !important",
+ visibility: "hidden !important",
});
const elDimensions = DomUtil.outerDimensions(element);
- const refDimensions = DomUtil.outerDimensions(options.refDimensionsElement instanceof HTMLElement ? options.refDimensionsElement : referenceElement);
+ const refDimensions = DomUtil.outerDimensions(
+ options.refDimensionsElement instanceof HTMLElement ? options.refDimensionsElement : referenceElement
+ );
const refOffsets = DomUtil.offset(referenceElement);
const windowHeight = window.innerHeight;
const windowWidth = document.body.clientWidth;
let horizontal: HorizontalResult | null = null;
let alignCenter = false;
- if (options.horizontal === 'center') {
+ if (options.horizontal === "center") {
alignCenter = true;
horizontal = tryAlignmentHorizontal(options.horizontal, elDimensions, refDimensions, refOffsets, windowWidth);
if (!horizontal.result) {
- if (options.allowFlip === 'both' || options.allowFlip === 'horizontal') {
- options.horizontal = 'left';
+ if (options.allowFlip === "both" || options.allowFlip === "horizontal") {
+ options.horizontal = "left";
} else {
horizontal.result = true;
}
}
// in rtl languages we simply swap the value for 'horizontal'
- if (Language.get('wcf.global.pageDirection') === 'rtl') {
- options.horizontal = (options.horizontal === 'left') ? 'right' : 'left';
+ if (Language.get("wcf.global.pageDirection") === "rtl") {
+ options.horizontal = options.horizontal === "left" ? "right" : "left";
}
if (horizontal === null || !horizontal.result) {
const horizontalCenter = horizontal;
horizontal = tryAlignmentHorizontal(options.horizontal!, elDimensions, refDimensions, refOffsets, windowWidth);
- if (!horizontal.result && (options.allowFlip === 'both' || options.allowFlip === 'horizontal')) {
- const horizontalFlipped = tryAlignmentHorizontal((options.horizontal === 'left' ? 'right' : 'left'), elDimensions, refDimensions, refOffsets, windowWidth);
+ if (!horizontal.result && (options.allowFlip === "both" || options.allowFlip === "horizontal")) {
+ const horizontalFlipped = tryAlignmentHorizontal(
+ options.horizontal === "left" ? "right" : "left",
+ elDimensions,
+ refDimensions,
+ refOffsets,
+ windowWidth
+ );
// only use these results if it fits into the boundaries, otherwise both directions exceed and we honor the demanded direction
if (horizontalFlipped.result) {
horizontal = horizontalFlipped;
const left = horizontal!.left;
const right = horizontal!.right;
- let vertical = tryAlignmentVertical(options.vertical, elDimensions, refDimensions, refOffsets, windowHeight, options.verticalOffset);
- if (!vertical.result && (options.allowFlip === 'both' || options.allowFlip === 'vertical')) {
- const verticalFlipped = tryAlignmentVertical((options.vertical === 'top' ? 'bottom' : 'top'), elDimensions, refDimensions, refOffsets, windowHeight, options.verticalOffset);
+ let vertical = tryAlignmentVertical(
+ options.vertical,
+ elDimensions,
+ refDimensions,
+ refOffsets,
+ windowHeight,
+ options.verticalOffset
+ );
+ if (!vertical.result && (options.allowFlip === "both" || options.allowFlip === "vertical")) {
+ const verticalFlipped = tryAlignmentVertical(
+ options.vertical === "top" ? "bottom" : "top",
+ elDimensions,
+ refDimensions,
+ refOffsets,
+ windowHeight,
+ options.verticalOffset
+ );
// only use these results if it fits into the boundaries, otherwise both directions exceed and we honor the demanded direction
if (verticalFlipped.result) {
vertical = verticalFlipped;
const top = vertical.top;
// set pointer position
if (options.pointer) {
- const pointers = DomTraverse.childrenByClass(element, 'elementPointer');
+ const pointers = DomTraverse.childrenByClass(element, "elementPointer");
const pointer = pointers[0] || null;
if (pointer === null) {
throw new Error("Expected the .elementPointer element to be a direct children.");
}
- if (horizontal!.align === 'center') {
- pointer.classList.add('center');
- pointer.classList.remove('left', 'right');
+ if (horizontal!.align === "center") {
+ pointer.classList.add("center");
+ pointer.classList.remove("left", "right");
} else {
pointer.classList.add(horizontal!.align);
- pointer.classList.remove('center');
- pointer.classList.remove(horizontal!.align === 'left' ? 'right' : 'left');
+ pointer.classList.remove("center");
+ pointer.classList.remove(horizontal!.align === "left" ? "right" : "left");
}
- if (vertical.align === 'top') {
- pointer.classList.add('flipVertical');
+ if (vertical.align === "top") {
+ pointer.classList.add("flipVertical");
} else {
- pointer.classList.remove('flipVertical');
+ pointer.classList.remove("flipVertical");
}
} else if (options.pointerClassNames.length === 2) {
- element.classList[(top === 'auto' ? 'add' : 'remove')](options.pointerClassNames[PointerClass.Bottom]);
- element.classList[(left === 'auto' ? 'add' : 'remove')](options.pointerClassNames[PointerClass.Right]);
+ element.classList[top === "auto" ? "add" : "remove"](options.pointerClassNames[PointerClass.Bottom]);
+ element.classList[left === "auto" ? "add" : "remove"](options.pointerClassNames[PointerClass.Right]);
}
-
+
DomUtil.setStyles(element, {
- bottom: bottom === 'auto' ? bottom : Math.round(bottom) + 'px',
- left: left === 'auto' ? left : Math.ceil(left) + 'px',
- right: right === 'auto' ? right : Math.floor(right) + 'px',
- top: top === 'auto' ? top : Math.round(top) + 'px',
+ bottom: bottom === "auto" ? bottom : Math.round(bottom) + "px",
+ left: left === "auto" ? left : Math.ceil(left) + "px",
+ right: right === "auto" ? right : Math.floor(right) + "px",
+ top: top === "auto" ? top : Math.round(top) + "px",
});
-
+
DomUtil.show(element);
- element.style.removeProperty('visibility');
+ element.style.removeProperty("visibility");
}
-export type AllowFlip = 'both' | 'horizontal' | 'none' | 'vertical';
+export type AllowFlip = "both" | "horizontal" | "none" | "vertical";
export interface AlignmentOptions {
// offset to reference element
* @module WoltLabSuite/Core/Ui/Article/MarkAllAsRead
*/
-import * as Ajax from '../../Ajax';
-import { AjaxCallbackObject } from '../../Ajax/Data';
+import * as Ajax from "../../Ajax";
+import { AjaxCallbackObject } from "../../Ajax/Data";
class UiArticleMarkAllAsRead implements AjaxCallbackObject {
constructor() {
- document.querySelectorAll('.markAllAsReadButton').forEach(button => {
- button.addEventListener('click', this.click.bind(this));
+ document.querySelectorAll(".markAllAsReadButton").forEach((button) => {
+ button.addEventListener("click", this.click.bind(this));
});
}
_ajaxSuccess() {
/* remove obsolete badges */
// main menu
- const badge = document.querySelector('.mainMenu .active .badge');
+ const badge = document.querySelector(".mainMenu .active .badge");
if (badge) badge.remove();
// article list
- document.querySelectorAll('.articleList .newMessageBadge').forEach(el => el.remove());
+ document.querySelectorAll(".articleList .newMessageBadge").forEach((el) => el.remove());
}
_ajaxSetup() {
return {
data: {
- actionName: 'markAllAsRead',
- className: 'wcf\\data\\article\\ArticleAction',
+ actionName: "markAllAsRead",
+ className: "wcf\\data\\article\\ArticleAction",
},
};
}
-import * as Ajax from '../../Ajax';
-import { AjaxCallbackObject, DatabaseObjectActionResponse } from '../../Ajax/Data';
-import { DialogCallbackObject } from '../Dialog/Data';
-import DomUtil from '../../Dom/Util';
-import * as Language from '../../Language';
-import * as StringUtil from '../../StringUtil';
-import UiDialog from '../Dialog';
+import * as Ajax from "../../Ajax";
+import { AjaxCallbackObject, DatabaseObjectActionResponse } from "../../Ajax/Data";
+import { DialogCallbackObject } from "../Dialog/Data";
+import DomUtil from "../../Dom/Util";
+import * as Language from "../../Language";
+import * as StringUtil from "../../StringUtil";
+import UiDialog from "../Dialog";
type CallbackSelect = (articleId: number) => void;
const value = this.searchInput!.value.trim();
if (value.length < 3) {
- DomUtil.innerError(inputContainer, Language.get('wcf.article.search.error.tooShort'));
+ DomUtil.innerError(inputContainer, Language.get("wcf.article.search.error.tooShort"));
return;
} else {
DomUtil.innerError(inputContainer, false);
_ajaxSuccess(data: AjaxResponse): void {
let html = data.returnValues
- .map(article => {
+ .map((article) => {
return `<li>
<div class="containerHeadline pointer" data-article-id="${article.articleID}">
<h3>${StringUtil.escapeHTML(article.name)}</h3>
</div>
</li>`;
})
- .join('');
+ .join("");
this.resultList!.innerHTML = html;
- DomUtil[html ? 'show' : 'hide'](this.resultList!);
+ DomUtil[html ? "show" : "hide"](this.resultList!);
if (html) {
- this.resultList!.querySelectorAll('.containerHeadline').forEach(item => {
- item.addEventListener('click', this.click.bind(this));
+ this.resultList!.querySelectorAll(".containerHeadline").forEach((item) => {
+ item.addEventListener("click", this.click.bind(this));
});
} else {
const parent = this.searchInput!.parentElement!;
- DomUtil.innerError(parent, Language.get('wcf.article.search.error.noResults'));
+ DomUtil.innerError(parent, Language.get("wcf.article.search.error.noResults"));
}
}
_ajaxSetup() {
return {
data: {
- actionName: 'search',
- className: 'wcf\\data\\article\\ArticleAction',
+ actionName: "search",
+ className: "wcf\\data\\article\\ArticleAction",
},
};
}
_dialogSetup() {
return {
- id: 'wcfUiArticleSearch',
+ id: "wcfUiArticleSearch",
options: {
onSetup: () => {
- this.searchInput = document.getElementById('wcfUiArticleSearchInput') as HTMLInputElement;
- this.searchInput.addEventListener('keydown', event => {
- if (event.key === 'Enter') {
+ this.searchInput = document.getElementById("wcfUiArticleSearchInput") as HTMLInputElement;
+ this.searchInput.addEventListener("keydown", (event) => {
+ if (event.key === "Enter") {
this.search(event);
}
});
const button = this.searchInput.nextElementSibling!;
- button.addEventListener('click', this.search.bind(this));
+ button.addEventListener("click", this.search.bind(this));
- this.resultContainer = document.getElementById('wcfUiArticleSearchResultContainer')!;
- this.resultList = document.getElementById('wcfUiArticleSearchResultList') as HTMLOListElement;
+ this.resultContainer = document.getElementById("wcfUiArticleSearchResultContainer")!;
+ this.resultList = document.getElementById("wcfUiArticleSearchResultList") as HTMLOListElement;
},
onShow: () => {
this.searchInput!.focus();
},
- title: Language.get('wcf.article.search'),
+ title: Language.get("wcf.article.search"),
},
source: `<div class="section">
<dl>
<dt>
- <label for="wcfUiArticleSearchInput">${Language.get('wcf.article.search.name')}</label>
+ <label for="wcfUiArticleSearchInput">${Language.get("wcf.article.search.name")}</label>
</dt>
<dd>
<div class="inputAddon">
</div>
<section id="wcfUiArticleSearchResultContainer" class="section" style="display: none;">
<header class="sectionHeader">
- <h2 class="sectionTitle">${Language.get('wcf.article.search.results')}</h2>
+ <h2 class="sectionTitle">${Language.get("wcf.article.search.results")}</h2>
</header>
<ol id="wcfUiArticleSearchResultList" class="containerList"></ol>
</section>`,
* @module WoltLabSuite/Core/Ui/CloseOverlay
*/
-import CallbackList from '../CallbackList';
+import CallbackList from "../CallbackList";
const _callbackList = new CallbackList();
* @see CallbackList.add
*/
add: _callbackList.add.bind(_callbackList),
-
+
/**
* @see CallbackList.remove
*/
remove: _callbackList.remove.bind(_callbackList),
-
+
/**
* Invokes all registered callbacks.
*/
execute() {
- _callbackList.forEach(null, callback => callback());
+ _callbackList.forEach(null, (callback) => callback());
},
};
-document.body.addEventListener('click', UiCloseOverlay.execute);
+document.body.addEventListener("click", UiCloseOverlay.execute);
export = UiCloseOverlay;
* @module WoltLabSuite/Core/Ui/Confirmation
*/
-import * as Core from '../Core';
-import * as Language from '../Language';
-import UiDialog from './Dialog';
-import { DialogCallbackObject } from './Dialog/Data';
+import * as Core from "../Core";
+import * as Language from "../Language";
+import UiDialog from "./Dialog";
+import { DialogCallbackObject } from "./Dialog/Data";
class UiConfirmation implements DialogCallbackObject {
private _active = false;
private callbackConfirm: CallbackConfirm;
constructor() {
- this.dialog = document.createElement('div');
- this.dialog.id = 'wcfSystemConfirmation';
- this.dialog.classList.add('systemConfirmation');
+ this.dialog = document.createElement("div");
+ this.dialog.id = "wcfSystemConfirmation";
+ this.dialog.classList.add("systemConfirmation");
- this.text = document.createElement('p');
+ this.text = document.createElement("p");
this.dialog.appendChild(this.text);
- this._content = document.createElement('div');
- this._content.id = 'wcfSystemConfirmationContent';
+ this._content = document.createElement("div");
+ this._content.id = "wcfSystemConfirmationContent";
this.dialog.appendChild(this._content);
- const formSubmit = document.createElement('div');
- formSubmit.classList.add('formSubmit');
+ const formSubmit = document.createElement("div");
+ formSubmit.classList.add("formSubmit");
this.dialog.appendChild(formSubmit);
- this.confirmButton = document.createElement('button');
- this.confirmButton.classList.add('buttonPrimary');
- this.confirmButton.textContent = Language.get('wcf.global.confirmation.confirm');
- this.confirmButton.addEventListener('click', (ev) => this._confirm());
+ this.confirmButton = document.createElement("button");
+ this.confirmButton.classList.add("buttonPrimary");
+ this.confirmButton.textContent = Language.get("wcf.global.confirmation.confirm");
+ this.confirmButton.addEventListener("click", (ev) => this._confirm());
formSubmit.appendChild(this.confirmButton);
- const cancelButton = document.createElement('button');
- cancelButton.textContent = Language.get('wcf.global.confirmation.cancel');
- cancelButton.addEventListener('click', () => {
+ const cancelButton = document.createElement("button");
+ cancelButton.textContent = Language.get("wcf.global.confirmation.cancel");
+ cancelButton.addEventListener("click", () => {
UiDialog.close(this);
});
formSubmit.appendChild(cancelButton);
public open(options: ConfirmationOptions): void {
this.parameters = options.parameters || {};
-
- this._content.innerHTML = (typeof options.template === 'string') ? options.template.trim() : '';
- this.text[options.messageIsHtml ? 'innerHTML' : 'textContent'] = options.message;
- if (typeof options.legacyCallback === 'function') {
- this.callbackCancel = parameters => {
- options.legacyCallback!('cancel', parameters, this.content);
+ this._content.innerHTML = typeof options.template === "string" ? options.template.trim() : "";
+ this.text[options.messageIsHtml ? "innerHTML" : "textContent"] = options.message;
+
+ if (typeof options.legacyCallback === "function") {
+ this.callbackCancel = (parameters) => {
+ options.legacyCallback!("cancel", parameters, this.content);
};
- this.callbackConfirm = parameters => {
- options.legacyCallback!('confirm', parameters, this.content);
+ this.callbackConfirm = (parameters) => {
+ options.legacyCallback!("confirm", parameters, this.content);
};
} else {
- if (typeof options.cancel !== 'function') {
- options.cancel = () => {
- };
+ if (typeof options.cancel !== "function") {
+ options.cancel = () => {};
}
this.callbackCancel = options.cancel;
*/
_confirm(): void {
this.callbackConfirm(this.parameters, this.content);
-
+
this._active = false;
- UiDialog.close('wcfSystemConfirmation');
+ UiDialog.close("wcfSystemConfirmation");
}
/**
_dialogSetup() {
return {
- id: 'wcfSystemConfirmation',
+ id: "wcfSystemConfirmation",
options: {
onClose: this._onClose.bind(this),
onShow: this._onShow.bind(this),
- title: Language.get('wcf.global.confirmation.title'),
+ title: Language.get("wcf.global.confirmation.title"),
},
};
}
return confirmation;
}
-type LegacyResult = 'cancel' | 'confirm';
+type LegacyResult = "cancel" | "confirm";
type CallbackParameters = {
- [key: string]: any,
-}
+ [key: string]: any;
+};
interface BasicConfirmationOptions {
message: string;
messageIsHtml?: boolean;
- parameters?: CallbackParameters,
+ parameters?: CallbackParameters;
template?: string;
}
return;
}
- options = Core.extend({
- cancel: null,
- confirm: null,
- legacyCallback: null,
- message: '',
- messageIsHtml: false,
- parameters: {},
- template: '',
- }, options) as ConfirmationOptions;
- options.message = (typeof (options.message as any) === 'string') ? options.message.trim() : '';
+ options = Core.extend(
+ {
+ cancel: null,
+ confirm: null,
+ legacyCallback: null,
+ message: "",
+ messageIsHtml: false,
+ parameters: {},
+ template: "",
+ },
+ options
+ ) as ConfirmationOptions;
+ options.message = typeof (options.message as any) === "string" ? options.message.trim() : "";
if (!options.message) {
throw new Error("Expected a non-empty string for option 'message'.");
}
- if (typeof options.confirm !== 'function' && typeof options.legacyCallback !== 'function') {
+ if (typeof options.confirm !== "function" && typeof options.legacyCallback !== "function") {
throw new TypeError("Expected a valid callback for option 'confirm'.");
}
* @module WoltLabSuite/Core/Ui/Dialog
*/
-import * as Core from '../Core';
-import DomChangeListener from '../Dom/Change/Listener';
-import * as UiScreen from './Screen';
-import DomUtil from '../Dom/Util';
+import * as Core from "../Core";
+import DomChangeListener from "../Dom/Change/Listener";
+import * as UiScreen from "./Screen";
+import DomUtil from "../Dom/Util";
import {
DialogCallbackObject,
DialogData,
DialogOptions,
DialogHtml,
AjaxInitialization,
-} from './Dialog/Data';
-import * as Language from '../Language';
-import * as Environment from '../Environment';
-import * as EventHandler from '../Event/Handler';
-import UiDropdownSimple from './Dropdown/Simple';
+} from "./Dialog/Data";
+import * as Language from "../Language";
+import * as Environment from "../Environment";
+import * as EventHandler from "../Event/Handler";
+import UiDropdownSimple from "./Dropdown/Simple";
let _activeDialog: string | null = null;
let _callbackFocus: (event: FocusEvent) => void;
const _dialogToObject = new Map<ElementId, DialogCallbackObject>();
let _focusedBeforeDialog: Element | null;
let _keyupListener: (event: KeyboardEvent) => boolean;
-const _validCallbacks = ['onBeforeClose', 'onClose', 'onShow'];
+const _validCallbacks = ["onBeforeClose", "onClose", "onShow"];
// list of supported `input[type]` values for dialog submit
-const _validInputTypes = ['number', 'password', 'search', 'tel', 'text', 'url'];
+const _validInputTypes = ["number", "password", "search", "tel", "text", "url"];
const _focusableElements = [
'a[href]:not([tabindex^="-"]):not([inert])',
'area[href]:not([tabindex^="-"]):not([inert])',
- 'input:not([disabled]):not([inert])',
- 'select:not([disabled]):not([inert])',
- 'textarea:not([disabled]):not([inert])',
- 'button:not([disabled]):not([inert])',
+ "input:not([disabled]):not([inert])",
+ "select:not([disabled]):not([inert])",
+ "textarea:not([disabled]):not([inert])",
+ "button:not([disabled]):not([inert])",
'iframe:not([tabindex^="-"]):not([inert])',
'audio:not([tabindex^="-"]):not([inert])',
'video:not([tabindex^="-"]):not([inert])',
* Sets up global container and internal variables.
*/
setup(): void {
- _container = document.createElement('div');
- _container.classList.add('dialogOverlay');
- _container.setAttribute('aria-hidden', 'true');
- _container.addEventListener('mousedown', (ev) => this._closeOnBackdrop(ev));
- _container.addEventListener('wheel', event => {
- if (event.target === _container) {
- event.preventDefault();
- }
- }, {passive: false});
+ _container = document.createElement("div");
+ _container.classList.add("dialogOverlay");
+ _container.setAttribute("aria-hidden", "true");
+ _container.addEventListener("mousedown", (ev) => this._closeOnBackdrop(ev));
+ _container.addEventListener(
+ "wheel",
+ (event) => {
+ if (event.target === _container) {
+ event.preventDefault();
+ }
+ },
+ { passive: false }
+ );
- document.getElementById('content')!.appendChild(_container);
+ document.getElementById("content")!.appendChild(_container);
_keyupListener = (event: KeyboardEvent): boolean => {
if (event.key === "Escape") {
const target = event.target as HTMLElement;
- if (target.nodeName !== 'INPUT' && target.nodeName !== 'TEXTAREA') {
+ if (target.nodeName !== "INPUT" && target.nodeName !== "TEXTAREA") {
this.close(_activeDialog!);
return false;
return true;
};
- UiScreen.on('screen-xs', {
+ UiScreen.on("screen-xs", {
match() {
_dialogFullHeight = true;
},
});
this._initStaticDialogs();
- DomChangeListener.add('Ui/Dialog', () => {
+ DomChangeListener.add("Ui/Dialog", () => {
this._initStaticDialogs();
});
UiScreen.setDialogContainer(_container);
- window.addEventListener('resize', () => {
- _dialogs.forEach(dialog => {
- if (!Core.stringToBool(dialog.dialog.getAttribute('aria-hidden'))) {
- this.rebuild(dialog.dialog.dataset.id || '');
+ window.addEventListener("resize", () => {
+ _dialogs.forEach((dialog) => {
+ if (!Core.stringToBool(dialog.dialog.getAttribute("aria-hidden"))) {
+ this.rebuild(dialog.dialog.dataset.id || "");
}
});
});
},
_initStaticDialogs(): void {
- document.querySelectorAll('.jsStaticDialog').forEach((button: HTMLElement) => {
- button.classList.remove('jsStaticDialog');
+ document.querySelectorAll(".jsStaticDialog").forEach((button: HTMLElement) => {
+ button.classList.remove("jsStaticDialog");
- const id = button.dataset.dialogId || '';
+ const id = button.dataset.dialogId || "";
if (id) {
const container = document.getElementById(id);
if (container !== null) {
- container.classList.remove('jsStaticDialogContent');
- container.dataset.isStaticDialog = 'true';
+ container.classList.remove("jsStaticDialogContent");
+ container.dataset.isStaticDialog = "true";
DomUtil.hide(container);
- button.addEventListener('click', event => {
+ button.addEventListener("click", (event) => {
event.preventDefault();
- this.openStatic(container.id, null, {title: container.dataset.title || ''});
+ this.openStatic(container.id, null, { title: container.dataset.title || "" });
});
}
}
let dialogData = _dialogObjects.get(callbackObject);
if (dialogData && Core.isPlainObject(dialogData)) {
// dialog already exists
- return this.openStatic(dialogData.id, typeof html === 'undefined' ? null : html);
+ return this.openStatic(dialogData.id, typeof html === "undefined" ? null : html);
}
// initialize a new dialog
- if (typeof callbackObject._dialogSetup !== 'function') {
+ if (typeof callbackObject._dialogSetup !== "function") {
throw new Error("Callback object does not implement the method '_dialogSetup()'.");
}
}
const id = setupData.id;
- dialogData = {id};
+ dialogData = { id };
let dialogElement: HTMLElement | null;
if (setupData.source === undefined) {
dialogElement = document.getElementById(id);
if (dialogElement === null) {
- throw new Error("Element id '" + id + "' is invalid and no source attribute was given. If you want to use the `html` argument instead, please add `source: null` to your dialog configuration.");
+ throw new Error(
+ "Element id '" +
+ id +
+ "' is invalid and no source attribute was given. If you want to use the `html` argument instead, please add `source: null` to your dialog configuration."
+ );
}
setupData.source = document.createDocumentFragment();
setupData.source.appendChild(dialogElement);
- dialogElement.removeAttribute('id');
+ dialogElement.removeAttribute("id");
DomUtil.show(dialogElement);
} else if (setupData.source === null) {
// `null` means there is no static markup and `html` should be used instead
setupData.source = html;
- } else if (typeof setupData.source === 'function') {
+ } else if (typeof setupData.source === "function") {
setupData.source();
} else if (Core.isPlainObject(setupData.source)) {
- if (typeof html === 'string' && html.trim() !== '') {
+ if (typeof html === "string" && html.trim() !== "") {
setupData.source = html;
} else {
- import('../Ajax').then(Ajax => {
+ import("../Ajax").then((Ajax) => {
const source = setupData.source as AjaxInitialization;
- Ajax.api(this as any, source.data, data => {
- if (data.returnValues && typeof data.returnValues.template === 'string') {
+ Ajax.api(this as any, source.data, (data) => {
+ if (data.returnValues && typeof data.returnValues.template === "string") {
this.open(callbackObject, data.returnValues.template);
- if (typeof source.after === 'function') {
+ if (typeof source.after === "function") {
source.after(_dialogs.get(id)!.content, data);
}
}
return {};
}
} else {
- if (typeof setupData.source === 'string') {
- dialogElement = document.createElement('div');
+ if (typeof setupData.source === "string") {
+ dialogElement = document.createElement("div");
dialogElement.id = id;
DomUtil.setInnerHtml(dialogElement, setupData.source);
openStatic(id: string, html: DialogHtml, options?: DialogOptions): DialogData {
UiScreen.pageOverlayOpen();
- if (Environment.platform() !== 'desktop') {
+ if (Environment.platform() !== "desktop") {
if (!this.isOpen(id)) {
UiScreen.scrollDisable();
}
if (_dialogs.has(id)) {
this._updateDialog(id, html as string);
} else {
- options = Core.extend({
- backdropCloseOnClick: true,
- closable: true,
- closeButtonLabel: Language.get('wcf.global.button.close'),
- closeConfirmMessage: '',
- disableContentPadding: false,
- title: '',
-
- onBeforeClose: null,
- onClose: null,
- onShow: null,
- }, options || {}) as InternalDialogOptions;
+ options = Core.extend(
+ {
+ backdropCloseOnClick: true,
+ closable: true,
+ closeButtonLabel: Language.get("wcf.global.button.close"),
+ closeConfirmMessage: "",
+ disableContentPadding: false,
+ title: "",
+
+ onBeforeClose: null,
+ onClose: null,
+ onShow: null,
+ },
+ options || {}
+ ) as InternalDialogOptions;
if (!options.closable) options.backdropCloseOnClick = false;
if (options.closeConfirmMessage) {
- options.onBeforeClose = id => {
- import('./Confirmation').then(UiConfirmation => {
+ options.onBeforeClose = (id) => {
+ import("./Confirmation").then((UiConfirmation) => {
UiConfirmation.show({
confirm: this.close.bind(this, id),
- message: options!.closeConfirmMessage || '',
+ message: options!.closeConfirmMessage || "",
});
});
};
// iOS breaks `position: fixed` when input elements or `contenteditable`
// are focused, this will freeze the screen and force Safari to scroll
// to the input field
- if (Environment.platform() === 'ios') {
+ if (Environment.platform() === "ios") {
window.setTimeout(() => {
- data.content.querySelector<HTMLElement>('input, textarea')?.focus();
+ data.content.querySelector<HTMLElement>("input, textarea")?.focus();
}, 200);
}
throw new Error("Expected a valid dialog id, '" + id + "' does not match any active dialog.");
}
- const dialogTitle = data.dialog.querySelector('.dialogTitle');
+ const dialogTitle = data.dialog.querySelector(".dialogTitle");
if (dialogTitle) {
dialogTitle.textContent = title;
}
* Sets a callback function on runtime.
*/
setCallback(id: ElementIdOrCallbackObject, key: string, value: (...args: any[]) => void | null): void {
- if (typeof id === 'object') {
+ if (typeof id === "object") {
const dialogData = _dialogObjects.get(id);
if (dialogData !== undefined) {
id = dialogData.id;
throw new Error("Invalid callback identifier, '" + key + "' is not recognized.");
}
- if (typeof value !== 'function' && value !== null) {
- throw new Error("Only functions or the 'null' value are acceptable callback values ('" + typeof value + "' given).");
+ if (typeof value !== "function" && value !== null) {
+ throw new Error(
+ "Only functions or the 'null' value are acceptable callback values ('" + typeof value + "' given)."
+ );
}
data[key] = value;
}
}
- const dialog = document.createElement('div');
- dialog.classList.add('dialogContainer');
- dialog.setAttribute('aria-hidden', 'true');
- dialog.setAttribute('role', 'dialog');
+ const dialog = document.createElement("div");
+ dialog.classList.add("dialogContainer");
+ dialog.setAttribute("aria-hidden", "true");
+ dialog.setAttribute("role", "dialog");
dialog.id = id;
- const header = document.createElement('header');
+ const header = document.createElement("header");
dialog.appendChild(header);
const titleId = DomUtil.getUniqueId();
- dialog.setAttribute('aria-labelledby', titleId);
+ dialog.setAttribute("aria-labelledby", titleId);
- const title = document.createElement('span');
- title.classList.add('dialogTitle');
+ const title = document.createElement("span");
+ title.classList.add("dialogTitle");
title.textContent = options.title!;
title.id = titleId;
header.appendChild(title);
if (options.closable) {
- const closeButton = document.createElement('a');
- closeButton.className = 'dialogCloseButton jsTooltip';
- closeButton.href = '#';
- closeButton.setAttribute('role', 'button');
+ const closeButton = document.createElement("a");
+ closeButton.className = "dialogCloseButton jsTooltip";
+ closeButton.href = "#";
+ closeButton.setAttribute("role", "button");
closeButton.tabIndex = 0;
closeButton.title = options.closeButtonLabel;
- closeButton.setAttribute('aria-label', options.closeButtonLabel);
- closeButton.addEventListener('click', (ev) => this._close(ev));
+ closeButton.setAttribute("aria-label", options.closeButtonLabel);
+ closeButton.addEventListener("click", (ev) => this._close(ev));
header.appendChild(closeButton);
- const span = document.createElement('span');
- span.className = 'icon icon24 fa-times';
+ const span = document.createElement("span");
+ span.className = "icon icon24 fa-times";
closeButton.appendChild(span);
}
- const contentContainer = document.createElement('div');
- contentContainer.classList.add('dialogContent');
- if (options.disableContentPadding) contentContainer.classList.add('dialogContentNoPadding');
+ const contentContainer = document.createElement("div");
+ contentContainer.classList.add("dialogContent");
+ if (options.disableContentPadding) contentContainer.classList.add("dialogContentNoPadding");
dialog.appendChild(contentContainer);
- contentContainer.addEventListener('wheel', event => {
- let allowScroll = false;
- let element: HTMLElement | null = event.target as HTMLElement;
- let clientHeight, scrollHeight, scrollTop;
- while (true) {
- clientHeight = element.clientHeight;
- scrollHeight = element.scrollHeight;
-
- if (clientHeight < scrollHeight) {
- scrollTop = element.scrollTop;
+ contentContainer.addEventListener(
+ "wheel",
+ (event) => {
+ let allowScroll = false;
+ let element: HTMLElement | null = event.target as HTMLElement;
+ let clientHeight, scrollHeight, scrollTop;
+ while (true) {
+ clientHeight = element.clientHeight;
+ scrollHeight = element.scrollHeight;
+
+ if (clientHeight < scrollHeight) {
+ scrollTop = element.scrollTop;
+
+ // negative value: scrolling up
+ if (event.deltaY < 0 && scrollTop > 0) {
+ allowScroll = true;
+ break;
+ } else if (event.deltaY > 0 && scrollTop + clientHeight < scrollHeight) {
+ allowScroll = true;
+ break;
+ }
+ }
- // negative value: scrolling up
- if (event.deltaY < 0 && scrollTop > 0) {
- allowScroll = true;
- break;
- } else if (event.deltaY > 0 && (scrollTop + clientHeight < scrollHeight)) {
- allowScroll = true;
+ if (!element || element === contentContainer) {
break;
}
- }
- if (!element || element === contentContainer) {
- break;
+ element = element.parentNode as HTMLElement;
}
- element = element.parentNode as HTMLElement;
- }
-
- if (!allowScroll) {
- event.preventDefault();
- }
- }, {passive: false});
+ if (!allowScroll) {
+ event.preventDefault();
+ }
+ },
+ { passive: false }
+ );
let content: HTMLElement;
if (element === null) {
- if (typeof html === 'string') {
- content = document.createElement('div');
+ if (typeof html === "string") {
+ content = document.createElement("div");
content.id = id;
DomUtil.setInnerHtml(content, html);
} else if (html instanceof DocumentFragment) {
}
}
- if (children[0].nodeName !== 'DIV' || children.length > 1) {
- content = document.createElement('div');
+ if (children[0].nodeName !== "DIV" || children.length > 1) {
+ content = document.createElement("div");
content.id = id;
content.appendChild(html);
} else {
contentContainer.appendChild(content);
- if (content.style.getPropertyValue('display') === 'none') {
+ if (content.style.getPropertyValue("display") === "none") {
DomUtil.show(content);
}
_container.insertBefore(dialog, _container.firstChild);
- if (typeof options.onSetup === 'function') {
+ if (typeof options.onSetup === "function") {
options.onSetup(content);
}
throw new Error("Expected a valid dialog id, '" + id + "' does not match any active dialog.");
}
- if (typeof html === 'string') {
+ if (typeof html === "string") {
DomUtil.setInnerHtml(data.content, html);
}
- if (Core.stringToBool(data.dialog.getAttribute('aria-hidden'))) {
+ if (Core.stringToBool(data.dialog.getAttribute("aria-hidden"))) {
// close existing dropdowns
UiDropdownSimple.closeAll();
window.WCF.Dropdown.Interactive.Handler.closeAll();
if (_callbackFocus === null) {
_callbackFocus = this._maintainFocus.bind(this);
- document.body.addEventListener('focus', _callbackFocus, {capture: true});
+ document.body.addEventListener("focus", _callbackFocus, { capture: true });
}
- if (data.closable && Core.stringToBool(_container.getAttribute('aria-hidden'))) {
- window.addEventListener('keyup', _keyupListener);
+ if (data.closable && Core.stringToBool(_container.getAttribute("aria-hidden"))) {
+ window.addEventListener("keyup", _keyupListener);
}
// Move the dialog to the front to prevent it being hidden behind already open dialogs
// if it was previously visible.
data.dialog.parentNode!.insertBefore(data.dialog, data.dialog.parentNode!.firstChild);
- data.dialog.setAttribute('aria-hidden', 'false');
- _container.setAttribute('aria-hidden', 'false');
- _container.setAttribute('close-on-click', (data.backdropCloseOnClick ? 'true' : 'false'));
+ data.dialog.setAttribute("aria-hidden", "false");
+ _container.setAttribute("aria-hidden", "false");
+ _container.setAttribute("close-on-click", data.backdropCloseOnClick ? "true" : "false");
_activeDialog = id;
// Keep a reference to the currently focused element to be able to restore it later.
_focusedBeforeDialog = document.activeElement;
// Set the focus to the first focusable child of the dialog element.
- const closeButton = data.header.querySelector('.dialogCloseButton');
- if (closeButton) closeButton.setAttribute('inert', 'true');
+ const closeButton = data.header.querySelector(".dialogCloseButton");
+ if (closeButton) closeButton.setAttribute("inert", "true");
this._setFocusToFirstItem(data.dialog, false);
- if (closeButton) closeButton.removeAttribute('inert');
+ if (closeButton) closeButton.removeAttribute("inert");
- if (typeof data.onShow === 'function') {
+ if (typeof data.onShow === "function") {
data.onShow(data.content);
}
- if (Core.stringToBool(data.content.dataset.isStaticDialog || '')) {
- EventHandler.fire('com.woltlab.wcf.dialog', 'openStatic', {
+ if (Core.stringToBool(data.content.dataset.isStaticDialog || "")) {
+ EventHandler.fire("com.woltlab.wcf.dialog", "openStatic", {
content: data.content,
id: id,
});
if (_activeDialog) {
const data = _dialogs.get(_activeDialog) as DialogData;
const target = event.target as HTMLElement;
- if (!data.dialog.contains(target) && !target.closest('.dropdownMenuContainer') && !target.closest('.datePicker')) {
+ if (
+ !data.dialog.contains(target) &&
+ !target.closest(".dropdownMenuContainer") &&
+ !target.closest(".datePicker")
+ ) {
this._setFocusToFirstItem(data.dialog, true);
}
}
let focusElement = this._getFirstFocusableChild(dialog);
if (focusElement !== null) {
if (maintain) {
- if (focusElement.id === 'username' || (focusElement as HTMLInputElement).name === 'username') {
- if (Environment.browser() === 'safari' && Environment.platform() === 'ios') {
- // iOS Safari's username/password autofill breaks if the input field is focused
+ if (focusElement.id === "username" || (focusElement as HTMLInputElement).name === "username") {
+ if (Environment.browser() === "safari" && Environment.platform() === "ios") {
+ // iOS Safari's username/password autofill breaks if the input field is focused
focusElement = null;
}
}
// Setting the focus to a select element in iOS is pretty strange, because
// it focuses it, but also displays the keyboard for a fraction of a second,
// causing it to pop out from below and immediately vanish.
- //
+ //
// iOS will only show the keyboard if an input element is focused *and* the
// focus is an immediate result of a user interaction. This method must be
// assumed to be called from within a click event, but we want to set the
// focus without triggering the keyboard.
- //
+ //
// We can break the condition by wrapping it in a setTimeout() call,
// effectively tricking iOS into focusing the element without showing the
// keyboard.
},
_getFirstFocusableChild(element: HTMLElement): HTMLElement | null {
- const nodeList = element.querySelectorAll<HTMLElement>(_focusableElements.join(','));
+ const nodeList = element.querySelectorAll<HTMLElement>(_focusableElements.join(","));
for (let i = 0, length = nodeList.length; i < length; i++) {
if (nodeList[i].offsetWidth && nodeList[i].offsetHeight && nodeList[i].getClientRects().length) {
return nodeList[i];
}
// ignore non-active dialogs
- if (Core.stringToBool(data.dialog.getAttribute('aria-hidden'))) {
+ if (Core.stringToBool(data.dialog.getAttribute("aria-hidden"))) {
return;
}
const contentContainer = data.content.parentNode as HTMLElement;
- const formSubmit = data.content.querySelector('.formSubmit') as HTMLElement;
+ const formSubmit = data.content.querySelector(".formSubmit") as HTMLElement;
let unavailableHeight = 0;
if (formSubmit !== null) {
- contentContainer.classList.add('dialogForm');
- formSubmit.classList.add('dialogFormSubmit');
+ contentContainer.classList.add("dialogForm");
+ formSubmit.classList.add("dialogFormSubmit");
unavailableHeight += DomUtil.outerHeight(formSubmit);
// working around fractional values, without visually changing anything.
unavailableHeight -= 1;
- contentContainer.style.setProperty('margin-bottom', unavailableHeight + 'px', '');
+ contentContainer.style.setProperty("margin-bottom", unavailableHeight + "px", "");
} else {
- contentContainer.classList.remove('dialogForm');
- contentContainer.style.removeProperty('margin-bottom');
+ contentContainer.classList.remove("dialogForm");
+ contentContainer.style.removeProperty("margin-bottom");
}
unavailableHeight += DomUtil.outerHeight(data.header);
- const maximumHeight = (window.innerHeight * (_dialogFullHeight ? 1 : 0.8)) - unavailableHeight;
- contentContainer.style.setProperty('max-height', ~~maximumHeight + 'px', '');
+ const maximumHeight = window.innerHeight * (_dialogFullHeight ? 1 : 0.8) - unavailableHeight;
+ contentContainer.style.setProperty("max-height", ~~maximumHeight + "px", "");
// fix for a calculation bug in Chrome causing the scrollbar to overlap the border
- if (Environment.browser() === 'chrome') {
+ if (Environment.browser() === "chrome") {
if (data.content.scrollHeight > maximumHeight) {
- data.content.style.setProperty('margin-right', '-1px', '');
+ data.content.style.setProperty("margin-right", "-1px", "");
} else {
- data.content.style.removeProperty('margin-right');
+ data.content.style.removeProperty("margin-right");
}
}
// Chrome and Safari use heavy anti-aliasing when the dialog's width
// cannot be evenly divided, causing the whole text to become blurry
- if (Environment.browser() === 'chrome' || Environment.browser() === 'safari') {
+ if (Environment.browser() === "chrome" || Environment.browser() === "safari") {
// The new Microsoft Edge is detected as "chrome", because effectively we're detecting
// Chromium rather than Chrome specifically. The workaround for fractional pixels does
// not work well in Edge, there seems to be a different logic for fractional positions,
// causing the text to be blurry.
- //
+ //
// We can use `backface-visibility: hidden` to prevent the anti aliasing artifacts in
// WebKit/Blink, which will also prevent some weird font rendering issues when resizing.
- contentContainer.classList.add('jsWebKitFractionalPixelFix');
+ contentContainer.classList.add("jsWebKitFractionalPixelFix");
}
const callbackObject = _dialogToObject.get(id);
//noinspection JSUnresolvedVariable
- if (callbackObject !== undefined && typeof callbackObject._dialogSubmit === 'function') {
+ if (callbackObject !== undefined && typeof callbackObject._dialogSubmit === "function") {
const inputFields = data.content.querySelectorAll<HTMLInputElement>('input[data-dialog-submit-on-enter="true"]');
- const submitButton = data.content.querySelector('.formSubmit > input[type="submit"], .formSubmit > button[data-type="submit"]');
+ const submitButton = data.content.querySelector(
+ '.formSubmit > input[type="submit"], .formSubmit > button[data-type="submit"]'
+ );
if (submitButton === null) {
// check if there is at least one input field with submit handling,
// otherwise we'll assume the dialog has not been populated yet
if (data.submitButton !== submitButton) {
data.submitButton = submitButton as HTMLElement;
- submitButton.addEventListener('click', event => {
+ submitButton.addEventListener("click", (event) => {
event.preventDefault();
this._submit(id);
});
const _callbackKeydown = (event: KeyboardEvent): void => {
- if (event.key === 'Enter') {
+ if (event.key === "Enter") {
event.preventDefault();
this._submit(id);
data.inputFields.add(inputField);
- inputField.addEventListener('keydown', _callbackKeydown);
+ inputField.addEventListener("keydown", _callbackKeydown);
}
}
}
const data = _dialogs.get(id);
let isValid = true;
- data!.inputFields.forEach(inputField => {
+ data!.inputFields.forEach((inputField) => {
if (inputField.required) {
- if (inputField.value.trim() === '') {
- DomUtil.innerError(inputField, Language.get('wcf.global.form.error.empty'));
+ if (inputField.value.trim() === "") {
+ DomUtil.innerError(inputField, Language.get("wcf.global.form.error.empty"));
isValid = false;
} else {
if (isValid) {
const callbackObject = _dialogToObject.get(id) as DialogCallbackObject;
- if (typeof callbackObject._dialogSubmit === 'function') {
+ if (typeof callbackObject._dialogSubmit === "function") {
callbackObject._dialogSubmit();
}
}
event.preventDefault();
const data = _dialogs.get(_activeDialog!) as DialogData;
- if (typeof data.onBeforeClose === 'function') {
+ if (typeof data.onBeforeClose === "function") {
data.onBeforeClose(_activeDialog!);
return false;
return;
}
- if (Core.stringToBool(_container.getAttribute('close-on-click'))) {
+ if (Core.stringToBool(_container.getAttribute("close-on-click"))) {
this._close(event);
} else {
event.preventDefault();
throw new Error("Expected a valid dialog id, '" + id + "' does not match any active dialog.");
}
- data.dialog.setAttribute('aria-hidden', 'true');
+ data.dialog.setAttribute("aria-hidden", "true");
// Move the keyboard focus away from a now hidden element.
const activeElement = document.activeElement as HTMLElement;
- if (activeElement.closest('.dialogContainer') === data.dialog) {
+ if (activeElement.closest(".dialogContainer") === data.dialog) {
activeElement.blur();
}
- if (typeof data.onClose === 'function') {
+ if (typeof data.onClose === "function") {
data.onClose(id);
}
_activeDialog = null;
for (let i = 0; i < _container.childElementCount; i++) {
const child = _container.children[i] as HTMLElement;
- if (!Core.stringToBool(child.getAttribute('aria-hidden'))) {
- _activeDialog = child.dataset.id || '';
+ if (!Core.stringToBool(child.getAttribute("aria-hidden"))) {
+ _activeDialog = child.dataset.id || "";
break;
}
}
UiScreen.pageOverlayClose();
if (_activeDialog === null) {
- _container.setAttribute('aria-hidden', 'true');
- _container.dataset.closeOnClick = 'false';
+ _container.setAttribute("aria-hidden", "true");
+ _container.dataset.closeOnClick = "false";
if (data.closable) {
- window.removeEventListener('keyup', _keyupListener);
+ window.removeEventListener("keyup", _keyupListener);
}
} else {
data = _dialogs.get(_activeDialog) as DialogData;
- _container.dataset.closeOnClick = data.backdropCloseOnClick ? 'true' : 'false';
+ _container.dataset.closeOnClick = data.backdropCloseOnClick ? "true" : "false";
}
- if (Environment.platform() !== 'desktop') {
+ if (Environment.platform() !== "desktop") {
UiScreen.scrollEnable();
}
},
*/
isOpen(id: ElementIdOrCallbackObject): boolean {
const data = this.getDialog(id);
- return data !== undefined && data.dialog.getAttribute('aria-hidden') === 'false';
+ return data !== undefined && data.dialog.getAttribute("aria-hidden") === "false";
},
/**
* @param {Object} callbackObject the same object that was used to invoke `_dialogSetup()` on first call
*/
destroy(callbackObject: DialogCallbackObject): void {
- if (typeof callbackObject !== 'object') {
+ if (typeof callbackObject !== "object") {
throw new TypeError("Expected the callback object as parameter.");
}
* @protected
*/
_getDialogId(id: ElementIdOrCallbackObject): DialogId {
- if (typeof id === 'object') {
+ if (typeof id === "object") {
const dialogData = _dialogObjects.get(id);
if (dialogData !== undefined) {
return dialogData.id;
-import { RequestPayload, ResponseData } from '../../Ajax/Data';
+import { RequestPayload, ResponseData } from "../../Ajax/Data";
export type DialogHtml = DocumentFragment | string | null;
* @module WoltLabSuite/Core/Ui/Dropdown/Builder
*/
-import * as Core from '../../Core';
-import UiDropdownSimple from './Simple';
+import * as Core from "../../Core";
+import UiDropdownSimple from "./Simple";
const _validIconSizes = [16, 24, 32, 48, 64, 96, 144];
function validateList(list: HTMLUListElement): void {
if (!(list instanceof HTMLUListElement)) {
- throw new TypeError('Expected a reference to an <ul> element.');
+ throw new TypeError("Expected a reference to an <ul> element.");
}
- if (!list.classList.contains('dropdownMenu')) {
- throw new Error('List does not appear to be a dropdown menu.');
+ if (!list.classList.contains("dropdownMenu")) {
+ throw new Error("List does not appear to be a dropdown menu.");
}
}
function buildItemFromData(data: DropdownBuilderItemData): HTMLLIElement {
- const item = document.createElement('li');
+ const item = document.createElement("li");
// handle special `divider` type
- if (data === 'divider') {
- item.className = 'dropdownDivider';
+ if (data === "divider") {
+ item.className = "dropdownDivider";
return item;
}
- if (typeof data.identifier === 'string') {
+ if (typeof data.identifier === "string") {
item.dataset.identifier = data.identifier;
}
- const link = document.createElement('a');
- link.href = (typeof data.href === 'string') ? data.href : '#';
- if (typeof data.callback === 'function') {
- link.addEventListener('click', event => {
+ const link = document.createElement("a");
+ link.href = typeof data.href === "string" ? data.href : "#";
+ if (typeof data.callback === "function") {
+ link.addEventListener("click", (event) => {
event.preventDefault();
data.callback!(link);
});
- } else if (link.href === '#') {
- throw new Error('Expected either a `href` value or a `callback`.');
+ } else if (link.href === "#") {
+ throw new Error("Expected either a `href` value or a `callback`.");
}
if (data.attributes && Core.isPlainObject(data.attributes)) {
- Object.keys(data.attributes).forEach(key => {
+ Object.keys(data.attributes).forEach((key) => {
const value = data.attributes![key];
- if (typeof (value as any) !== 'string') {
- throw new Error('Expected only string values.');
+ if (typeof (value as any) !== "string") {
+ throw new Error("Expected only string values.");
}
// Support the dash notation for backwards compatibility.
- if (key.indexOf('-') !== -1) {
+ if (key.indexOf("-") !== -1) {
link.setAttribute(`data-${key}`, value);
} else {
link.dataset[key] = value;
item.appendChild(link);
- if (typeof data.icon !== 'undefined' && Core.isPlainObject(data.icon)) {
- if (typeof (data.icon.name as any) !== 'string') {
- throw new TypeError('Expected a valid icon name.');
+ if (typeof data.icon !== "undefined" && Core.isPlainObject(data.icon)) {
+ if (typeof (data.icon.name as any) !== "string") {
+ throw new TypeError("Expected a valid icon name.");
}
let size = 16;
- if (typeof data.icon.size === 'number' && _validIconSizes.indexOf(~~data.icon.size) !== -1) {
+ if (typeof data.icon.size === "number" && _validIconSizes.indexOf(~~data.icon.size) !== -1) {
size = ~~data.icon.size;
}
- const icon = document.createElement('span');
- icon.className = 'icon icon' + size + ' fa-' + data.icon.name;
+ const icon = document.createElement("span");
+ icon.className = "icon icon" + size + " fa-" + data.icon.name;
link.appendChild(icon);
}
- const label = (typeof (data.label as any) === 'string') ? data.label!.trim() : '';
- const labelHtml = (typeof (data.labelHtml as any) === 'string') ? data.labelHtml!.trim() : '';
- if (label === '' && labelHtml === '') {
- throw new TypeError('Expected either a label or a `labelHtml`.');
+ const label = typeof (data.label as any) === "string" ? data.label!.trim() : "";
+ const labelHtml = typeof (data.labelHtml as any) === "string" ? data.labelHtml!.trim() : "";
+ if (label === "" && labelHtml === "") {
+ throw new TypeError("Expected either a label or a `labelHtml`.");
}
- const span = document.createElement('span');
- span[label ? 'textContent' : 'innerHTML'] = (label) ? label : labelHtml;
- link.appendChild(document.createTextNode(' '));
+ const span = document.createElement("span");
+ span[label ? "textContent" : "innerHTML"] = label ? label : labelHtml;
+ link.appendChild(document.createTextNode(" "));
link.appendChild(span);
return item;
* into the DOM by the callee.
*/
export function create(items: DropdownBuilderItemData[], identifier?: string): HTMLUListElement {
- const list = document.createElement('ul');
- list.className = 'dropdownMenu';
- if (typeof identifier === 'string') {
+ const list = document.createElement("ul");
+ list.className = "dropdownMenu";
+ if (typeof identifier === "string") {
list.dataset.identifier = identifier;
}
validateList(list);
if (!Array.isArray(items)) {
- throw new TypeError('Expected an array of items.');
+ throw new TypeError("Expected an array of items.");
}
const length = items.length;
if (length === 0) {
- throw new Error('Expected a non-empty list of items.');
+ throw new Error("Expected a non-empty list of items.");
}
if (length === 1) {
appendItem(list, items[0]);
} else {
const fragment = document.createDocumentFragment();
- items.forEach(item => {
+ items.forEach((item) => {
fragment.appendChild(buildItemFromData(item));
});
list.appendChild(fragment);
export function setItems(list: HTMLUListElement, items: DropdownBuilderItemData[]): void {
validateList(list);
- list.innerHTML = '';
+ list.innerHTML = "";
appendItems(list, items);
}
UiDropdownSimple.initFragment(button, list);
- button.addEventListener('click', event => {
+ button.addEventListener("click", (event) => {
event.preventDefault();
event.stopPropagation();
* be created.
*/
export function divider(): string {
- return 'divider';
+ return "divider";
}
interface BaseItemData {
icon?: {
name: string;
size?: 16 | 24 | 32 | 48 | 64 | 96 | 144;
- }
+ };
identifier?: string;
label?: string;
labelHtml?: string;
-export type NotificationAction = 'close' | 'open';
+export type NotificationAction = "close" | "open";
export type NotificationCallback = (containerId: string, action: NotificationAction) => void;
* @module WoltLabSuite/Core/Ui/Dropdown/Reusable
*/
-import UiDropdownSimple from './Simple';
-import { NotificationCallback } from './Data';
+import UiDropdownSimple from "./Simple";
+import { NotificationCallback } from "./Data";
const _dropdowns = new Map<string, string>();
let _ghostElementId = 0;
return;
}
- const ghostElement = document.createElement('div');
- ghostElement.id = 'reusableDropdownGhost' + _ghostElementId++;
+ const ghostElement = document.createElement("div");
+ ghostElement.id = "reusableDropdownGhost" + _ghostElementId++;
UiDropdownSimple.initFragment(ghostElement, menu);
* @module WoltLabSuite/Core/Ui/Dropdown/Simple
*/
-import CallbackList from '../../CallbackList';
-import * as Core from '../../Core';
-import DomChangeListener from '../../Dom/Change/Listener';
-import * as DomTraverse from '../../Dom/Traverse';
-import DomUtil from '../../Dom/Util';
-import * as UiAlignment from '../Alignment';
-import UiCloseOverlay from '../CloseOverlay';
-import { AllowFlip } from '../Alignment';
-import { NotificationAction, NotificationCallback } from './Data';
+import CallbackList from "../../CallbackList";
+import * as Core from "../../Core";
+import DomChangeListener from "../../Dom/Change/Listener";
+import * as DomTraverse from "../../Dom/Traverse";
+import DomUtil from "../../Dom/Util";
+import * as UiAlignment from "../Alignment";
+import UiCloseOverlay from "../CloseOverlay";
+import { AllowFlip } from "../Alignment";
+import { NotificationAction, NotificationCallback } from "./Data";
let _availableDropdowns: HTMLCollectionOf<HTMLElement>;
const _callbacks = new CallbackList();
const _dropdowns = new Map<string, HTMLElement>();
const _menus = new Map<string, HTMLElement>();
let _menuContainer: HTMLElement;
-let _activeTargetId = '';
+let _activeTargetId = "";
/**
* Handles drop-down positions in overlays when scrolling in the overlay.
*/
function onDialogScroll(event: WheelEvent): void {
const dialogContent = event.currentTarget as HTMLElement;
- const dropdowns = dialogContent.querySelectorAll('.dropdown.dropdownOpen');
+ const dropdowns = dialogContent.querySelectorAll(".dropdown.dropdownOpen");
for (let i = 0, length = dropdowns.length; i < length; i++) {
const dropdown = dropdowns[i];
*/
function onScroll() {
_dropdowns.forEach((dropdown, containerId) => {
- if (dropdown.classList.contains('dropdownOpen')) {
- if (Core.stringToBool(dropdown.dataset.isOverlayDropdownButton || '')) {
+ if (dropdown.classList.contains("dropdownOpen")) {
+ if (Core.stringToBool(dropdown.dataset.isOverlayDropdownButton || "")) {
UiDropdownSimple.setAlignment(dropdown, _menus.get(containerId)!);
} else {
const menu = _menus.get(dropdown.id) as HTMLElement;
- if (!Core.stringToBool(menu.dataset.dropdownIgnorePageScroll || '')) {
+ if (!Core.stringToBool(menu.dataset.dropdownIgnorePageScroll || "")) {
UiDropdownSimple.close(containerId);
}
}
* Notifies callbacks on status change.
*/
function notifyCallbacks(containerId: string, action: NotificationAction): void {
- _callbacks.forEach(containerId, callback => {
+ _callbacks.forEach(containerId, (callback) => {
callback(containerId, action);
});
}
/**
* Toggles the drop-down's state between open and close.
*/
-function toggle(event: KeyboardEvent | MouseEvent | null, targetId?: string, alternateElement?: HTMLElement, disableAutoFocus?: boolean): boolean {
+function toggle(
+ event: KeyboardEvent | MouseEvent | null,
+ targetId?: string,
+ alternateElement?: HTMLElement,
+ disableAutoFocus?: boolean
+): boolean {
if (event !== null) {
event.preventDefault();
event.stopPropagation();
button = event.currentTarget;
parent = button.parentNode;
if (parent !== dropdown) {
- parent.classList.add('dropdown');
+ parent.classList.add("dropdown");
parent.id = dropdown.id;
// remove dropdown class and id from old parent
- dropdown.classList.remove('dropdown');
- dropdown.id = '';
+ dropdown.classList.remove("dropdown");
+ dropdown.id = "";
dropdown = parent;
_dropdowns.set(targetId!, parent);
}
if (disableAutoFocus === undefined) {
- button = dropdown.closest('.dropdownToggle');
+ button = dropdown.closest(".dropdownToggle");
if (!button) {
- button = dropdown.querySelector('.dropdownToggle');
+ button = dropdown.querySelector(".dropdownToggle");
if (!button && dropdown.id) {
button = document.querySelector('[data-target="' + dropdown.id + '"]');
}
}
- if (button && Core.stringToBool(button.dataset.dropdownLazyInit || '')) {
+ if (button && Core.stringToBool(button.dataset.dropdownLazyInit || "")) {
disableAutoFocus = true;
}
}
// to close it is by clicking somewhere else in the document or on another dropdown
// toggle. This is used with the search bar to prevent the dropdown from closing by
// setting the caret position in the search input field.
- if (Core.stringToBool(dropdown.dataset.dropdownPreventToggle || '') && dropdown.classList.contains('dropdownOpen')) {
+ if (
+ Core.stringToBool(dropdown.dataset.dropdownPreventToggle || "") &&
+ dropdown.classList.contains("dropdownOpen")
+ ) {
preventToggle = true;
}
// check if 'isOverlayDropdownButton' is set which indicates that the dropdown toggle is within an overlay
- if (dropdown.dataset.isOverlayDropdownButton === '') {
- const dialogContent = DomTraverse.parentByClass(dropdown, 'dialogContent');
- dropdown.dataset.isOverlayDropdownButton = (dialogContent !== null) ? 'true' : 'false';
+ if (dropdown.dataset.isOverlayDropdownButton === "") {
+ const dialogContent = DomTraverse.parentByClass(dropdown, "dialogContent");
+ dropdown.dataset.isOverlayDropdownButton = dialogContent !== null ? "true" : "false";
if (dialogContent !== null) {
- dialogContent.addEventListener('scroll', onDialogScroll);
+ dialogContent.addEventListener("scroll", onDialogScroll);
}
}
}
// close all dropdowns
- _activeTargetId = '';
+ _activeTargetId = "";
_dropdowns.forEach((dropdown, containerId) => {
const menu = _menus.get(containerId) as HTMLElement;
let firstListItem: HTMLLIElement | null = null;
- if (dropdown.classList.contains('dropdownOpen')) {
+ if (dropdown.classList.contains("dropdownOpen")) {
if (!preventToggle) {
- dropdown.classList.remove('dropdownOpen');
- menu.classList.remove('dropdownOpen');
+ dropdown.classList.remove("dropdownOpen");
+ menu.classList.remove("dropdownOpen");
- const button = dropdown.querySelector('.dropdownToggle');
- if (button) button.setAttribute('aria-expanded', 'false');
+ const button = dropdown.querySelector(".dropdownToggle");
+ if (button) button.setAttribute("aria-expanded", "false");
- notifyCallbacks(containerId, 'close');
+ notifyCallbacks(containerId, "close");
} else {
_activeTargetId = targetId!;
}
} else if (containerId === targetId && menu.childElementCount > 0) {
_activeTargetId = targetId;
- dropdown.classList.add('dropdownOpen');
- menu.classList.add('dropdownOpen');
+ dropdown.classList.add("dropdownOpen");
+ menu.classList.add("dropdownOpen");
- const button = dropdown.querySelector('.dropdownToggle');
- if (button) button.setAttribute('aria-expanded', 'true');
+ const button = dropdown.querySelector(".dropdownToggle");
+ if (button) button.setAttribute("aria-expanded", "true");
- const list: HTMLElement | null = menu.childElementCount > 0 ? menu.children[0] as HTMLElement : null;
- if (list && Core.stringToBool(list.dataset.scrollToActive || '')) {
+ const list: HTMLElement | null = menu.childElementCount > 0 ? (menu.children[0] as HTMLElement) : null;
+ if (list && Core.stringToBool(list.dataset.scrollToActive || "")) {
delete list.dataset.scrollToActive;
let active: HTMLElement | null = null;
for (let i = 0, length = list.childElementCount; i < length; i++) {
- if (list.children[i].classList.contains('active')) {
+ if (list.children[i].classList.contains("active")) {
active = list.children[i] as HTMLElement;
break;
}
}
if (active) {
- list.scrollTop = Math.max((active.offsetTop + active.clientHeight) - menu.clientHeight, 0);
+ list.scrollTop = Math.max(active.offsetTop + active.clientHeight - menu.clientHeight, 0);
}
}
- const itemList = menu.querySelector('.scrollableDropdownMenu');
+ const itemList = menu.querySelector(".scrollableDropdownMenu");
if (itemList !== null) {
- itemList.classList[(itemList.scrollHeight > itemList.clientHeight ? 'add' : 'remove')]('forceScrollbar');
+ itemList.classList[itemList.scrollHeight > itemList.clientHeight ? "add" : "remove"]("forceScrollbar");
}
- notifyCallbacks(containerId, 'open');
+ notifyCallbacks(containerId, "open");
if (!disableAutoFocus) {
- menu.setAttribute('role', 'menu');
+ menu.setAttribute("role", "menu");
menu.tabIndex = -1;
- menu.removeEventListener('keydown', dropdownMenuKeyDown);
- menu.addEventListener('keydown', dropdownMenuKeyDown);
- menu.querySelectorAll('li').forEach(listItem => {
+ menu.removeEventListener("keydown", dropdownMenuKeyDown);
+ menu.addEventListener("keydown", dropdownMenuKeyDown);
+ menu.querySelectorAll("li").forEach((listItem) => {
if (!listItem.clientHeight) return;
if (firstListItem === null) firstListItem = listItem;
- else if (listItem.classList.contains('active')) firstListItem = listItem;
+ else if (listItem.classList.contains("active")) firstListItem = listItem;
- listItem.setAttribute('role', 'menuitem');
+ listItem.setAttribute("role", "menuitem");
listItem.tabIndex = -1;
});
}
window.WCF.Dropdown.Interactive.Handler.closeAll();
- return (event === null);
+ return event === null;
}
function handleKeyDown(event: KeyboardEvent): void {
// <input> elements are not valid targets for drop-down menus. However, some developers
// might still decide to combine them, in which case we try not to break things even more.
const target = event.currentTarget as HTMLElement;
- if (target.nodeName === 'INPUT') {
+ if (target.nodeName === "INPUT") {
return;
}
- if (event.key === 'Enter' || event.key === 'Space') {
+ if (event.key === "Enter" || event.key === "Space") {
event.preventDefault();
toggle(event);
}
function dropdownMenuKeyDown(event: KeyboardEvent): void {
const activeItem = document.activeElement as HTMLElement;
- if (activeItem.nodeName !== 'LI') {
+ if (activeItem.nodeName !== "LI") {
return;
}
- if (event.key === 'ArrowDown' || event.key === 'ArrowUp' || event.key === 'End' || event.key === 'Home') {
+ if (event.key === "ArrowDown" || event.key === "ArrowUp" || event.key === "End" || event.key === "Home") {
event.preventDefault();
- const listItems: HTMLElement[] = Array.from(activeItem.closest('.dropdownMenu')!.querySelectorAll('li'));
- if (event.key === 'ArrowUp' || event.key === 'End') {
+ const listItems: HTMLElement[] = Array.from(activeItem.closest(".dropdownMenu")!.querySelectorAll("li"));
+ if (event.key === "ArrowUp" || event.key === "End") {
listItems.reverse();
}
let newActiveItem: HTMLElement | null = null;
- const isValidItem = listItem => {
- return !listItem.classList.contains('dropdownDivider') && listItem.clientHeight > 0;
+ const isValidItem = (listItem) => {
+ return !listItem.classList.contains("dropdownDivider") && listItem.clientHeight > 0;
};
let activeIndex = listItems.indexOf(activeItem);
- if (event.key === 'End' || event.key === 'Home') {
+ if (event.key === "End" || event.key === "Home") {
activeIndex = -1;
}
if (newActiveItem !== null) {
newActiveItem.focus();
}
- } else if (event.key === 'Enter' || event.key === 'Space') {
+ } else if (event.key === "Enter" || event.key === "Space") {
event.preventDefault();
let target = activeItem;
- if (target.childElementCount === 1 && (target.children[0].nodeName === 'SPAN' || target.children[0].nodeName === 'A')) {
+ if (
+ target.childElementCount === 1 &&
+ (target.children[0].nodeName === "SPAN" || target.children[0].nodeName === "A")
+ ) {
target = target.children[0] as HTMLElement;
}
const dropdown = _dropdowns.get(_activeTargetId)!;
- const button = dropdown.querySelector('.dropdownToggle') as HTMLElement;
+ const button = dropdown.querySelector(".dropdownToggle") as HTMLElement;
- const mouseEvent = dropdown.dataset.a11yMouseEvent || 'click';
+ const mouseEvent = dropdown.dataset.a11yMouseEvent || "click";
Core.triggerEvent(target, mouseEvent);
if (button) {
button.focus();
}
- } else if (event.key === 'Escape' || event.key === 'Tab') {
+ } else if (event.key === "Escape" || event.key === "Tab") {
event.preventDefault();
const dropdown = _dropdowns.get(_activeTargetId)!;
- let button: HTMLElement | null = dropdown.querySelector('.dropdownToggle');
+ let button: HTMLElement | null = dropdown.querySelector(".dropdownToggle");
// Remote controlled drop-down menus may not have a dedicated toggle button, instead the
// `dropdown` element itself is the button.
- if (button === null && !dropdown.classList.contains('dropdown')) {
+ if (button === null && !dropdown.classList.contains("dropdown")) {
button = dropdown;
}
if (_didInit) return;
_didInit = true;
- _menuContainer = document.createElement('div');
- _menuContainer.className = 'dropdownMenuContainer';
+ _menuContainer = document.createElement("div");
+ _menuContainer.className = "dropdownMenuContainer";
document.body.appendChild(_menuContainer);
- _availableDropdowns = document.getElementsByClassName('dropdownToggle') as HTMLCollectionOf<HTMLElement>;
+ _availableDropdowns = document.getElementsByClassName("dropdownToggle") as HTMLCollectionOf<HTMLElement>;
UiDropdownSimple.initAll();
- UiCloseOverlay.add('WoltLabSuite/Core/Ui/Dropdown/Simple', UiDropdownSimple.closeAll);
- DomChangeListener.add('WoltLabSuite/Core/Ui/Dropdown/Simple', UiDropdownSimple.initAll);
+ UiCloseOverlay.add("WoltLabSuite/Core/Ui/Dropdown/Simple", UiDropdownSimple.closeAll);
+ DomChangeListener.add("WoltLabSuite/Core/Ui/Dropdown/Simple", UiDropdownSimple.initAll);
- document.addEventListener('scroll', onScroll);
+ document.addEventListener("scroll", onScroll);
// expose on window object for backward compatibility
window.bc_wcfSimpleDropdown = this;
init(button: HTMLElement, isLazyInitialization?: boolean | MouseEvent): boolean {
UiDropdownSimple.setup();
- button.setAttribute('role', 'button');
+ button.setAttribute("role", "button");
button.tabIndex = 0;
- button.setAttribute('aria-haspopup', 'true');
- button.setAttribute('aria-expanded', 'false');
+ button.setAttribute("aria-haspopup", "true");
+ button.setAttribute("aria-expanded", "false");
- if (button.classList.contains('jsDropdownEnabled') || button.dataset.target) {
+ if (button.classList.contains("jsDropdownEnabled") || button.dataset.target) {
return false;
}
- const dropdown = DomTraverse.parentByClass(button, 'dropdown') as HTMLElement;
+ const dropdown = DomTraverse.parentByClass(button, "dropdown") as HTMLElement;
if (dropdown === null) {
- throw new Error("Invalid dropdown passed, button '" + DomUtil.identify(button) + "' does not have a parent with .dropdown.");
+ throw new Error(
+ "Invalid dropdown passed, button '" + DomUtil.identify(button) + "' does not have a parent with .dropdown."
+ );
}
- const menu = DomTraverse.nextByClass(button, 'dropdownMenu') as HTMLElement;
+ const menu = DomTraverse.nextByClass(button, "dropdownMenu") as HTMLElement;
if (menu === null) {
- throw new Error("Invalid dropdown passed, button '" + DomUtil.identify(button) + "' does not have a menu as next sibling.");
+ throw new Error(
+ "Invalid dropdown passed, button '" + DomUtil.identify(button) + "' does not have a menu as next sibling."
+ );
}
// move menu into global container
const containerId = DomUtil.identify(dropdown);
if (!_dropdowns.has(containerId)) {
- button.classList.add('jsDropdownEnabled');
- button.addEventListener('click', toggle);
- button.addEventListener('keydown', handleKeyDown);
+ button.classList.add("jsDropdownEnabled");
+ button.addEventListener("click", toggle);
+ button.addEventListener("keydown", handleKeyDown);
_dropdowns.set(containerId, dropdown);
_menus.set(containerId, menu);
}
// prevent page scrolling
- if (menu.childElementCount && menu.children[0].classList.contains('scrollableDropdownMenu')) {
+ if (menu.childElementCount && menu.children[0].classList.contains("scrollableDropdownMenu")) {
const child = menu.children[0] as HTMLElement;
- child.dataset.scrollToActive = 'true';
+ child.dataset.scrollToActive = "true";
let menuHeight: number | null = null;
let menuRealHeight: number | null = null;
- child.addEventListener('wheel', event => {
- if (menuHeight === null) menuHeight = child.clientHeight;
- if (menuRealHeight === null) menuRealHeight = child.scrollHeight;
-
- // negative value: scrolling up
- if (event.deltaY < 0 && child.scrollTop === 0) {
- event.preventDefault();
- } else if (event.deltaY > 0 && (child.scrollTop + menuHeight === menuRealHeight)) {
- event.preventDefault();
- }
- }, {passive: false});
+ child.addEventListener(
+ "wheel",
+ (event) => {
+ if (menuHeight === null) menuHeight = child.clientHeight;
+ if (menuRealHeight === null) menuRealHeight = child.scrollHeight;
+
+ // negative value: scrolling up
+ if (event.deltaY < 0 && child.scrollTop === 0) {
+ event.preventDefault();
+ } else if (event.deltaY > 0 && child.scrollTop + menuHeight === menuRealHeight) {
+ event.preventDefault();
+ }
+ },
+ { passive: false }
+ );
}
}
if (isLazyInitialization) {
setTimeout(() => {
- button.dataset.dropdownLazyInit = (isLazyInitialization instanceof MouseEvent) ? 'true' : 'false';
+ button.dataset.dropdownLazyInit = isLazyInitialization instanceof MouseEvent ? "true" : "false";
- Core.triggerEvent(button, 'click');
+ Core.triggerEvent(button, "click");
setTimeout(() => {
delete button.dataset.dropdownLazyInit;
*/
setAlignment(dropdown: HTMLElement, dropdownMenu: HTMLElement, alternateElement?: HTMLElement): void {
// check if button belongs to an i18n textarea
- const button = dropdown.querySelector('.dropdownToggle');
- const parent = (button !== null) ? button.parentNode as HTMLElement : null;
+ const button = dropdown.querySelector(".dropdownToggle");
+ const parent = button !== null ? (button.parentNode as HTMLElement) : null;
let refDimensionsElement;
- if (parent && parent.classList.contains('inputAddonTextarea')) {
+ if (parent && parent.classList.contains("inputAddonTextarea")) {
refDimensionsElement = button;
}
UiAlignment.set(dropdownMenu, alternateElement || dropdown, {
- pointerClassNames: ['dropdownArrowBottom', 'dropdownArrowRight'],
+ pointerClassNames: ["dropdownArrowBottom", "dropdownArrowRight"],
refDimensionsElement: refDimensionsElement || null,
// alignment
- horizontal: dropdownMenu.dataset.dropdownAlignmentHorizontal === 'right' ? 'right' : 'left',
- vertical: dropdownMenu.dataset.dropdownAlignmentVertical === 'top' ? 'top' : 'bottom',
+ horizontal: dropdownMenu.dataset.dropdownAlignmentHorizontal === "right" ? "right" : "left",
+ vertical: dropdownMenu.dataset.dropdownAlignmentVertical === "top" ? "top" : "bottom",
- allowFlip: dropdownMenu.dataset.dropdownAllowFlip as AllowFlip || 'both',
+ allowFlip: (dropdownMenu.dataset.dropdownAllowFlip as AllowFlip) || "both",
});
},
*/
isOpen(containerId: string): boolean {
const menu = _menus.get(containerId);
- return (menu !== undefined && menu.classList.contains('dropdownOpen'));
+ return menu !== undefined && menu.classList.contains("dropdownOpen");
},
/**
*/
open(containerId: string, disableAutoFocus?: boolean): void {
const menu = _menus.get(containerId);
- if (menu !== undefined && !menu.classList.contains('dropdownOpen')) {
+ if (menu !== undefined && !menu.classList.contains("dropdownOpen")) {
UiDropdownSimple.toggleDropdown(containerId, undefined, disableAutoFocus);
}
},
close(containerId: string): void {
const dropdown = _dropdowns.get(containerId);
if (dropdown !== undefined) {
- dropdown.classList.remove('dropdownOpen');
- _menus.get(containerId)!.classList.remove('dropdownOpen');
+ dropdown.classList.remove("dropdownOpen");
+ _menus.get(containerId)!.classList.remove("dropdownOpen");
}
},
*/
closeAll(): void {
_dropdowns.forEach((dropdown, containerId) => {
- if (dropdown.classList.contains('dropdownOpen')) {
- dropdown.classList.remove('dropdownOpen');
- _menus.get(containerId)!.classList.remove('dropdownOpen');
+ if (dropdown.classList.contains("dropdownOpen")) {
+ dropdown.classList.remove("dropdownOpen");
+ _menus.get(containerId)!.classList.remove("dropdownOpen");
- notifyCallbacks(containerId, 'close');
+ notifyCallbacks(containerId, "close");
}
});
},
},
// Legacy call required for `WCF.Dropdown`
- _toggle(event: KeyboardEvent | MouseEvent | null, targetId?: string, alternateElement?: HTMLElement, disableAutoFocus?: boolean): boolean {
+ _toggle(
+ event: KeyboardEvent | MouseEvent | null,
+ targetId?: string,
+ alternateElement?: HTMLElement,
+ disableAutoFocus?: boolean
+ ): boolean {
return toggle(event, targetId, alternateElement, disableAutoFocus);
},
};
* @since 5.2
*/
-import * as Ajax from '../../Ajax';
-import { AjaxCallbackObject, DatabaseObjectActionResponse } from '../../Ajax/Data';
-import * as Core from '../../Core';
-import DomChangeListener from '../../Dom/Change/Listener';
-import * as Language from '../../Language';
+import * as Ajax from "../../Ajax";
+import { AjaxCallbackObject, DatabaseObjectActionResponse } from "../../Ajax/Data";
+import * as Core from "../../Core";
+import DomChangeListener from "../../Dom/Change/Listener";
+import * as Language from "../../Language";
interface AjaxResponse extends DatabaseObjectActionResponse {
uniqueFileId: string;
*/
private createButtons(): void {
let triggerChange = false;
- this.target.querySelectorAll('li.uploadedFile').forEach((element: HTMLElement) => {
+ this.target.querySelectorAll("li.uploadedFile").forEach((element: HTMLElement) => {
const uniqueFileId = element.dataset.uniqueFileId!;
if (this.containers.has(uniqueFileId)) {
return;
* Init the delete button for a specific element.
*/
private initDeleteButton(element: HTMLElement, elementData: ElementData): void {
- const buttonGroup = element.querySelector('.buttonGroup');
+ const buttonGroup = element.querySelector(".buttonGroup");
if (buttonGroup === null) {
throw new Error(`Button group in '${this.target.id}' is unknown.`);
}
- const li = document.createElement('li');
- const span = document.createElement('span');
+ const li = document.createElement("li");
+ const span = document.createElement("span");
span.className = "button jsDeleteButton small";
- span.textContent = Language.get('wcf.global.button.delete');
+ span.textContent = Language.get("wcf.global.button.delete");
li.appendChild(span);
buttonGroup.appendChild(li);
- li.addEventListener('click', this.deleteElement.bind(this, elementData.uniqueFileId));
+ li.addEventListener("click", this.deleteElement.bind(this, elementData.uniqueFileId));
}
/**
return;
}
- const img = this.target.querySelector('img');
+ const img = this.target.querySelector("img");
if (img !== null) {
const uniqueFileId = img.dataset.uniqueFileId!;
this.containers.set(uniqueFileId, elementData);
- this.deleteButton = document.createElement('p');
- this.deleteButton.className = 'button deleteButton';
+ this.deleteButton = document.createElement("p");
+ this.deleteButton.className = "button deleteButton";
- const span = document.createElement('span');
- span.textContent = Language.get('wcf.global.button.delete');
+ const span = document.createElement("span");
+ span.textContent = Language.get("wcf.global.button.delete");
this.deleteButton.appendChild(span);
this.buttonContainer.appendChild(this.deleteButton);
- this.deleteButton.addEventListener('click', this.deleteElement.bind(this, elementData.uniqueFileId));
+ this.deleteButton.addEventListener("click", this.deleteElement.bind(this, elementData.uniqueFileId));
}
}
}
}
this.uploadHandler.checkMaxFiles();
- Core.triggerEvent(this.target, 'change');
+ Core.triggerEvent(this.target, "change");
}
_ajaxSetup() {
return {
- url: 'index.php?ajax-file-delete/&t=' + window.SECURITY_TOKEN,
+ url: "index.php?ajax-file-delete/&t=" + window.SECURITY_TOKEN,
};
}
}
-export = UiFileDelete
+export = UiFileDelete;
* @module WoltLabSuite/Core/Ui/FlexibleMenu
*/
-import DomChangeListener from '../Dom/Change/Listener';
-import DomUtil from '../Dom/Util';
-import * as DomTraverse from '../Dom/Traverse';
-import UiDropdownSimple from './Dropdown/Simple';
+import DomChangeListener from "../Dom/Change/Listener";
+import DomUtil from "../Dom/Util";
+import * as DomTraverse from "../Dom/Traverse";
+import UiDropdownSimple from "./Dropdown/Simple";
const _containers = new Map<string, HTMLElement>();
const _dropdowns = new Map<string, HTMLLIElement>();
* Register default menus and set up event listeners.
*/
export function setup(): void {
- if (document.getElementById('mainMenu') !== null) {
- register('mainMenu');
+ if (document.getElementById("mainMenu") !== null) {
+ register("mainMenu");
}
- const navigationHeader = document.querySelector('.navigationHeader');
+ const navigationHeader = document.querySelector(".navigationHeader");
if (navigationHeader !== null) {
register(DomUtil.identify(navigationHeader));
}
- window.addEventListener('resize', rebuildAll);
- DomChangeListener.add('WoltLabSuite/Core/Ui/FlexibleMenu', registerTabMenus);
+ window.addEventListener("resize", rebuildAll);
+ DomChangeListener.add("WoltLabSuite/Core/Ui/FlexibleMenu", registerTabMenus);
}
/**
return;
}
- const list = DomTraverse.childByTag(container, 'UL') as HTMLUListElement;
+ const list = DomTraverse.childByTag(container, "UL") as HTMLUListElement;
if (list === null) {
throw "Expected an <ul> element as child of container '" + containerId + "'.";
}
* Registers tab menus.
*/
export function registerTabMenus(): void {
- document.querySelectorAll('.tabMenuContainer:not(.jsFlexibleMenuEnabled), .messageTabMenu:not(.jsFlexibleMenuEnabled)').forEach(tabMenu => {
- const nav = DomTraverse.childByTag(tabMenu, 'NAV');
- if (nav !== null) {
- tabMenu.classList.add('jsFlexibleMenuEnabled');
- register(DomUtil.identify(nav));
- }
- });
+ document
+ .querySelectorAll(".tabMenuContainer:not(.jsFlexibleMenuEnabled), .messageTabMenu:not(.jsFlexibleMenuEnabled)")
+ .forEach((tabMenu) => {
+ const nav = DomTraverse.childByTag(tabMenu, "NAV");
+ if (nav !== null) {
+ tabMenu.classList.add("jsFlexibleMenuEnabled");
+ register(DomUtil.identify(nav));
+ }
+ });
}
/**
const styles = window.getComputedStyle(container);
const parent = container.parentNode as HTMLElement;
let availableWidth = parent.clientWidth;
- availableWidth -= DomUtil.styleAsInt(styles, 'margin-left');
- availableWidth -= DomUtil.styleAsInt(styles, 'margin-right');
+ availableWidth -= DomUtil.styleAsInt(styles, "margin-left");
+ availableWidth -= DomUtil.styleAsInt(styles, "margin-right");
const list = _itemLists.get(containerId)!;
- const items = DomTraverse.childrenByTag(list, 'LI') as HTMLLIElement[];
+ const items = DomTraverse.childrenByTag(list, "LI") as HTMLLIElement[];
let dropdown = _dropdowns.get(containerId);
let dropdownWidth = 0;
if (dropdown !== undefined) {
// show all items for calculation
for (let i = 0, length = items.length; i < length; i++) {
const item = items[i];
- if (item.classList.contains('dropdown')) {
+ if (item.classList.contains("dropdown")) {
continue;
}
const item = items[i];
// ignore dropdown and active item
- if (item.classList.contains('dropdown') || item.classList.contains('active') || item.classList.contains('ui-state-active')) {
+ if (
+ item.classList.contains("dropdown") ||
+ item.classList.contains("active") ||
+ item.classList.contains("ui-state-active")
+ ) {
continue;
}
if (hiddenItems.length) {
let dropdownMenu: HTMLUListElement;
if (dropdown === undefined) {
- dropdown = document.createElement('li');
- dropdown.className = 'dropdown jsFlexibleMenuDropdown';
+ dropdown = document.createElement("li");
+ dropdown.className = "dropdown jsFlexibleMenuDropdown";
- const icon = document.createElement('a');
- icon.className = 'icon icon16 fa-list';
+ const icon = document.createElement("a");
+ icon.className = "icon icon16 fa-list";
dropdown.appendChild(icon);
- dropdownMenu = document.createElement('ul');
- dropdownMenu.classList.add('dropdownMenu');
+ dropdownMenu = document.createElement("ul");
+ dropdownMenu.classList.add("dropdownMenu");
dropdown.appendChild(dropdownMenu);
_dropdowns.set(containerId, dropdown);
// build dropdown menu
const fragment = document.createDocumentFragment();
- hiddenItems.forEach(hiddenItem => {
- const item = document.createElement('li');
+ hiddenItems.forEach((hiddenItem) => {
+ const item = document.createElement("li");
item.innerHTML = hiddenItem.innerHTML;
- item.addEventListener('click', event => {
+ item.addEventListener("click", (event) => {
event.preventDefault();
- hiddenItem.querySelector('a')?.click();
+ hiddenItem.querySelector("a")?.click();
// force a rebuild to guarantee the active item being visible
setTimeout(() => {
fragment.appendChild(item);
});
- dropdownMenu.innerHTML = '';
+ dropdownMenu.innerHTML = "";
dropdownMenu.appendChild(fragment);
} else if (dropdown !== undefined && dropdown.parentNode !== null) {
dropdown.remove();
* @module WoltLabSuite/Core/Ui/ItemList
*/
-import * as Core from '../Core';
-import * as DomTraverse from '../Dom/Traverse';
-import * as Language from '../Language';
-import UiSuggestion from './Suggestion';
-import UiDropdownSimple from './Dropdown/Simple';
-import { DatabaseObjectActionPayload } from '../Ajax/Data';
-import DomUtil from '../Dom/Util';
-
-let _activeId = '';
+import * as Core from "../Core";
+import * as DomTraverse from "../Dom/Traverse";
+import * as Language from "../Language";
+import UiSuggestion from "./Suggestion";
+import UiDropdownSimple from "./Dropdown/Simple";
+import { DatabaseObjectActionPayload } from "../Ajax/Data";
+import DomUtil from "../Dom/Util";
+
+let _activeId = "";
const _data = new Map<string, ElementData>();
/**
function createUI(element: ItemListInputElement, options: ItemListOptions): UiData {
const parentElement = element.parentElement!;
- const list = document.createElement('ol');
- list.className = 'inputItemList' + (element.disabled ? ' disabled' : '');
+ const list = document.createElement("ol");
+ list.className = "inputItemList" + (element.disabled ? " disabled" : "");
list.dataset.elementId = element.id;
- list.addEventListener('click', event => {
+ list.addEventListener("click", (event) => {
if (event.target === list) {
element.focus();
}
});
- const listItem = document.createElement('li');
- listItem.className = 'input';
+ const listItem = document.createElement("li");
+ listItem.className = "input";
list.appendChild(listItem);
- element.addEventListener('keydown', keyDown);
- element.addEventListener('keypress', keyPress);
- element.addEventListener('keyup', keyUp);
- element.addEventListener('paste', paste);
+ element.addEventListener("keydown", keyDown);
+ element.addEventListener("keypress", keyPress);
+ element.addEventListener("keyup", keyUp);
+ element.addEventListener("paste", paste);
- const hasFocus = (element === document.activeElement);
+ const hasFocus = element === document.activeElement;
if (hasFocus) {
element.blur();
}
- element.addEventListener('blur', blur);
+ element.addEventListener("blur", blur);
parentElement.insertBefore(list, element);
listItem.appendChild(element);
element.maxLength = options.maxLength;
}
- const limitReached = document.createElement('span');
- limitReached.className = 'inputItemListLimitReached';
- limitReached.textContent = Language.get('wcf.global.form.input.maxItems');
+ const limitReached = document.createElement("span");
+ limitReached.className = "inputItemListLimitReached";
+ limitReached.textContent = Language.get("wcf.global.form.input.maxItems");
DomUtil.hide(limitReached);
listItem.appendChild(limitReached);
let shadow: HTMLInputElement | null = null;
const values: string[] = [];
if (options.isCSV) {
- shadow = document.createElement('input');
- shadow.className = 'itemListInputShadow';
- shadow.type = 'hidden';
+ shadow = document.createElement("input");
+ shadow.className = "itemListInputShadow";
+ shadow.type = "hidden";
shadow.name = element.name;
- element.removeAttribute('name');
+ element.removeAttribute("name");
list.parentNode!.insertBefore(shadow, list);
- element.value.split(',').forEach(value => {
+ element.value.split(",").forEach((value) => {
value = value.trim();
if (value) {
values.push(value);
}
});
- if (element.nodeName === 'TEXTAREA') {
- const inputElement = document.createElement('input');
- inputElement.type = 'text';
+ if (element.nodeName === "TEXTAREA") {
+ const inputElement = document.createElement("input");
+ inputElement.type = "text";
parentElement.insertBefore(inputElement, element);
inputElement.id = element.id;
return true;
}
- return (data.list.childElementCount - 1 < data.options.maxItems);
+ return data.list.childElementCount - 1 < data.options.maxItems;
}
/**
_activeId = input.id;
const lastItem = input.parentElement!.previousElementSibling as HTMLElement | null;
- if (event.key === 'Backspace') {
+ if (event.key === "Backspace") {
if (input.value.length === 0) {
if (lastItem !== null) {
- if (lastItem.classList.contains('active')) {
+ if (lastItem.classList.contains("active")) {
removeItem(lastItem);
} else {
- lastItem.classList.add('active');
+ lastItem.classList.add("active");
}
}
}
- } else if (event.key === 'Escape') {
- if (lastItem !== null && lastItem.classList.contains('active')) {
- lastItem.classList.remove('active');
+ } else if (event.key === "Escape") {
+ if (lastItem !== null && lastItem.classList.contains("active")) {
+ lastItem.classList.remove("active");
}
}
}
* Handles the `[ENTER]` and `[,]` key to add an item to the list unless it is restricted.
*/
function keyPress(event: KeyboardEvent): void {
- if (event.key === 'Enter' || event.key === ',') {
+ if (event.key === "Enter" || event.key === ",") {
event.preventDefault();
const input = event.currentTarget as HTMLInputElement;
}
const value = input.value.trim();
if (value.length) {
- addItem(input.id, {objectId: 0, value: value});
+ addItem(input.id, { objectId: 0, value: value });
}
}
}
function paste(event: ClipboardEvent): void {
event.preventDefault();
- const text = event.clipboardData!.getData('text/plain');
+ const text = event.clipboardData!.getData("text/plain");
const element = event.currentTarget as HTMLInputElement;
const elementId = element.id;
const maxLength = +element.maxLength;
- text.split(/,/).forEach(item => {
+ text.split(/,/).forEach((item) => {
item = item.trim();
if (maxLength && item.length > maxLength) {
// truncating items provides a better UX than throwing an error or silently discarding it
}
if (item.length > 0 && acceptsNewItems(elementId)) {
- addItem(elementId, {objectId: 0, value: item});
+ addItem(elementId, { objectId: 0, value: item });
}
});
}
if (input.value.length > 0) {
const lastItem = input.parentElement!.previousElementSibling;
if (lastItem !== null) {
- lastItem.classList.remove('active');
+ lastItem.classList.remove("active");
}
}
}
*/
function addItem(elementId: string, value: ItemData): void {
const data = _data.get(elementId)!;
- const listItem = document.createElement('li');
- listItem.className = 'item';
+ const listItem = document.createElement("li");
+ listItem.className = "item";
- const content = document.createElement('span');
- content.className = 'content';
+ const content = document.createElement("span");
+ content.className = "content";
content.dataset.objectId = value.objectId.toString();
if (value.type) {
content.dataset.type = value.type;
listItem.appendChild(content);
if (!data.element.disabled) {
- const button = document.createElement('a');
- button.className = 'icon icon16 fa-times';
- button.addEventListener('click', removeItem);
+ const button = document.createElement("a");
+ button.className = "icon icon16 fa-times";
+ button.addEventListener("click", removeItem);
listItem.appendChild(button);
}
data.list.insertBefore(listItem, data.listItem);
data.suggestion.addExcludedValue(value.value);
- data.element.value = '';
+ data.element.value = "";
if (!data.element.disabled) {
handleLimit(elementId);
}
let values = syncShadow(data);
- if (typeof data.options.callbackChange === 'function') {
+ if (typeof data.options.callbackChange === "function") {
if (values === null) {
values = getValues(elementId);
}
}
const parent = item.parentElement!;
- const elementId = parent.dataset.elementId || '';
+ const elementId = parent.dataset.elementId || "";
const data = _data.get(elementId)!;
if (item.children[0].textContent) {
data.suggestion.removeExcludedValue(item.children[0].textContent);
handleLimit(elementId);
let values = syncShadow(data);
- if (typeof data.options.callbackChange === 'function') {
+ if (typeof data.options.callbackChange === "function") {
if (values === null) {
values = getValues(elementId);
}
return null;
}
- if (typeof data.options.callbackSyncShadow === 'function') {
+ if (typeof data.options.callbackSyncShadow === "function") {
return data.options.callbackSyncShadow(data);
}
const values = getValues(data.element.id);
data.shadow!.value = getValues(data.element.id)
- .map(value => value.value)
- .join(',');
+ .map((value) => value.value)
+ .join(",");
return values;
}
const value = input.value.trim();
if (value.length) {
if (!data.suggestion || !data.suggestion.isActive()) {
- addItem(input.id, {objectId: 0, value: value});
+ addItem(input.id, { objectId: 0, value: value });
}
}
}
-
/**
* Initializes an item list.
*
// remove data from previous instance
if (_data.has(elementId)) {
const tmp = _data.get(elementId)!;
- Object.keys(tmp).forEach(key => {
+ Object.keys(tmp).forEach((key) => {
const el = tmp[key];
if (el instanceof Element && el.parentNode) {
el.remove();
_data.delete(elementId);
}
- options = Core.extend({
- // search parameters for suggestions
- ajax: {
- actionName: 'getSearchResultList',
- className: '',
- data: {},
+ options = Core.extend(
+ {
+ // search parameters for suggestions
+ ajax: {
+ actionName: "getSearchResultList",
+ className: "",
+ data: {},
+ },
+ // list of excluded string values, e.g. `['ignore', 'these strings', 'when', 'searching']`
+ excludedSearchValues: [],
+ // maximum number of items this list may contain, `-1` for infinite
+ maxItems: -1,
+ // maximum length of an item value, `-1` for infinite
+ maxLength: -1,
+ // disallow custom values, only values offered by the suggestion dropdown are accepted
+ restricted: false,
+ // initial value will be interpreted as comma separated value and submitted as such
+ isCSV: false,
+ // will be invoked whenever the items change, receives the element id first and list of values second
+ callbackChange: null,
+ // callback once the form is about to be submitted
+ callbackSubmit: null,
+ // Callback for the custom shadow synchronization.
+ callbackSyncShadow: null,
+ // Callback to set values during the setup.
+ callbackSetupValues: null,
+ // value may contain the placeholder `{$objectId}`
+ submitFieldName: "",
},
- // list of excluded string values, e.g. `['ignore', 'these strings', 'when', 'searching']`
- excludedSearchValues: [],
- // maximum number of items this list may contain, `-1` for infinite
- maxItems: -1,
- // maximum length of an item value, `-1` for infinite
- maxLength: -1,
- // disallow custom values, only values offered by the suggestion dropdown are accepted
- restricted: false,
- // initial value will be interpreted as comma separated value and submitted as such
- isCSV: false,
- // will be invoked whenever the items change, receives the element id first and list of values second
- callbackChange: null,
- // callback once the form is about to be submitted
- callbackSubmit: null,
- // Callback for the custom shadow synchronization.
- callbackSyncShadow: null,
- // Callback to set values during the setup.
- callbackSetupValues: null,
- // value may contain the placeholder `{$objectId}`
- submitFieldName: '',
- }, options) as ItemListOptions;
-
- const form = DomTraverse.parentByTag(element, 'FORM') as HTMLFormElement;
+ options
+ ) as ItemListOptions;
+
+ const form = DomTraverse.parentByTag(element, "FORM") as HTMLFormElement;
if (form !== null) {
if (!options.isCSV) {
- if (!options.submitFieldName.length && typeof options.callbackSubmit !== 'function') {
- throw new Error("Expected a valid function for option 'callbackSubmit', a non-empty value for option 'submitFieldName' or enabling the option 'submitFieldCSV'.");
+ if (!options.submitFieldName.length && typeof options.callbackSubmit !== "function") {
+ throw new Error(
+ "Expected a valid function for option 'callbackSubmit', a non-empty value for option 'submitFieldName' or enabling the option 'submitFieldCSV'."
+ );
}
- form.addEventListener('submit', () => {
+ form.addEventListener("submit", () => {
if (acceptsNewItems(elementId)) {
const value = _data.get(elementId)!.element.value.trim();
if (value.length) {
- addItem(elementId, {objectId: 0, value: value});
+ addItem(elementId, { objectId: 0, value: value });
}
}
const values = getValues(elementId);
if (options.submitFieldName.length) {
- values.forEach(value => {
- const input = document.createElement('input');
- input.type = 'hidden';
- input.name = options.submitFieldName.replace('{$objectId}', value.objectId.toString());
+ values.forEach((value) => {
+ const input = document.createElement("input");
+ input.type = "hidden";
+ input.name = options.submitFieldName.replace("{$objectId}", value.objectId.toString());
input.value = value.value;
form.appendChild(input);
});
}
});
} else {
- form.addEventListener('submit', () => {
+ form.addEventListener("submit", () => {
if (acceptsNewItems(elementId)) {
const value = _data.get(elementId)!.element.value.trim();
if (value.length) {
- addItem(elementId, {objectId: 0, value: value});
+ addItem(elementId, { objectId: 0, value: value });
}
}
});
if (options.callbackSetupValues) {
values = options.callbackSetupValues();
} else {
- values = (data.values.length) ? data.values : values;
+ values = data.values.length ? data.values : values;
}
if (Array.isArray(values)) {
- values.forEach(value => {
- if (typeof value === 'string') {
- value = {objectId: 0, value: value};
+ values.forEach((value) => {
+ if (typeof value === "string") {
+ value = { objectId: 0, value: value };
}
addItem(elementId, value);
}
const values: ItemData[] = [];
- data.list.querySelectorAll('.item > span').forEach((span: HTMLSpanElement) => {
+ data.list.querySelectorAll(".item > span").forEach((span: HTMLSpanElement) => {
values.push({
- objectId: +(span.dataset.objectId || ''),
+ objectId: +(span.dataset.objectId || ""),
value: span.textContent!.trim(),
type: span.dataset.type,
});
}
// remove all existing items first
- DomTraverse.childrenByClass(data.list, 'item').forEach((item: HTMLElement) => {
+ DomTraverse.childrenByClass(data.list, "item").forEach((item: HTMLElement) => {
removeItem(item, true);
});
// add new items
- values.forEach(value => {
+ values.forEach((value) => {
addItem(elementId, value);
});
}
limitReached: HTMLSpanElement;
list: HTMLElement;
listItem: HTMLElement;
- options: ItemListOptions,
+ options: ItemListOptions;
shadow: HTMLInputElement | null;
suggestion: UiSuggestion;
}
* @module WoltLabSuite/Core/Ui/Notification
*/
-import * as Language from '../Language';
+import * as Language from "../Language";
type Callback = () => void;
function init() {
if (_didInit) return;
_didInit = true;
-
- _notificationElement = document.createElement('div');
- _notificationElement.id = 'systemNotification';
- _message = document.createElement('p');
- _message.addEventListener('click', hide);
+ _notificationElement = document.createElement("div");
+ _notificationElement.id = "systemNotification";
+
+ _message = document.createElement("p");
+ _message.addEventListener("click", hide);
_notificationElement.appendChild(_message);
document.body.appendChild(_notificationElement);
function hide() {
clearTimeout(_timeout);
- _notificationElement.classList.remove('active');
+ _notificationElement.classList.remove("active");
if (_callback !== null) {
_callback();
init();
- _callback = (typeof callback === 'function') ? callback : null;
- _message.className = cssClassName || 'success';
- _message.textContent = Language.get(message || 'wcf.global.success');
+ _callback = typeof callback === "function" ? callback : null;
+ _message.className = cssClassName || "success";
+ _message.textContent = Language.get(message || "wcf.global.success");
- _notificationElement.classList.add('active');
+ _notificationElement.classList.add("active");
_timeout = setTimeout(hide, 2000);
}
* @module WoltLabSuite/Core/Ui/Page/Action
*/
-import * as Core from '../../Core';
-import * as Language from '../../Language';
+import * as Core from "../../Core";
+import * as Language from "../../Language";
const _buttons = new Map<string, HTMLElement>();
let _wrapper: HTMLElement;
function buildToTopButton(): HTMLAnchorElement {
- const button = document.createElement('a');
- button.className = 'button buttonPrimary pageActionButtonToTop initiallyHidden jsTooltip';
- button.href = '';
- button.title = Language.get('wcf.global.scrollUp');
- button.setAttribute('aria-hidden', 'true');
+ const button = document.createElement("a");
+ button.className = "button buttonPrimary pageActionButtonToTop initiallyHidden jsTooltip";
+ button.href = "";
+ button.title = Language.get("wcf.global.scrollUp");
+ button.setAttribute("aria-hidden", "true");
button.innerHTML = '<span class="icon icon32 fa-angle-up"></span>';
- button.addEventListener('click', scrollToTop);
+ button.addEventListener("click", scrollToTop);
return button;
}
function onScroll(): void {
- if (document.documentElement.classList.contains('disableScrolling')) {
+ if (document.documentElement.classList.contains("disableScrolling")) {
// Ignore any scroll events that take place while body scrolling is disabled,
// because it messes up the scroll offsets.
return;
}
if (offset >= 300) {
- if (_toTopButton.classList.contains('initiallyHidden')) {
- _toTopButton.classList.remove('initiallyHidden');
+ if (_toTopButton.classList.contains("initiallyHidden")) {
+ _toTopButton.classList.remove("initiallyHidden");
}
- _toTopButton.setAttribute('aria-hidden', 'false');
+ _toTopButton.setAttribute("aria-hidden", "false");
} else {
- _toTopButton.setAttribute('aria-hidden', 'true');
+ _toTopButton.setAttribute("aria-hidden", "true");
}
renderContainer();
if (_lastPosition !== -1) {
- _wrapper.classList[offset < _lastPosition ? 'remove' : 'add']('scrolledDown');
+ _wrapper.classList[offset < _lastPosition ? "remove" : "add"]("scrolledDown");
}
_lastPosition = offset;
function scrollToTop(event: MouseEvent): void {
event.preventDefault();
- const topAnchor = document.getElementById('top')!;
- topAnchor.scrollIntoView({behavior: 'smooth'});
+ const topAnchor = document.getElementById("top")!;
+ topAnchor.scrollIntoView({ behavior: "smooth" });
}
/**
* Toggles the container's visibility.
*/
function renderContainer() {
- const visibleChild = Array.from(_container.children).find(element => {
- return element.getAttribute('aria-hidden') === 'false';
+ const visibleChild = Array.from(_container.children).find((element) => {
+ return element.getAttribute("aria-hidden") === "false";
});
- _container.classList[visibleChild ? 'add' : 'remove']('active');
+ _container.classList[visibleChild ? "add" : "remove"]("active");
}
/**
_didInit = true;
- _wrapper = document.createElement('div');
- _wrapper.className = 'pageAction';
+ _wrapper = document.createElement("div");
+ _wrapper.className = "pageAction";
- _container = document.createElement('div');
- _container.className = 'pageActionButtons';
+ _container = document.createElement("div");
+ _container.className = "pageActionButtons";
_wrapper.appendChild(_container);
_toTopButton = buildToTopButton();
document.body.appendChild(_wrapper);
- window.addEventListener(
- 'scroll',
- Core.debounce(onScroll, 100),
- {passive: true},
- );
+ window.addEventListener("scroll", Core.debounce(onScroll, 100), { passive: true });
onScroll();
}
// The wrapper is required for backwards compatibility, because some implementations rely on a
// dedicated parent element to insert elements, for example, for drop-down menus.
- const wrapper = document.createElement('div');
- wrapper.className = 'pageActionButton';
+ const wrapper = document.createElement("div");
+ wrapper.className = "pageActionButton";
wrapper.dataset.name = buttonName;
- wrapper.setAttribute('aria-hidden', 'true');
+ wrapper.setAttribute("aria-hidden", "true");
- button.classList.add('button');
- button.classList.add('buttonPrimary');
+ button.classList.add("button");
+ button.classList.add("buttonPrimary");
wrapper.appendChild(button);
let insertBefore: HTMLElement | null = null;
}
_container.insertBefore(wrapper, insertBefore);
- _wrapper.classList.remove('scrolledDown');
+ _wrapper.classList.remove("scrolledDown");
_buttons.set(buttonName, button);
wrapper.offsetParent;
// Toggle the visibility to force the transition to be applied.
- wrapper.setAttribute('aria-hidden', 'false');
+ wrapper.setAttribute("aria-hidden", "false");
renderContainer();
}
const listItem = button.parentElement!;
const callback = () => {
try {
- if (Core.stringToBool(listItem.getAttribute('aria-hidden'))) {
+ if (Core.stringToBool(listItem.getAttribute("aria-hidden"))) {
_container.removeChild(listItem);
_buttons.delete(buttonName);
}
- listItem.removeEventListener('transitionend', callback);
+ listItem.removeEventListener("transitionend", callback);
} catch (e) {
// ignore errors if the element has already been removed
}
};
- listItem.addEventListener('transitionend', callback);
+ listItem.addEventListener("transitionend", callback);
hide(buttonName);
}
const button = _buttons.get(buttonName);
if (button) {
const parent = button.parentElement!;
- parent.setAttribute('aria-hidden', 'true');
+ parent.setAttribute("aria-hidden", "true");
renderContainer();
}
const button = _buttons.get(buttonName);
if (button) {
const parent = button.parentElement!;
- if (parent.classList.contains('initiallyHidden')) {
- parent.classList.remove('initiallyHidden');
+ if (parent.classList.contains("initiallyHidden")) {
+ parent.classList.remove("initiallyHidden");
}
- parent.setAttribute('aria-hidden', 'false');
- _wrapper.classList.remove('scrolledDown');
+ parent.setAttribute("aria-hidden", "false");
+ _wrapper.classList.remove("scrolledDown");
renderContainer();
}
}
-
-
* @module WoltLabSuite/Core/Ui/Page/Header/Fixed
*/
-import * as EventHandler from '../../../Event/Handler';
-import * as UiAlignment from '../../Alignment';
-import UiCloseOverlay from '../../CloseOverlay';
-import UiDropdownSimple from '../../Dropdown/Simple';
-import * as UiScreen from '../../Screen';
+import * as EventHandler from "../../../Event/Handler";
+import * as UiAlignment from "../../Alignment";
+import UiCloseOverlay from "../../CloseOverlay";
+import UiDropdownSimple from "../../Dropdown/Simple";
+import * as UiScreen from "../../Screen";
let _isMobile = false;
* Provides the collapsible search bar.
*/
function initSearchBar(): void {
- _pageHeaderSearch = document.getElementById('pageHeaderSearch')!;
- _pageHeaderSearch.addEventListener('click', ev => ev.stopPropagation());
+ _pageHeaderSearch = document.getElementById("pageHeaderSearch")!;
+ _pageHeaderSearch.addEventListener("click", (ev) => ev.stopPropagation());
- _pageHeaderPanel = document.getElementById('pageHeaderPanel')!;
- _searchInput = document.getElementById('pageHeaderSearchInput') as HTMLInputElement;
- _topMenu = document.getElementById('topMenu')!;
+ _pageHeaderPanel = document.getElementById("pageHeaderPanel")!;
+ _searchInput = document.getElementById("pageHeaderSearchInput") as HTMLInputElement;
+ _topMenu = document.getElementById("topMenu")!;
- _userPanelSearchButton = document.getElementById('userPanelSearchButton')!;
- _userPanelSearchButton.addEventListener('click', event => {
+ _userPanelSearchButton = document.getElementById("userPanelSearchButton")!;
+ _userPanelSearchButton.addEventListener("click", (event) => {
event.preventDefault();
event.stopPropagation();
- if (_pageHeader.classList.contains('searchBarOpen')) {
+ if (_pageHeader.classList.contains("searchBarOpen")) {
closeSearchBar();
} else {
openSearchBar();
}
});
- UiCloseOverlay.add('WoltLabSuite/Core/Ui/Page/Header/Fixed', () => {
- if (_pageHeader.classList.contains('searchBarForceOpen')) {
+ UiCloseOverlay.add("WoltLabSuite/Core/Ui/Page/Header/Fixed", () => {
+ if (_pageHeader.classList.contains("searchBarForceOpen")) {
return;
}
closeSearchBar();
});
- EventHandler.add('com.woltlab.wcf.MainMenuMobile', 'more', data => {
- if (data.identifier === 'com.woltlab.wcf.search') {
+ EventHandler.add("com.woltlab.wcf.MainMenuMobile", "more", (data) => {
+ if (data.identifier === "com.woltlab.wcf.search") {
data.handler.close(true);
_userPanelSearchButton.click();
function openSearchBar(): void {
window.WCF.Dropdown.Interactive.Handler.closeAll();
- _pageHeader.classList.add('searchBarOpen');
- _userPanelSearchButton.parentElement!.classList.add('open');
+ _pageHeader.classList.add("searchBarOpen");
+ _userPanelSearchButton.parentElement!.classList.add("open");
if (!_isMobile) {
// calculate value for `right` on desktop
UiAlignment.set(_pageHeaderSearch, _topMenu, {
- horizontal: 'right',
+ horizontal: "right",
});
}
- _pageHeaderSearch.style.setProperty('top', _pageHeaderPanel.clientHeight + 'px', '');
+ _pageHeaderSearch.style.setProperty("top", _pageHeaderPanel.clientHeight + "px", "");
_searchInput.focus();
window.setTimeout(() => {
* Closes the search bar.
*/
function closeSearchBar(): void {
- _pageHeader.classList.remove('searchBarOpen');
- _userPanelSearchButton.parentElement!.classList.remove('open');
+ _pageHeader.classList.remove("searchBarOpen");
+ _userPanelSearchButton.parentElement!.classList.remove("open");
- ['bottom', 'left', 'right', 'top'].forEach(propertyName => {
+ ["bottom", "left", "right", "top"].forEach((propertyName) => {
_pageHeaderSearch.style.removeProperty(propertyName);
});
_searchInput.blur();
// close the scope selection
- const scope = _pageHeaderSearch.querySelector('.pageHeaderSearchType')!;
+ const scope = _pageHeaderSearch.querySelector(".pageHeaderSearchType")!;
UiDropdownSimple.close(scope.id);
}
* Initializes the sticky page header handler.
*/
export function init(): void {
- _pageHeader = document.getElementById('pageHeader')!;
- _pageHeaderContainer = document.getElementById('pageHeaderContainer')!;
+ _pageHeader = document.getElementById("pageHeader")!;
+ _pageHeaderContainer = document.getElementById("pageHeaderContainer")!;
initSearchBar();
- UiScreen.on('screen-md-down', {
+ UiScreen.on("screen-md-down", {
match() {
_isMobile = true;
},
},
});
- EventHandler.add('com.woltlab.wcf.Search', 'close', closeSearchBar);
+ EventHandler.add("com.woltlab.wcf.Search", "close", closeSearchBar);
}
* @module WoltLabSuite/Core/Ui/Page/Header/Menu
*/
-import * as Environment from '../../../Environment';
-import * as Language from '../../../Language';
-import * as UiScreen from '../../Screen';
+import * as Environment from "../../../Environment";
+import * as Language from "../../../Language";
+import * as UiScreen from "../../Screen";
let _enabled = false;
// issue results in the next button being shown for a short time. To circumvent this issue,
// we wait a second before showing the obverflow controls in Safari.
// see https://webkit.org/blog/6643/improved-font-loading/
- if (Environment.browser() === 'safari') {
+ if (Environment.browser() === "safari") {
window.setTimeout(rebuildVisibility, 1000);
} else {
rebuildVisibility();
setMarginLeft(_menu.clientWidth - (showItem.offsetLeft + showItem.clientWidth));
if (_menu.lastElementChild === showItem) {
- _buttonShowNext.classList.remove('active');
+ _buttonShowNext.classList.remove("active");
}
- _buttonShowPrevious.classList.add('active');
+ _buttonShowPrevious.classList.add("active");
}
}
setMarginLeft(showItem.offsetLeft * -1);
if (_menu.firstElementChild === showItem) {
- _buttonShowPrevious.classList.remove('active');
+ _buttonShowPrevious.classList.remove("active");
}
- _buttonShowNext.classList.add('active');
+ _buttonShowNext.classList.add("active");
}
}
function setMarginLeft(offset: number): void {
_marginLeft = Math.min(_marginLeft + offset, 0);
- _firstElement.style.setProperty('margin-left', _marginLeft + 'px', '');
+ _firstElement.style.setProperty("margin-left", _marginLeft + "px", "");
}
/**
});
}
- _buttonShowPrevious.classList[(_invisibleLeft.length ? 'add' : 'remove')]('active');
- _buttonShowNext.classList[(_invisibleRight.length ? 'add' : 'remove')]('active');
+ _buttonShowPrevious.classList[_invisibleLeft.length ? "add" : "remove"]("active");
+ _buttonShowNext.classList[_invisibleRight.length ? "add" : "remove"]("active");
}
/**
function setupOverflow(): void {
const menuParent = _menu.parentElement!;
- _buttonShowNext = document.createElement('a');
- _buttonShowNext.className = 'mainMenuShowNext';
- _buttonShowNext.href = '#';
+ _buttonShowNext = document.createElement("a");
+ _buttonShowNext.className = "mainMenuShowNext";
+ _buttonShowNext.href = "#";
_buttonShowNext.innerHTML = '<span class="icon icon32 fa-angle-right"></span>';
- _buttonShowNext.setAttribute('aria-hidden', 'true');
- _buttonShowNext.addEventListener('click', showNext);
+ _buttonShowNext.setAttribute("aria-hidden", "true");
+ _buttonShowNext.addEventListener("click", showNext);
menuParent.appendChild(_buttonShowNext);
- _buttonShowPrevious = document.createElement('a');
- _buttonShowPrevious.className = 'mainMenuShowPrevious';
- _buttonShowPrevious.href = '#';
+ _buttonShowPrevious = document.createElement("a");
+ _buttonShowPrevious.className = "mainMenuShowPrevious";
+ _buttonShowPrevious.href = "#";
_buttonShowPrevious.innerHTML = '<span class="icon icon32 fa-angle-left"></span>';
- _buttonShowPrevious.setAttribute('aria-hidden', 'true');
- _buttonShowPrevious.addEventListener('click', showPrevious);
+ _buttonShowPrevious.setAttribute("aria-hidden", "true");
+ _buttonShowPrevious.addEventListener("click", showPrevious);
menuParent.insertBefore(_buttonShowPrevious, menuParent.firstChild);
- _firstElement.addEventListener('transitionend', rebuildVisibility);
+ _firstElement.addEventListener("transitionend", rebuildVisibility);
- window.addEventListener('resize', () => {
- _firstElement.style.setProperty('margin-left', '0px', '');
+ window.addEventListener("resize", () => {
+ _firstElement.style.setProperty("margin-left", "0px", "");
_marginLeft = 0;
rebuildVisibility();
* Setups a11y improvements.
*/
function setupA11y(): void {
- _menu.querySelectorAll('.boxMenuHasChildren').forEach(element => {
- const link = element.querySelector('.boxMenuLink')!;
- link.setAttribute('aria-haspopup', 'true');
- link.setAttribute('aria-expanded', 'false');
+ _menu.querySelectorAll(".boxMenuHasChildren").forEach((element) => {
+ const link = element.querySelector(".boxMenuLink")!;
+ link.setAttribute("aria-haspopup", "true");
+ link.setAttribute("aria-expanded", "false");
- const showMenuButton = document.createElement('button');
- showMenuButton.className = 'visuallyHidden';
+ const showMenuButton = document.createElement("button");
+ showMenuButton.className = "visuallyHidden";
showMenuButton.tabIndex = 0;
- showMenuButton.setAttribute('role', 'button');
- showMenuButton.setAttribute('aria-label', Language.get('wcf.global.button.showMenu'));
+ showMenuButton.setAttribute("role", "button");
+ showMenuButton.setAttribute("aria-label", Language.get("wcf.global.button.showMenu"));
element.insertBefore(showMenuButton, link.nextSibling);
let showMenu = false;
- showMenuButton.addEventListener('click', () => {
+ showMenuButton.addEventListener("click", () => {
showMenu = !showMenu;
- link.setAttribute('aria-expanded', showMenu ? 'true' : 'false');
- showMenuButton.setAttribute('aria-label', Language.get(showMenu ? 'wcf.global.button.hideMenu' : 'wcf.global.button.showMenu'));
+ link.setAttribute("aria-expanded", showMenu ? "true" : "false");
+ showMenuButton.setAttribute(
+ "aria-label",
+ Language.get(showMenu ? "wcf.global.button.hideMenu" : "wcf.global.button.showMenu")
+ );
});
});
}
* Initializes the main menu overflow handling.
*/
export function init(): void {
- const menu = document.querySelector('.mainMenu .boxMenu') as HTMLElement;
- const firstElement = (menu && menu.childElementCount) ? menu.children[0] as HTMLElement : null;
+ const menu = document.querySelector(".mainMenu .boxMenu") as HTMLElement;
+ const firstElement = menu && menu.childElementCount ? (menu.children[0] as HTMLElement) : null;
if (firstElement === null) {
throw new Error("Unable to find the main menu.");
}
_menu = menu;
_firstElement = firstElement;
- UiScreen.on('screen-lg', {
+ UiScreen.on("screen-lg", {
match: enable,
unmatch: disable,
setup: setup,
* @module WoltLabSuite/Core/Ui/Page/JumpTo
*/
-import { DialogCallbackObject, DialogSettings } from '../Dialog/Data';
-import * as Language from '../../Language';
-import UiDialog from '../Dialog';
+import { DialogCallbackObject, DialogSettings } from "../Dialog/Data";
+import * as Language from "../../Language";
+import UiDialog from "../Dialog";
class UiPageJumpTo implements DialogCallbackObject {
private activeElement: HTMLElement;
const redirectUrl = element.dataset.link;
if (redirectUrl) {
callback = function (pageNo) {
- window.location.href = redirectUrl.replace(/pageNo=%d/, 'pageNo=' + pageNo);
+ window.location.href = redirectUrl.replace(/pageNo=%d/, "pageNo=" + pageNo);
};
} else {
- callback = function () {
- };
+ callback = function () {};
}
- } else if (typeof callback !== 'function') {
+ } else if (typeof callback !== "function") {
throw new TypeError("Expected a valid function for parameter 'callback'.");
}
if (!this.elements.has(element)) {
- element.querySelectorAll('.jumpTo').forEach((jumpTo: HTMLElement) => {
- jumpTo.addEventListener('click', (ev) => this.click(element, ev));
+ element.querySelectorAll(".jumpTo").forEach((jumpTo: HTMLElement) => {
+ jumpTo.addEventListener("click", (ev) => this.click(element, ev));
this.elements.set(element, callback!);
});
}
UiDialog.open(this);
- const pages = element.dataset.pages || '0';
+ const pages = element.dataset.pages || "0";
this.input.value = pages;
this.input.max = pages;
this.input.select();
- this.description.textContent = Language.get('wcf.page.jumpTo.description').replace(/#pages#/, pages);
+ this.description.textContent = Language.get("wcf.page.jumpTo.description").replace(/#pages#/, pages);
}
/**
* @param {object} event event object
*/
_keyUp(event: KeyboardEvent): void {
- if (event.key === 'Enter' && !this.submitButton.disabled) {
+ if (event.key === "Enter" && !this.submitButton.disabled) {
this.submit();
return;
}
_dialogSetup(): DialogSettings {
const source = `<dl>
- <dt><label for="jsPaginationPageNo">${Language.get('wcf.page.jumpTo')}</label></dt>
+ <dt><label for="jsPaginationPageNo">${Language.get("wcf.page.jumpTo")}</label></dt>
<dd>
<input type="number" id="jsPaginationPageNo" value="1" min="1" max="1" class="tiny">
<small></small>
</dd>
</dl>
<div class="formSubmit">
- <button class="buttonPrimary">${Language.get('wcf.global.button.submit')}</button>
+ <button class="buttonPrimary">${Language.get("wcf.global.button.submit")}</button>
</div>`;
return {
- id: 'paginationOverlay',
+ id: "paginationOverlay",
options: {
- onSetup: content => {
- this.input = content.querySelector('input')!;
- this.input.addEventListener('keyup', (ev) => this._keyUp(ev));
+ onSetup: (content) => {
+ this.input = content.querySelector("input")!;
+ this.input.addEventListener("keyup", (ev) => this._keyUp(ev));
- this.description = content.querySelector('small')!;
+ this.description = content.querySelector("small")!;
- this.submitButton = content.querySelector('button')!;
- this.submitButton.addEventListener('click', () => this.submit());
+ this.submitButton = content.querySelector("button")!;
+ this.submitButton.addEventListener("click", () => this.submit());
},
- title: Language.get('wcf.global.page.pagination'),
+ title: Language.get("wcf.global.page.pagination"),
},
source: source,
};
* @module WoltLabSuite/Core/Ui/Page/Menu/Abstract
*/
-import * as Core from '../../../Core';
-import * as Environment from '../../../Environment';
-import * as EventHandler from '../../../Event/Handler';
-import * as Language from '../../../Language';
-import * as DomTraverse from '../../../Dom/Traverse';
-import * as UiScreen from '../../Screen';
+import * as Core from "../../../Core";
+import * as Environment from "../../../Environment";
+import * as EventHandler from "../../../Event/Handler";
+import * as Language from "../../../Language";
+import * as DomTraverse from "../../../Dom/Traverse";
+import * as UiScreen from "../../Screen";
-const _pageContainer = document.getElementById('pageContainer')!;
+const _pageContainer = document.getElementById("pageContainer")!;
const enum TouchPosition {
AtEdge = 20,
*
* One 'left', 'right' or ''.
*/
-let _androidTouching = '';
+let _androidTouching = "";
interface ItemData {
itemList: HTMLOListElement;
private removeActiveList = false;
protected constructor(eventIdentifier: string, elementId: string, buttonSelector: string) {
- if (document.body.dataset.template === 'packageInstallationSetup') {
+ if (document.body.dataset.template === "packageInstallationSetup") {
// work-around for WCFSetup on mobile
return;
}
const callbackOpen = this.open.bind(this);
this.button = document.querySelector(buttonSelector) as HTMLElement;
- this.button.addEventListener('click', callbackOpen);
+ this.button.addEventListener("click", callbackOpen);
this.initItems();
this.initHeader();
- EventHandler.add(this.eventIdentifier, 'open', callbackOpen);
- EventHandler.add(this.eventIdentifier, 'close', this.close.bind(this));
- EventHandler.add(this.eventIdentifier, 'updateButtonState', this.updateButtonState.bind(this));
+ EventHandler.add(this.eventIdentifier, "open", callbackOpen);
+ EventHandler.add(this.eventIdentifier, "close", this.close.bind(this));
+ EventHandler.add(this.eventIdentifier, "updateButtonState", this.updateButtonState.bind(this));
- this.menu.addEventListener('animationend', () => {
- if (!this.menu.classList.contains('open')) {
- this.menu.querySelectorAll('.menuOverlayItemList').forEach(itemList => {
+ this.menu.addEventListener("animationend", () => {
+ if (!this.menu.classList.contains("open")) {
+ this.menu.querySelectorAll(".menuOverlayItemList").forEach((itemList) => {
// force the main list to be displayed
- itemList.classList.remove('active', 'hidden');
+ itemList.classList.remove("active", "hidden");
});
}
});
- this.menu.children[0].addEventListener('transitionend', () => {
- this.menu.classList.add('allowScroll');
+ this.menu.children[0].addEventListener("transitionend", () => {
+ this.menu.classList.add("allowScroll");
if (this.removeActiveList) {
this.removeActiveList = false;
const list = this.activeList.pop();
if (list) {
- list.classList.remove('activeList');
+ list.classList.remove("activeList");
}
}
});
- const backdrop = document.createElement('div');
- backdrop.className = 'menuOverlayMobileBackdrop';
- backdrop.addEventListener('click', this.close.bind(this));
+ const backdrop = document.createElement("div");
+ backdrop.className = "menuOverlayMobileBackdrop";
+ backdrop.addEventListener("click", this.close.bind(this));
- this.menu.insertAdjacentElement('afterend', backdrop);
+ this.menu.insertAdjacentElement("afterend", backdrop);
this.menu.parentElement!.insertBefore(backdrop, this.menu.nextSibling);
this.updateButtonState();
- if (Environment.platform() === 'android') {
+ if (Environment.platform() === "android") {
this.initializeAndroid();
}
}
event.preventDefault();
}
- this.menu.classList.add('open');
- this.menu.classList.add('allowScroll');
- this.menu.children[0].classList.add('activeList');
+ this.menu.classList.add("open");
+ this.menu.classList.add("allowScroll");
+ this.menu.children[0].classList.add("activeList");
UiScreen.scrollDisable();
- _pageContainer.classList.add('menuOverlay-' + this.menu.id);
+ _pageContainer.classList.add("menuOverlay-" + this.menu.id);
UiScreen.pageOverlayOpen();
event.preventDefault();
}
- if (this.menu.classList.contains('open')) {
- this.menu.classList.remove('open');
+ if (this.menu.classList.contains("open")) {
+ this.menu.classList.remove("open");
UiScreen.scrollEnable();
UiScreen.pageOverlayClose();
- _pageContainer.classList.remove('menuOverlay-' + this.menu.id);
+ _pageContainer.classList.remove("menuOverlay-" + this.menu.id);
return true;
}
// specify on which side of the page the menu appears
let appearsAt: "left" | "right";
switch (this.menu.id) {
- case 'pageUserMenuMobile':
- appearsAt = 'right';
+ case "pageUserMenuMobile":
+ appearsAt = "right";
break;
- case 'pageMainMenuMobile':
- appearsAt = 'left';
+ case "pageMainMenuMobile":
+ appearsAt = "left";
break;
default:
return;
// horizontal position of the touch start
let touchStart: { x: number; y: number } | undefined = undefined;
- document.addEventListener('touchstart', event => {
+ document.addEventListener("touchstart", (event) => {
const touches = event.touches;
let isLeftEdge: boolean;
let isRightEdge: boolean;
- const isOpen = this.menu.classList.contains('open');
+ const isOpen = this.menu.classList.contains("open");
// check whether we touch the edges of the menu
- if (appearsAt === 'left') {
- isLeftEdge = !isOpen && (touches[0].clientX < TouchPosition.AtEdge);
- isRightEdge = isOpen && (Math.abs(this.menu.offsetWidth - touches[0].clientX) < TouchPosition.AtEdge);
+ if (appearsAt === "left") {
+ isLeftEdge = !isOpen && touches[0].clientX < TouchPosition.AtEdge;
+ isRightEdge = isOpen && Math.abs(this.menu.offsetWidth - touches[0].clientX) < TouchPosition.AtEdge;
} else {
- isLeftEdge = isOpen && (Math.abs(document.body.clientWidth - this.menu.offsetWidth - touches[0].clientX) < TouchPosition.AtEdge);
- isRightEdge = !isOpen && ((document.body.clientWidth - touches[0].clientX) < TouchPosition.AtEdge);
+ isLeftEdge =
+ isOpen &&
+ Math.abs(document.body.clientWidth - this.menu.offsetWidth - touches[0].clientX) < TouchPosition.AtEdge;
+ isRightEdge = !isOpen && document.body.clientWidth - touches[0].clientX < TouchPosition.AtEdge;
}
// abort if more than one touch
if (touches.length > 1) {
if (_androidTouching) {
- Core.triggerEvent(document, 'touchend');
+ Core.triggerEvent(document, "touchend");
}
return;
}
}
}
// break if redactor is in use
- if (document.documentElement.classList.contains('redactorActive')) {
+ if (document.documentElement.classList.contains("redactorActive")) {
return;
}
y: touches[0].clientY,
};
- if (isLeftEdge) _androidTouching = 'left';
- if (isRightEdge) _androidTouching = 'right';
+ if (isLeftEdge) _androidTouching = "left";
+ if (isRightEdge) _androidTouching = "right";
});
- document.addEventListener('touchend', event => {
+ document.addEventListener("touchend", (event) => {
// break if we did not start a touch
if (!_androidTouching || !touchStart) {
return;
}
// break if the menu did not even start opening
- if (!this.menu.classList.contains('open')) {
+ if (!this.menu.classList.contains("open")) {
// reset
touchStart = undefined;
- _androidTouching = '';
+ _androidTouching = "";
return;
}
}
// clean up touch styles
- this.menu.classList.add('androidMenuTouchEnd');
- this.menu.style.removeProperty('transform');
+ this.menu.classList.add("androidMenuTouchEnd");
+ this.menu.style.removeProperty("transform");
backdrop.style.removeProperty(appearsAt);
- this.menu.addEventListener('transitionend', () => {
- this.menu.classList.remove('androidMenuTouchEnd');
- }, {once: true});
+ this.menu.addEventListener(
+ "transitionend",
+ () => {
+ this.menu.classList.remove("androidMenuTouchEnd");
+ },
+ { once: true }
+ );
// check whether the user moved the finger far enough
- if (appearsAt === 'left') {
- if (_androidTouching === 'left' && position < (touchStart.x + 100)) this.close();
- if (_androidTouching === 'right' && position < (touchStart.x - 100)) this.close();
+ if (appearsAt === "left") {
+ if (_androidTouching === "left" && position < touchStart.x + 100) this.close();
+ if (_androidTouching === "right" && position < touchStart.x - 100) this.close();
} else {
- if (_androidTouching === 'left' && position > (touchStart.x + 100)) this.close();
- if (_androidTouching === 'right' && position > (touchStart.x - 100)) this.close();
+ if (_androidTouching === "left" && position > touchStart.x + 100) this.close();
+ if (_androidTouching === "right" && position > touchStart.x - 100) this.close();
}
// reset
touchStart = undefined;
- _androidTouching = '';
+ _androidTouching = "";
});
- document.addEventListener('touchmove', event => {
+ document.addEventListener("touchmove", (event) => {
// break if we did not start a touch
if (!_androidTouching || !touchStart) {
return;
// check whether the user started moving in the correct direction
// this avoids false positives, in case the user just wanted to tap
let movedFromEdge = false;
- if (_androidTouching === 'left') movedFromEdge = touches[0].clientX > (touchStart.x + TouchPosition.MovedHorizontally);
- if (_androidTouching === 'right') movedFromEdge = touches[0].clientX < (touchStart.x - TouchPosition.MovedHorizontally);
+ if (_androidTouching === "left")
+ movedFromEdge = touches[0].clientX > touchStart.x + TouchPosition.MovedHorizontally;
+ if (_androidTouching === "right")
+ movedFromEdge = touches[0].clientX < touchStart.x - TouchPosition.MovedHorizontally;
const movedVertically = Math.abs(touches[0].clientY - touchStart.y) > TouchPosition.MovedVertically;
- let isOpen = this.menu.classList.contains('open');
+ let isOpen = this.menu.classList.contains("open");
if (!isOpen && movedFromEdge && !movedVertically) {
// the menu is not yet open, but the user moved into the right direction
this.open();
if (isOpen) {
// update CSS to the new finger position
let position = touches[0].clientX;
- if (appearsAt === 'right') position = document.body.clientWidth - position;
+ if (appearsAt === "right") position = document.body.clientWidth - position;
if (position > this.menu.offsetWidth) position = this.menu.offsetWidth;
if (position < 0) position = 0;
- this.menu.style.setProperty('transform', 'translateX(' + (appearsAt === 'left' ? 1 : -1) * (position - this.menu.offsetWidth) + 'px)');
- backdrop.style.setProperty(appearsAt, Math.min(this.menu.offsetWidth, position) + 'px');
+ this.menu.style.setProperty(
+ "transform",
+ "translateX(" + (appearsAt === "left" ? 1 : -1) * (position - this.menu.offsetWidth) + "px)"
+ );
+ backdrop.style.setProperty(appearsAt, Math.min(this.menu.offsetWidth, position) + "px");
}
});
}
* Initializes all menu items.
*/
private initItems(): void {
- this.menu.querySelectorAll('.menuOverlayItemLink').forEach((element: HTMLAnchorElement) => {
+ this.menu.querySelectorAll(".menuOverlayItemLink").forEach((element: HTMLAnchorElement) => {
this.initItem(element);
});
}
const parent = item.parentElement!;
const more = parent.dataset.more;
if (more) {
- item.addEventListener('click', event => {
+ item.addEventListener("click", (event) => {
event.preventDefault();
event.stopPropagation();
- EventHandler.fire(this.eventIdentifier, 'more', {
+ EventHandler.fire(this.eventIdentifier, "more", {
handler: this,
identifier: more,
item: item,
}
// handle static items with an icon-type button next to it (acp menu)
- if (itemList.nodeName !== 'OL' && itemList.classList.contains('menuOverlayItemLinkIcon')) {
+ if (itemList.nodeName !== "OL" && itemList.classList.contains("menuOverlayItemLinkIcon")) {
// add wrapper
- const wrapper = document.createElement('span');
- wrapper.className = 'menuOverlayItemWrapper';
+ const wrapper = document.createElement("span");
+ wrapper.className = "menuOverlayItemWrapper";
parent.insertBefore(wrapper, item);
wrapper.appendChild(item);
return;
}
- const isLink = item.href !== '#';
+ const isLink = item.href !== "#";
const parentItemList = parent.parentElement as HTMLOListElement;
let itemTitle = itemList.dataset.title;
});
if (!itemTitle) {
- itemTitle = DomTraverse.childByClass(item, 'menuOverlayItemTitle')!.textContent!;
+ itemTitle = DomTraverse.childByClass(item, "menuOverlayItemTitle")!.textContent!;
itemList.dataset.title = itemTitle;
}
const callbackLink = this.showItemList.bind(this, item);
if (isLink) {
- const wrapper = document.createElement('span');
- wrapper.className = 'menuOverlayItemWrapper';
+ const wrapper = document.createElement("span");
+ wrapper.className = "menuOverlayItemWrapper";
parent.insertBefore(wrapper, item);
wrapper.appendChild(item);
- const moreLink = document.createElement('a');
- moreLink.href = '#';
- moreLink.className = 'menuOverlayItemLinkIcon' + (item.classList.contains('active') ? ' active' : '');
+ const moreLink = document.createElement("a");
+ moreLink.href = "#";
+ moreLink.className = "menuOverlayItemLinkIcon" + (item.classList.contains("active") ? " active" : "");
moreLink.innerHTML = '<span class="icon icon24 fa-angle-right"></span>';
- moreLink.addEventListener('click', callbackLink);
+ moreLink.addEventListener("click", callbackLink);
wrapper.appendChild(moreLink);
} else {
- item.classList.add('menuOverlayItemLinkMore');
- item.addEventListener('click', callbackLink);
+ item.classList.add("menuOverlayItemLinkMore");
+ item.addEventListener("click", callbackLink);
}
- const backLinkItem = document.createElement('li');
- backLinkItem.className = 'menuOverlayHeader';
+ const backLinkItem = document.createElement("li");
+ backLinkItem.className = "menuOverlayHeader";
- const wrapper = document.createElement('span');
- wrapper.className = 'menuOverlayItemWrapper';
+ const wrapper = document.createElement("span");
+ wrapper.className = "menuOverlayItemWrapper";
- const backLink = document.createElement('a');
- backLink.href = '#';
- backLink.className = 'menuOverlayItemLink menuOverlayBackLink';
- backLink.textContent = parentItemList.dataset.title || '';
- backLink.addEventListener('click', this.hideItemList.bind(this, item));
+ const backLink = document.createElement("a");
+ backLink.href = "#";
+ backLink.className = "menuOverlayItemLink menuOverlayBackLink";
+ backLink.textContent = parentItemList.dataset.title || "";
+ backLink.addEventListener("click", this.hideItemList.bind(this, item));
- const closeLink = document.createElement('a');
- closeLink.href = '#';
- closeLink.className = 'menuOverlayItemLinkIcon';
+ const closeLink = document.createElement("a");
+ closeLink.href = "#";
+ closeLink.className = "menuOverlayItemLinkIcon";
closeLink.innerHTML = '<span class="icon icon24 fa-times"></span>';
- closeLink.addEventListener('click', this.close.bind(this));
+ closeLink.addEventListener("click", this.close.bind(this));
wrapper.appendChild(backLink);
wrapper.appendChild(closeLink);
itemList.insertBefore(backLinkItem, itemList.firstElementChild);
- if (!backLinkItem.nextElementSibling!.classList.contains('menuOverlayTitle')) {
- const titleItem = document.createElement('li');
- titleItem.className = 'menuOverlayTitle';
- const title = document.createElement('span');
+ if (!backLinkItem.nextElementSibling!.classList.contains("menuOverlayTitle")) {
+ const titleItem = document.createElement("li");
+ titleItem.className = "menuOverlayTitle";
+ const title = document.createElement("span");
title.textContent = itemTitle;
titleItem.appendChild(title);
* Renders the menu item list header.
*/
private initHeader(): void {
- const listItem = document.createElement('li');
- listItem.className = 'menuOverlayHeader';
+ const listItem = document.createElement("li");
+ listItem.className = "menuOverlayHeader";
- const wrapper = document.createElement('span');
- wrapper.className = 'menuOverlayItemWrapper';
+ const wrapper = document.createElement("span");
+ wrapper.className = "menuOverlayItemWrapper";
listItem.appendChild(wrapper);
- const logoWrapper = document.createElement('span');
- logoWrapper.className = 'menuOverlayLogoWrapper';
+ const logoWrapper = document.createElement("span");
+ logoWrapper.className = "menuOverlayLogoWrapper";
wrapper.appendChild(logoWrapper);
- const logo = document.createElement('span');
- logo.className = 'menuOverlayLogo';
+ const logo = document.createElement("span");
+ logo.className = "menuOverlayLogo";
const pageLogo = this.menu.dataset.pageLogo!;
- logo.style.setProperty('background-image', `url("${pageLogo}")`, '');
+ logo.style.setProperty("background-image", `url("${pageLogo}")`, "");
logoWrapper.appendChild(logo);
- const closeLink = document.createElement('a');
- closeLink.href = '#';
- closeLink.className = 'menuOverlayItemLinkIcon';
+ const closeLink = document.createElement("a");
+ closeLink.href = "#";
+ closeLink.className = "menuOverlayItemLinkIcon";
closeLink.innerHTML = '<span class="icon icon24 fa-times"></span>';
- closeLink.addEventListener('click', this.close.bind(this));
+ closeLink.addEventListener("click", this.close.bind(this));
wrapper.appendChild(closeLink);
- const list = DomTraverse.childByClass(this.menu, 'menuOverlayItemList')!;
+ const list = DomTraverse.childByClass(this.menu, "menuOverlayItemList")!;
list.insertBefore(listItem, list.firstElementChild);
}
event.preventDefault();
}
- this.menu.classList.remove('allowScroll');
+ this.menu.classList.remove("allowScroll");
this.removeActiveList = true;
const data = this.items.get(item)!;
- data.parentItemList.classList.remove('hidden');
+ data.parentItemList.classList.remove("hidden");
this.updateDepth(false);
}
const load = data.itemList.dataset.load;
if (load) {
- if (!Core.stringToBool(item.dataset.loaded || '')) {
+ if (!Core.stringToBool(item.dataset.loaded || "")) {
const target = event.currentTarget as HTMLElement;
const icon = target.firstElementChild!;
- if (icon.classList.contains('fa-angle-right')) {
- icon.classList.remove('fa-angle-right');
- icon.classList.add('fa-spinner');
+ if (icon.classList.contains("fa-angle-right")) {
+ icon.classList.remove("fa-angle-right");
+ icon.classList.add("fa-spinner");
}
- EventHandler.fire(this.eventIdentifier, 'load_' + load);
+ EventHandler.fire(this.eventIdentifier, "load_" + load);
return;
}
}
- this.menu.classList.remove('allowScroll');
+ this.menu.classList.remove("allowScroll");
- data.itemList.classList.add('activeList');
- data.parentItemList.classList.add('hidden');
+ data.itemList.classList.add("activeList");
+ data.parentItemList.classList.add("hidden");
this.activeList.push(data.itemList);
}
private updateDepth(increase: boolean): void {
- this.depth += (increase) ? 1 : -1;
+ this.depth += increase ? 1 : -1;
let offset = this.depth * -100;
- if (Language.get('wcf.global.pageDirection') === 'rtl') {
+ if (Language.get("wcf.global.pageDirection") === "rtl") {
// reverse logic for RTL
offset *= -1;
}
const child = this.menu.children[0] as HTMLElement;
- child.style.setProperty('transform', `translateX(${offset}%)`, '');
+ child.style.setProperty("transform", `translateX(${offset}%)`, "");
}
private updateButtonState(): void {
let hasNewContent = false;
- const itemList = this.menu.querySelector('.menuOverlayItemList');
- this.menu.querySelectorAll('.badgeUpdate').forEach(badge => {
+ const itemList = this.menu.querySelector(".menuOverlayItemList");
+ this.menu.querySelectorAll(".badgeUpdate").forEach((badge) => {
const value = badge.textContent!;
- if (~~value > 0 && badge.closest('.menuOverlayItemList') === itemList) {
+ if (~~value > 0 && badge.closest(".menuOverlayItemList") === itemList) {
hasNewContent = true;
}
});
- this.button.classList[hasNewContent ? 'add' : 'remove']('pageMenuMobileButtonHasContent');
+ this.button.classList[hasNewContent ? "add" : "remove"]("pageMenuMobileButtonHasContent");
}
}
-import * as Ajax from '../../Ajax';
-import { AjaxCallbackObject, DatabaseObjectActionResponse } from '../../Ajax/Data';
-import { DialogCallbackObject } from '../Dialog/Data';
-import DomUtil from '../../Dom/Util';
-import * as Language from '../../Language';
-import * as StringUtil from '../../StringUtil';
-import UiDialog from '../Dialog';
+import * as Ajax from "../../Ajax";
+import { AjaxCallbackObject, DatabaseObjectActionResponse } from "../../Ajax/Data";
+import { DialogCallbackObject } from "../Dialog/Data";
+import DomUtil from "../../Dom/Util";
+import * as Language from "../../Language";
+import * as StringUtil from "../../StringUtil";
+import UiDialog from "../Dialog";
-type CallbackSelect = (value: string) => void
+type CallbackSelect = (value: string) => void;
interface SearchResult {
displayLink: string;
const value = this.searchInput!.value.trim();
if (value.length < 3) {
- DomUtil.innerError(inputContainer, Language.get('wcf.page.search.error.tooShort'));
+ DomUtil.innerError(inputContainer, Language.get("wcf.page.search.error.tooShort"));
return;
} else {
DomUtil.innerError(inputContainer, false);
event.preventDefault();
const page = event.currentTarget as HTMLElement;
- const pageTitle = page.querySelector('h3')!;
+ const pageTitle = page.querySelector("h3")!;
- this.callbackSelect!(page.dataset.pageId! + '#' + pageTitle.textContent!.replace(/['"]/g, ''));
+ this.callbackSelect!(page.dataset.pageId! + "#" + pageTitle.textContent!.replace(/['"]/g, ""));
UiDialog.close(this);
}
_ajaxSuccess(data: AjaxResponse): void {
const html = data.returnValues
- .map(page => {
+ .map((page) => {
const name = StringUtil.escapeHTML(page.name);
const displayLink = StringUtil.escapeHTML(page.displayLink);
</div>
</li>`;
})
- .join('');
+ .join("");
this.resultList!.innerHTML = html;
- DomUtil[html ? 'show' : 'hide'](this.resultContainer!);
+ DomUtil[html ? "show" : "hide"](this.resultContainer!);
if (html) {
- this.resultList!.querySelectorAll('.containerHeadline').forEach((item: HTMLElement) => {
- item.addEventListener('click', (ev) => this.click(ev));
+ this.resultList!.querySelectorAll(".containerHeadline").forEach((item: HTMLElement) => {
+ item.addEventListener("click", (ev) => this.click(ev));
});
} else {
- DomUtil.innerError(this.searchInput!.parentElement!, Language.get('wcf.page.search.error.noResults'));
+ DomUtil.innerError(this.searchInput!.parentElement!, Language.get("wcf.page.search.error.noResults"));
}
}
_ajaxSetup() {
return {
data: {
- actionName: 'search',
- className: 'wcf\\data\\page\\PageAction',
+ actionName: "search",
+ className: "wcf\\data\\page\\PageAction",
},
};
}
_dialogSetup() {
return {
- id: 'wcfUiPageSearch',
+ id: "wcfUiPageSearch",
options: {
onSetup: () => {
- this.searchInput = document.getElementById('wcfUiPageSearchInput') as HTMLInputElement;
- this.searchInput.addEventListener('keydown', event => {
- if (event.key === 'Enter') {
+ this.searchInput = document.getElementById("wcfUiPageSearchInput") as HTMLInputElement;
+ this.searchInput.addEventListener("keydown", (event) => {
+ if (event.key === "Enter") {
this.search(event);
}
});
- this.searchInput.nextElementSibling!.addEventListener('click', (ev) => this.search(ev));
+ this.searchInput.nextElementSibling!.addEventListener("click", (ev) => this.search(ev));
- this.resultContainer = document.getElementById('wcfUiPageSearchResultContainer') as HTMLElement;
- this.resultList = document.getElementById('wcfUiPageSearchResultList') as HTMLOListElement;
+ this.resultContainer = document.getElementById("wcfUiPageSearchResultContainer") as HTMLElement;
+ this.resultList = document.getElementById("wcfUiPageSearchResultList") as HTMLOListElement;
},
onShow: () => {
this.searchInput!.focus();
},
- title: Language.get('wcf.page.search'),
+ title: Language.get("wcf.page.search"),
},
source: `<div class="section">
<dl>
- <dt><label for="wcfUiPageSearchInput">${Language.get('wcf.page.search.name')}</label></dt>
+ <dt><label for="wcfUiPageSearchInput">${Language.get("wcf.page.search.name")}</label></dt>
<dd>
<div class="inputAddon">
<input type="text" id="wcfUiPageSearchInput" class="long">
</div>
<section id="wcfUiPageSearchResultContainer" class="section" style="display: none;">
<header class="sectionHeader">
- <h2 class="sectionTitle">${Language.get('wcf.page.search.results')}</h2>
+ <h2 class="sectionTitle">${Language.get("wcf.page.search.results")}</h2>
</header>
<ol id="wcfUiPageSearchResultList" class="containerList"></ol>
</section>`,
* @module WoltLabSuite/Core/Ui/Page/Search/Handler
*/
-import * as Language from '../../../Language';
-import * as StringUtil from '../../../StringUtil';
-import DomUtil from '../../../Dom/Util';
-import UiDialog from '../../Dialog';
-import UiPageSearchInput from './Input';
-import { DatabaseObjectActionResponse } from '../../../Ajax/Data';
+import * as Language from "../../../Language";
+import * as StringUtil from "../../../StringUtil";
+import DomUtil from "../../../Dom/Util";
+import UiDialog from "../../Dialog";
+import UiPageSearchInput from "./Input";
+import { DatabaseObjectActionResponse } from "../../../Ajax/Data";
-type CallbackSelect = (objectId: number) => void
+type CallbackSelect = (objectId: number) => void;
interface ItemData {
description?: string;
UiDialog.open(this);
UiDialog.setTitle(this, title);
- this.searchInputLabel!.textContent = Language.get(labelLanguageItem || 'wcf.page.pageObjectID.search.terms');
+ this.searchInputLabel!.textContent = Language.get(labelLanguageItem || "wcf.page.pageObjectID.search.terms");
this._getSearchInputHandler().setPageId(pageId);
}
this.resetList();
if (!Array.isArray(data.returnValues) || data.returnValues.length === 0) {
- DomUtil.innerError(this.searchInput!, Language.get('wcf.page.pageObjectID.search.noResults'));
+ DomUtil.innerError(this.searchInput!, Language.get("wcf.page.pageObjectID.search.noResults"));
return;
}
- data.returnValues.forEach(item => {
+ data.returnValues.forEach((item) => {
let image = item.image;
if (/^fa-/.test(image)) {
- image = `<span class="icon icon48 ${image} pointer jsTooltip" title="${Language.get('wcf.global.select')}"></span>`;
+ image = `<span class="icon icon48 ${image} pointer jsTooltip" title="${Language.get(
+ "wcf.global.select"
+ )}"></span>`;
}
- const listItem = document.createElement('li');
+ const listItem = document.createElement("li");
listItem.dataset.objectId = item.objectID.toString();
- const description = item.description ? `<p>${item.description}</p>` : ''
+ const description = item.description ? `<p>${item.description}</p>` : "";
listItem.innerHTML = `<div class="box48">
${image}
<div>
</div>
</div>`;
- listItem.addEventListener('click', this.click.bind(this));
+ listItem.addEventListener("click", this.click.bind(this));
this.resultList!.appendChild(listItem);
});
private resetList(): void {
DomUtil.innerError(this.searchInput!, false);
- this.resultList!.innerHTML = '';
+ this.resultList!.innerHTML = "";
DomUtil.hide(this.resultListContainer!);
}
*/
_getSearchInputHandler(): UiPageSearchInput {
if (!this.searchInputHandler) {
- const input = document.getElementById('wcfUiPageSearchInput') as HTMLInputElement;
+ const input = document.getElementById("wcfUiPageSearchInput") as HTMLInputElement;
this.searchInputHandler = new UiPageSearchInput(input, {
callbackSuccess: this.buildList.bind(this),
});
*/
private click(event: MouseEvent): void {
const clickTarget = event.target as HTMLElement;
- if (clickTarget.nodeName === 'A') {
+ if (clickTarget.nodeName === "A") {
return;
}
_dialogSetup() {
return {
- id: 'wcfUiPageSearchHandler',
+ id: "wcfUiPageSearchHandler",
options: {
onShow: (content: HTMLElement): void => {
if (!this.searchInput) {
- this.searchInput = document.getElementById('wcfUiPageSearchInput') as HTMLInputElement;
+ this.searchInput = document.getElementById("wcfUiPageSearchInput") as HTMLInputElement;
this.searchInputLabel = content.querySelector('label[for="wcfUiPageSearchInput"]') as HTMLLabelElement;
- this.resultList = document.getElementById('wcfUiPageSearchResultList') as HTMLUListElement;
- this.resultListContainer = document.getElementById('wcfUiPageSearchResultListContainer') as HTMLElement;
+ this.resultList = document.getElementById("wcfUiPageSearchResultList") as HTMLUListElement;
+ this.resultListContainer = document.getElementById("wcfUiPageSearchResultListContainer") as HTMLElement;
}
// clear search input
- this.searchInput.value = '';
+ this.searchInput.value = "";
// reset results
DomUtil.hide(this.resultListContainer!);
- this.resultList!.innerHTML = '';
+ this.resultList!.innerHTML = "";
this.searchInput.focus();
},
- title: '',
+ title: "",
},
source: `<div class="section">
<dl>
<dt>
- <label for="wcfUiPageSearchInput">${Language.get('wcf.page.pageObjectID.search.terms')}</label>
+ <label for="wcfUiPageSearchInput">${Language.get("wcf.page.pageObjectID.search.terms")}</label>
</dt>
<dd>
<input type="text" id="wcfUiPageSearchInput" class="long">
</div>
<section id="wcfUiPageSearchResultListContainer" class="section sectionContainerList">
<header class="sectionHeader">
- <h2 class="sectionTitle">${Language.get('wcf.page.pageObjectID.search.results')}</h2>
+ <h2 class="sectionTitle">${Language.get("wcf.page.pageObjectID.search.results")}</h2>
</header>
<ul id="wcfUiPageSearchResultList" class="containerList wcfUiPageSearchResultList"></ul>
</section>`,
* @module WoltLabSuite/Core/Ui/Page/Search/Input
*/
-import * as Core from '../../../Core';
-import UiSearchInput from '../../Search/Input';
-import { SearchInputOptions } from '../../Search/Data';
-import { DatabaseObjectActionPayload, DatabaseObjectActionResponse } from '../../../Ajax/Data';
+import * as Core from "../../../Core";
+import UiSearchInput from "../../Search/Input";
+import { SearchInputOptions } from "../../Search/Data";
+import { DatabaseObjectActionPayload, DatabaseObjectActionResponse } from "../../../Ajax/Data";
-type CallbackSuccess = (data: DatabaseObjectActionResponse) => void
+type CallbackSuccess = (data: DatabaseObjectActionResponse) => void;
interface PageSearchOptions extends SearchInputOptions {
- callbackSuccess: CallbackSuccess
+ callbackSuccess: CallbackSuccess;
}
class UiPageSearchInput extends UiSearchInput {
private pageId: number;
constructor(element: HTMLInputElement, options: PageSearchOptions) {
- if (typeof options.callbackSuccess !== 'function') {
+ if (typeof options.callbackSuccess !== "function") {
throw new Error("Expected a valid callback function for 'callbackSuccess'.");
}
- options = Core.extend({
- ajax: {
- className: 'wcf\\data\\page\\PageAction',
+ options = Core.extend(
+ {
+ ajax: {
+ className: "wcf\\data\\page\\PageAction",
+ },
},
- }, options) as any;
+ options
+ ) as any;
super(element, options);
* @module WoltLabSuite/Core/Ui/Pagination
*/
-import * as Core from '../Core';
-import * as Language from '../Language';
-import * as StringUtil from '../StringUtil';
-import * as UiPageJumpTo from './Page/JumpTo';
+import * as Core from "../Core";
+import * as Language from "../Language";
+import * as StringUtil from "../StringUtil";
+import * as UiPageJumpTo from "./Page/JumpTo";
class UiPagination {
/**
this.element = element;
this.activePage = options.activePage;
this.maxPage = options.maxPage;
- if (typeof options.callbackSwitch === 'function') {
+ if (typeof options.callbackSwitch === "function") {
this.callbackSwitch = options.callbackSwitch;
}
- if (typeof options.callbackShouldSwitch === 'function') {
+ if (typeof options.callbackShouldSwitch === "function") {
this.callbackShouldSwitch = options.callbackShouldSwitch;
}
- this.element.classList.add('pagination');
+ this.element.classList.add("pagination");
this.rebuild();
}
let hasHiddenPages = false;
// clear content
- this.element.innerHTML = '';
+ this.element.innerHTML = "";
- const list = document.createElement('ul');
- let listItem = document.createElement('li');
- listItem.className = 'skip';
+ const list = document.createElement("ul");
+ let listItem = document.createElement("li");
+ listItem.className = "skip";
list.appendChild(listItem);
- let iconClassNames = 'icon icon24 fa-chevron-left';
+ let iconClassNames = "icon icon24 fa-chevron-left";
if (this.activePage > 1) {
- const link = document.createElement('a');
- link.className = iconClassNames + ' jsTooltip';
- link.href = '#';
- link.title = Language.get('wcf.global.page.previous');
- link.rel = 'prev';
+ const link = document.createElement("a");
+ link.className = iconClassNames + " jsTooltip";
+ link.href = "#";
+ link.title = Language.get("wcf.global.page.previous");
+ link.rel = "prev";
listItem.appendChild(link);
- link.addEventListener('click', (ev) => this.switchPage(this.activePage - 1, ev));
+ link.addEventListener("click", (ev) => this.switchPage(this.activePage - 1, ev));
} else {
listItem.innerHTML = '<span class="' + iconClassNames + '"></span>';
- listItem.classList.add('disabled');
+ listItem.classList.add("disabled");
}
// add first page
}
// left ... links
- const jumpToHtml = '<a class="jsTooltip" title="' + Language.get('wcf.page.jumpTo') + '">…</a>';
+ const jumpToHtml = '<a class="jsTooltip" title="' + Language.get("wcf.page.jumpTo") + '">…</a>';
if (left > 1) {
if (left - 1 < 2) {
list.appendChild(this.createLink(2));
} else {
- listItem = document.createElement('li');
- listItem.className = 'jumpTo';
+ listItem = document.createElement("li");
+ listItem.className = "jumpTo";
listItem.innerHTML = jumpToHtml;
list.appendChild(listItem);
hasHiddenPages = true;
if (this.maxPage - right < 2) {
list.appendChild(this.createLink(this.maxPage - 1));
} else {
- listItem = document.createElement('li');
- listItem.className = 'jumpTo';
+ listItem = document.createElement("li");
+ listItem.className = "jumpTo";
listItem.innerHTML = jumpToHtml;
list.appendChild(listItem);
hasHiddenPages = true;
list.appendChild(this.createLink(this.maxPage));
// add next button
- listItem = document.createElement('li');
- listItem.className = 'skip';
+ listItem = document.createElement("li");
+ listItem.className = "skip";
list.appendChild(listItem);
- iconClassNames = 'icon icon24 fa-chevron-right';
+ iconClassNames = "icon icon24 fa-chevron-right";
if (this.activePage < this.maxPage) {
- const link = document.createElement('a');
- link.className = iconClassNames + ' jsTooltip';
- link.href = '#';
- link.title = Language.get('wcf.global.page.next');
- link.rel = 'next';
+ const link = document.createElement("a");
+ link.className = iconClassNames + " jsTooltip";
+ link.href = "#";
+ link.title = Language.get("wcf.global.page.next");
+ link.rel = "next";
listItem.appendChild(link);
- link.addEventListener('click', (ev) => this.switchPage(this.activePage + 1, ev));
+ link.addEventListener("click", (ev) => this.switchPage(this.activePage + 1, ev));
} else {
listItem.innerHTML = '<span class="' + iconClassNames + '"></span>';
- listItem.classList.add('disabled');
+ listItem.classList.add("disabled");
}
if (hasHiddenPages) {
* Creates a link to a specific page.
*/
private createLink(pageNo: number): HTMLElement {
- const listItem = document.createElement('li');
+ const listItem = document.createElement("li");
if (pageNo !== this.activePage) {
- const link = document.createElement('a');
+ const link = document.createElement("a");
link.textContent = StringUtil.addThousandsSeparator(pageNo);
- link.addEventListener('click', (ev) => this.switchPage(pageNo, ev));
+ link.addEventListener("click", (ev) => this.switchPage(pageNo, ev));
listItem.appendChild(link);
} else {
- listItem.classList.add('active');
- listItem.innerHTML = '<span>' + StringUtil.addThousandsSeparator(pageNo) + '</span><span class="invisible">' + Language.get('wcf.page.pagePosition', {
- pageNo: pageNo,
- pages: this.maxPage,
- }) + '</span>';
+ listItem.classList.add("active");
+ listItem.innerHTML =
+ "<span>" +
+ StringUtil.addThousandsSeparator(pageNo) +
+ '</span><span class="invisible">' +
+ Language.get("wcf.page.pagePosition", {
+ pageNo: pageNo,
+ pages: this.maxPage,
+ }) +
+ "</span>";
}
return listItem;
}
const target = event.currentTarget as HTMLElement;
// force tooltip to vanish and strip positioning
if (target && target.dataset.tooltip) {
- const tooltip = document.getElementById('balloonTooltip');
+ const tooltip = document.getElementById("balloonTooltip");
if (tooltip) {
- Core.triggerEvent(target, 'mouseleave');
- tooltip.style.removeProperty('top');
- tooltip.style.removeProperty('bottom');
+ Core.triggerEvent(target, "mouseleave");
+ tooltip.style.removeProperty("top");
+ tooltip.style.removeProperty("bottom");
}
}
}
}
}
-export = UiPagination
+export = UiPagination;
type CallbackSwitch = (pageNo: number) => void;
type CallbackShouldSwitch = (pageNo: number) => boolean;
interface PaginationOptions {
activePage: number;
maxPage: number;
- callbackShouldSwitch?: CallbackShouldSwitch | null,
- callbackSwitch?: CallbackSwitch | null,
+ callbackShouldSwitch?: CallbackShouldSwitch | null;
+ callbackSwitch?: CallbackSwitch | null;
}
* @module WoltLabSuite/Core/Ui/Screen
*/
-import * as Core from '../Core';
-import * as Environment from '../Environment';
+import * as Core from "../Core";
+import * as Environment from "../Environment";
const _mql = new Map<string, MediaQueryData>();
let _scrollTop = 0;
let _pageOverlayCounter = 0;
-const _mqMap = new Map<string, string>(Object.entries({
- 'screen-xs': '(max-width: 544px)', /* smartphone */
- 'screen-sm': '(min-width: 545px) and (max-width: 768px)', /* tablet (portrait) */
- 'screen-sm-down': '(max-width: 768px)', /* smartphone + tablet (portrait) */
- 'screen-sm-up': '(min-width: 545px)', /* tablet (portrait) + tablet (landscape) + desktop */
- 'screen-sm-md': '(min-width: 545px) and (max-width: 1024px)', /* tablet (portrait) + tablet (landscape) */
- 'screen-md': '(min-width: 769px) and (max-width: 1024px)', /* tablet (landscape) */
- 'screen-md-down': '(max-width: 1024px)', /* smartphone + tablet (portrait) + tablet (landscape) */
- 'screen-md-up': '(min-width: 769px)', /* tablet (landscape) + desktop */
- 'screen-lg': '(min-width: 1025px)', /* desktop */
- 'screen-lg-only': '(min-width: 1025px) and (max-width: 1280px)',
- 'screen-lg-down': '(max-width: 1280px)',
- 'screen-xl': '(min-width: 1281px)',
-}));
+const _mqMap = new Map<string, string>(
+ Object.entries({
+ "screen-xs": "(max-width: 544px)" /* smartphone */,
+ "screen-sm": "(min-width: 545px) and (max-width: 768px)" /* tablet (portrait) */,
+ "screen-sm-down": "(max-width: 768px)" /* smartphone + tablet (portrait) */,
+ "screen-sm-up": "(min-width: 545px)" /* tablet (portrait) + tablet (landscape) + desktop */,
+ "screen-sm-md": "(min-width: 545px) and (max-width: 1024px)" /* tablet (portrait) + tablet (landscape) */,
+ "screen-md": "(min-width: 769px) and (max-width: 1024px)" /* tablet (landscape) */,
+ "screen-md-down": "(max-width: 1024px)" /* smartphone + tablet (portrait) + tablet (landscape) */,
+ "screen-md-up": "(min-width: 769px)" /* tablet (landscape) + desktop */,
+ "screen-lg": "(min-width: 1025px)" /* desktop */,
+ "screen-lg-only": "(min-width: 1025px) and (max-width: 1280px)",
+ "screen-lg-down": "(max-width: 1280px)",
+ "screen-xl": "(min-width: 1281px)",
+ })
+);
// Microsoft Edge rewrites the media queries to whatever it
// pleases, causing the input and output query to mismatch
* to remove binding by calling the `remove` method.
*/
export function on(query: string, callbacks: Callbacks): string {
- const uuid = Core.getUuid(), queryObject = _getQueryObject(query);
+ const uuid = Core.getUuid(),
+ queryObject = _getQueryObject(query);
- if (typeof callbacks.match === 'function') {
+ if (typeof callbacks.match === "function") {
queryObject.callbacksMatch.set(uuid, callbacks.match);
}
- if (typeof callbacks.unmatch === 'function') {
+ if (typeof callbacks.unmatch === "function") {
queryObject.callbacksUnmatch.set(uuid, callbacks.unmatch);
}
- if (typeof callbacks.setup === 'function') {
+ if (typeof callbacks.setup === "function") {
if (queryObject.mql.matches) {
callbacks.setup();
} else {
export function scrollDisable(): void {
if (_scrollDisableCounter === 0) {
_scrollTop = document.body.scrollTop;
- _scrollOffsetFrom = 'body';
+ _scrollOffsetFrom = "body";
if (!_scrollTop) {
_scrollTop = document.documentElement.scrollTop;
- _scrollOffsetFrom = 'documentElement';
+ _scrollOffsetFrom = "documentElement";
}
- const pageContainer = document.getElementById('pageContainer')!;
+ const pageContainer = document.getElementById("pageContainer")!;
// setting translateY causes Mobile Safari to snap
- if (Environment.platform() === 'ios') {
- pageContainer.style.setProperty('position', 'relative', '');
- pageContainer.style.setProperty('top', '-' + _scrollTop + 'px', '');
+ if (Environment.platform() === "ios") {
+ pageContainer.style.setProperty("position", "relative", "");
+ pageContainer.style.setProperty("top", "-" + _scrollTop + "px", "");
} else {
- pageContainer.style.setProperty('margin-top', '-' + _scrollTop + 'px', '');
+ pageContainer.style.setProperty("margin-top", "-" + _scrollTop + "px", "");
}
- document.documentElement.classList.add('disableScrolling');
+ document.documentElement.classList.add("disableScrolling");
}
_scrollDisableCounter++;
_scrollDisableCounter--;
if (_scrollDisableCounter === 0) {
- document.documentElement.classList.remove('disableScrolling');
+ document.documentElement.classList.remove("disableScrolling");
- const pageContainer = document.getElementById('pageContainer')!;
- if (Environment.platform() === 'ios') {
- pageContainer.style.removeProperty('position');
- pageContainer.style.removeProperty('top');
+ const pageContainer = document.getElementById("pageContainer")!;
+ if (Environment.platform() === "ios") {
+ pageContainer.style.removeProperty("position");
+ pageContainer.style.removeProperty("top");
} else {
- pageContainer.style.removeProperty('margin-top');
+ pageContainer.style.removeProperty("margin-top");
}
if (_scrollTop) {
*/
export function pageOverlayOpen(): void {
if (_pageOverlayCounter === 0) {
- document.documentElement.classList.add('pageOverlayActive');
+ document.documentElement.classList.add("pageOverlayActive");
}
_pageOverlayCounter++;
_pageOverlayCounter--;
if (_pageOverlayCounter === 0) {
- document.documentElement.classList.remove('pageOverlayActive');
+ document.documentElement.classList.remove("pageOverlayActive");
}
}
}
}
function _getQueryObject(query: string): MediaQueryData {
- if (typeof (query as any) !== 'string' || query.trim() === '') {
- throw new TypeError('Expected a non-empty string for parameter \'query\'.');
+ if (typeof (query as any) !== "string" || query.trim() === "") {
+ throw new TypeError("Expected a non-empty string for parameter 'query'.");
}
// Microsoft Edge rewrites the media queries to whatever it
callbacksMatch: Map<string, Callback>;
callbacksSetup: Map<string, Callback>;
callbacksUnmatch: Map<string, Callback>;
- mql: MediaQueryList
+ mql: MediaQueryList;
}
* @module Ui/Scroll (alias)
* @module WoltLabSuite/Core/Ui/Scroll
*/
-import DomUtil from '../Dom/Util';
+import DomUtil from "../Dom/Util";
type Callback = () => void;
_callback();
}
- window.removeEventListener('scroll', onScroll);
+ window.removeEventListener("scroll", onScroll);
_callback = null;
_timeoutScroll = null;
}, 100);
export function element(element: HTMLElement, callback?: Callback): void {
if (!(element instanceof HTMLElement)) {
throw new TypeError("Expected a valid DOM element.");
- } else if (callback !== undefined && typeof callback !== 'function') {
+ } else if (callback !== undefined && typeof callback !== "function") {
throw new TypeError("Expected a valid callback function.");
} else if (!document.body.contains(element)) {
throw new Error("Element must be part of the visible DOM.");
if (callback) {
_callback = callback;
- window.addEventListener('scroll', onScroll);
+ window.addEventListener("scroll", onScroll);
}
let y = DomUtil.offset(element).top;
if (_offset === null) {
_offset = 50;
- const pageHeader = document.getElementById('pageHeaderPanel');
+ const pageHeader = document.getElementById("pageHeaderPanel");
if (pageHeader !== null) {
const position = window.getComputedStyle(pageHeader).position;
- if (position === 'fixed' || position === 'static') {
+ if (position === "fixed" || position === "static") {
_offset = pageHeader.offsetHeight;
} else {
_offset = 0;
window.scrollTo({
left: 0,
top: y,
- behavior: 'smooth',
+ behavior: "smooth",
});
window.setTimeout(() => {
-import { DatabaseObjectActionPayload } from '../../Ajax/Data';
+import { DatabaseObjectActionPayload } from "../../Ajax/Data";
-export type CallbackDropdownInit = (list: HTMLUListElement) => void
+export type CallbackDropdownInit = (list: HTMLUListElement) => void;
-export type CallbackSelect = (item: HTMLElement) => boolean
+export type CallbackSelect = (item: HTMLElement) => boolean;
export interface SearchInputOptions {
ajax?: Partial<DatabaseObjectActionPayload>;
* @module WoltLabSuite/Core/Ui/Search/Input
*/
-import * as Ajax from '../../Ajax';
-import * as Core from '../../Core';
-import DomUtil from '../../Dom/Util';
-import UiDropdownSimple from '../Dropdown/Simple';
-import { DatabaseObjectActionPayload, DatabaseObjectActionResponse } from '../../Ajax/Data';
-import AjaxRequest from '../../Ajax/Request';
-import { CallbackDropdownInit, CallbackSelect, SearchInputOptions } from './Data';
+import * as Ajax from "../../Ajax";
+import * as Core from "../../Core";
+import DomUtil from "../../Dom/Util";
+import UiDropdownSimple from "../Dropdown/Simple";
+import { DatabaseObjectActionPayload, DatabaseObjectActionResponse } from "../../Ajax/Data";
+import AjaxRequest from "../../Ajax/Request";
+import { CallbackDropdownInit, CallbackSelect, SearchInputOptions } from "./Data";
class UiSearchInput {
private activeItem?: HTMLLIElement = undefined;
private readonly callbackDropdownInit?: CallbackDropdownInit = undefined;
private readonly callbackSelect?: CallbackSelect = undefined;
private readonly delay: number;
- private dropdownContainerId = '';
+ private dropdownContainerId = "";
private readonly element: HTMLInputElement;
private readonly excludedSearchValues = new Set<string>();
private list?: HTMLUListElement = undefined;
- private lastValue = '';
+ private lastValue = "";
private readonly minLength: number;
private readonly noResultPlaceholder: string;
private readonly preventSubmit: boolean;
this.element = element;
if (!(this.element instanceof HTMLInputElement)) {
throw new TypeError("Expected a valid DOM element.");
- } else if (this.element.nodeName !== 'INPUT' || (this.element.type !== 'search' && this.element.type !== 'text')) {
+ } else if (this.element.nodeName !== "INPUT" || (this.element.type !== "search" && this.element.type !== "text")) {
throw new Error('Expected an input[type="text"].');
}
- options = Core.extend({
- ajax: {
- actionName: 'getSearchResultList',
- className: '',
- interfaceName: 'wcf\\data\\ISearchAction',
+ options = Core.extend(
+ {
+ ajax: {
+ actionName: "getSearchResultList",
+ className: "",
+ interfaceName: "wcf\\data\\ISearchAction",
+ },
+ autoFocus: true,
+ callbackDropdownInit: undefined,
+ callbackSelect: undefined,
+ delay: 500,
+ excludedSearchValues: [],
+ minLength: 3,
+ noResultPlaceholder: "",
+ preventSubmit: false,
},
- autoFocus: true,
- callbackDropdownInit: undefined,
- callbackSelect: undefined,
- delay: 500,
- excludedSearchValues: [],
- minLength: 3,
- noResultPlaceholder: '',
- preventSubmit: false,
- }, options) as SearchInputOptions;
+ options
+ ) as SearchInputOptions;
this.ajaxPayload = options.ajax as DatabaseObjectActionPayload;
this.autoFocus = options.autoFocus!;
this.callbackDropdownInit = options.callbackDropdownInit;
this.callbackSelect = options.callbackSelect;
this.delay = options.delay!;
- options.excludedSearchValues!.forEach(value => {
+ options.excludedSearchValues!.forEach((value) => {
this.addExcludedSearchValues(value);
});
this.minLength = options.minLength!;
this.preventSubmit = options.preventSubmit!;
// Disable auto-complete because it collides with the suggestion dropdown.
- this.element.autocomplete = 'off';
+ this.element.autocomplete = "off";
- this.element.addEventListener('keydown', (ev) => this.keydown(ev));
- this.element.addEventListener('keyup', (ev) => this.keyup(ev));
+ this.element.addEventListener("keydown", (ev) => this.keydown(ev));
+ this.element.addEventListener("keyup", (ev) => this.keyup(ev));
}
/**
*/
private keydown(event: KeyboardEvent): void {
if ((this.activeItem !== null && UiDropdownSimple.isOpen(this.dropdownContainerId)) || this.preventSubmit) {
- if (event.key === 'Enter') {
+ if (event.key === "Enter") {
event.preventDefault();
}
}
- if (['ArrowUp', 'ArrowDown', 'Escape'].includes(event.key)) {
+ if (["ArrowUp", "ArrowDown", "Escape"].includes(event.key)) {
event.preventDefault();
}
}
// handle dropdown keyboard navigation
if (this.activeItem !== null || !this.autoFocus) {
if (UiDropdownSimple.isOpen(this.dropdownContainerId)) {
- if (event.key === 'ArrowUp') {
+ if (event.key === "ArrowUp") {
event.preventDefault();
return this.keyboardPreviousItem();
- } else if (event.key === 'ArrowDown') {
+ } else if (event.key === "ArrowDown") {
event.preventDefault();
return this.keyboardNextItem();
- } else if (event.key === 'Enter') {
+ } else if (event.key === "Enter") {
event.preventDefault();
return this.keyboardSelectItem();
}
// close list on escape
- if (event.key === 'Escape') {
+ if (event.key === "Escape") {
UiDropdownSimple.close(this.dropdownContainerId);
return;
let nextItem: HTMLLIElement | undefined = undefined;
if (this.activeItem) {
- this.activeItem.classList.remove('active');
+ this.activeItem.classList.remove("active");
if (this.activeItem.nextElementSibling) {
nextItem = this.activeItem.nextElementSibling as HTMLLIElement;
}
}
- this.activeItem = nextItem || this.list!.children[0] as HTMLLIElement;
- this.activeItem.classList.add('active');
+ this.activeItem = nextItem || (this.list!.children[0] as HTMLLIElement);
+ this.activeItem.classList.add("active");
}
/**
let nextItem: HTMLLIElement | undefined = undefined;
if (this.activeItem) {
- this.activeItem.classList.remove('active');
+ this.activeItem.classList.remove("active");
if (this.activeItem.previousElementSibling) {
nextItem = this.activeItem.previousElementSibling as HTMLLIElement;
}
}
- this.activeItem = nextItem || this.list!.children[this.list!.childElementCount - 1] as HTMLLIElement;
- this.activeItem.classList.add('active');
+ this.activeItem = nextItem || (this.list!.children[this.list!.childElementCount - 1] as HTMLLIElement);
+ this.activeItem.classList.add("active");
}
/**
*/
private selectItem(item: HTMLLIElement): void {
if (this.callbackSelect && !this.callbackSelect(item)) {
- this.element.value = '';
+ this.element.value = "";
} else {
- this.element.value = item.dataset.label || '';
+ this.element.value = item.dataset.label || "";
}
this.activeItem = undefined;
_ajaxSuccess(data: DatabaseObjectActionResponse): void {
let createdList = false;
if (!this.list) {
- this.list = document.createElement('ul');
- this.list.className = 'dropdownMenu';
+ this.list = document.createElement("ul");
+ this.list.className = "dropdownMenu";
createdList = true;
- if (typeof this.callbackDropdownInit === 'function') {
+ if (typeof this.callbackDropdownInit === "function") {
this.callbackDropdownInit(this.list);
}
} else {
// reset current list
- this.list.innerHTML = '';
+ this.list.innerHTML = "";
}
- if (typeof data.returnValues === 'object') {
+ if (typeof data.returnValues === "object") {
const callbackClick = this.clickSelectItem.bind(this);
let listItem;
- Object.keys(data.returnValues).forEach(key => {
+ Object.keys(data.returnValues).forEach((key) => {
listItem = this.createListItem(data.returnValues[key]);
- listItem.addEventListener('click', callbackClick);
+ listItem.addEventListener("click", callbackClick);
this.list!.appendChild(listItem);
});
}
UiDropdownSimple.open(this.dropdownContainerId, true);
// mark first item as active
- const firstChild = this.list.childElementCount ? this.list.children[0] as HTMLLIElement : undefined;
- if (this.autoFocus && firstChild && ~~(firstChild.dataset.objectId || '')) {
+ const firstChild = this.list.childElementCount ? (this.list.children[0] as HTMLLIElement) : undefined;
+ if (this.autoFocus && firstChild && ~~(firstChild.dataset.objectId || "")) {
this.activeItem = firstChild;
- this.activeItem.classList.add('active');
+ this.activeItem.classList.add("active");
}
}
}
return false;
}
- const listItem = document.createElement('li');
- listItem.className = 'dropdownText';
+ const listItem = document.createElement("li");
+ listItem.className = "dropdownText";
- const span = document.createElement('span');
+ const span = document.createElement("span");
span.textContent = this.noResultPlaceholder;
listItem.appendChild(span);
* Creates an list item from response data.
*/
protected createListItem(item: ListItemData): HTMLLIElement {
- const listItem = document.createElement('li');
+ const listItem = document.createElement("li");
listItem.dataset.objectId = item.objectID.toString();
listItem.dataset.label = item.label;
- const span = document.createElement('span');
+ const span = document.createElement("span");
span.textContent = item.label;
listItem.appendChild(span);
}
}
-export = UiSearchInput
+export = UiSearchInput;
interface ListItemData {
label: string;
-import * as Core from '../../Core';
-import * as DomTraverse from '../../Dom/Traverse';
-import DomUtil from '../../Dom/Util';
-import UiDropdownSimple from '../Dropdown/Simple';
-import * as UiScreen from '../Screen';
-import UiSearchInput from './Input';
+import * as Core from "../../Core";
+import * as DomTraverse from "../../Dom/Traverse";
+import DomUtil from "../../Dom/Util";
+import UiDropdownSimple from "../Dropdown/Simple";
+import * as UiScreen from "../Screen";
+import UiSearchInput from "./Input";
function click(event: MouseEvent): void {
event.preventDefault();
- const pageHeader = document.getElementById('pageHeader') as HTMLElement;
- pageHeader.classList.add('searchBarForceOpen');
+ const pageHeader = document.getElementById("pageHeader") as HTMLElement;
+ pageHeader.classList.add("searchBarForceOpen");
window.setTimeout(() => {
- pageHeader.classList.remove('searchBarForceOpen');
+ pageHeader.classList.remove("searchBarForceOpen");
}, 10);
const target = event.currentTarget as HTMLElement;
const objectType = target.dataset.objectType;
- const container = document.getElementById('pageHeaderSearchParameters') as HTMLElement;
- container.innerHTML = '';
+ const container = document.getElementById("pageHeaderSearchParameters") as HTMLElement;
+ container.innerHTML = "";
const extendedLink = target.dataset.extendedLink;
if (extendedLink) {
- const link = document.querySelector('.pageHeaderSearchExtendedLink') as HTMLAnchorElement;
+ const link = document.querySelector(".pageHeaderSearchExtendedLink") as HTMLAnchorElement;
link.href = extendedLink;
}
const parameters = new Map<string, string>();
try {
- const data = JSON.parse(target.dataset.parameters || '');
+ const data = JSON.parse(target.dataset.parameters || "");
if (Core.isPlainObject(data)) {
- Object.keys(data).forEach(key => {
+ Object.keys(data).forEach((key) => {
parameters.set(key, data[key]);
});
}
- } catch (e) {
- }
+ } catch (e) {}
if (objectType) {
- parameters.set('types[]', objectType);
+ parameters.set("types[]", objectType);
}
parameters.forEach((value, key) => {
- const input = document.createElement('input');
- input.type = 'hidden';
+ const input = document.createElement("input");
+ input.type = "hidden";
input.name = key;
input.value = value;
container.appendChild(input);
});
// update label
- const inputContainer = document.getElementById('pageHeaderSearchInputContainer') as HTMLElement;
- const button = inputContainer.querySelector('.pageHeaderSearchType > .button > .pageHeaderSearchTypeLabel') as HTMLElement;
+ const inputContainer = document.getElementById("pageHeaderSearchInputContainer") as HTMLElement;
+ const button = inputContainer.querySelector(
+ ".pageHeaderSearchType > .button > .pageHeaderSearchTypeLabel"
+ ) as HTMLElement;
button.textContent = target.textContent;
}
export function init(objectType: string): void {
- const searchInput = document.getElementById('pageHeaderSearchInput') as HTMLInputElement;
+ const searchInput = document.getElementById("pageHeaderSearchInput") as HTMLInputElement;
new UiSearchInput(searchInput, {
ajax: {
- className: 'wcf\\data\\search\\keyword\\SearchKeywordAction',
+ className: "wcf\\data\\search\\keyword\\SearchKeywordAction",
},
autoFocus: false,
callbackDropdownInit(dropdownMenu) {
- dropdownMenu.classList.add('dropdownMenuPageSearch');
+ dropdownMenu.classList.add("dropdownMenuPageSearch");
- if (UiScreen.is('screen-lg')) {
- dropdownMenu.dataset.dropdownAlignmentHorizontal = 'right';
+ if (UiScreen.is("screen-lg")) {
+ dropdownMenu.dataset.dropdownAlignmentHorizontal = "right";
const minWidth = searchInput.clientWidth;
- dropdownMenu.style.setProperty('min-width', minWidth + 'px', '');
+ dropdownMenu.style.setProperty("min-width", minWidth + "px", "");
// calculate offset to ignore the width caused by the submit button
const parent = searchInput.parentElement!;
- const offsetRight = (DomUtil.offset(parent).left + parent.clientWidth) - (DomUtil.offset(searchInput).left + minWidth);
- const offsetTop = DomUtil.styleAsInt(window.getComputedStyle(parent), 'padding-bottom');
- dropdownMenu.style.setProperty('transform', 'translateX(-' + Math.ceil(offsetRight) + 'px) translateY(-' + offsetTop + 'px)', '');
+ const offsetRight =
+ DomUtil.offset(parent).left + parent.clientWidth - (DomUtil.offset(searchInput).left + minWidth);
+ const offsetTop = DomUtil.styleAsInt(window.getComputedStyle(parent), "padding-bottom");
+ dropdownMenu.style.setProperty(
+ "transform",
+ "translateX(-" + Math.ceil(offsetRight) + "px) translateY(-" + offsetTop + "px)",
+ ""
+ );
}
},
callbackSelect() {
setTimeout(() => {
- const form = DomTraverse.parentByTag(searchInput, 'FORM') as HTMLFormElement;
+ const form = DomTraverse.parentByTag(searchInput, "FORM") as HTMLFormElement;
form.submit();
}, 1);
},
});
- const searchType = document.querySelector('.pageHeaderSearchType') as HTMLElement;
+ const searchType = document.querySelector(".pageHeaderSearchType") as HTMLElement;
const dropdownMenu = UiDropdownSimple.getDropdownMenu(DomUtil.identify(searchType))!;
- dropdownMenu.querySelectorAll('a[data-object-type]').forEach(link => {
- link.addEventListener('click', click);
+ dropdownMenu.querySelectorAll("a[data-object-type]").forEach((link) => {
+ link.addEventListener("click", click);
});
// trigger click on init
const link = dropdownMenu.querySelector('a[data-object-type="' + objectType + '"]') as HTMLAnchorElement;
link.click();
}
-
-
* @module WoltLabSuite/Core/Ui/Smiley/Insert
*/
-import * as EventHandler from '../../Event/Handler';
+import * as EventHandler from "../../Event/Handler";
class UiSmileyInsert {
private readonly container: HTMLElement;
constructor(editorId: string) {
this.editorId = editorId;
- let container = document.getElementById('smilies-' + this.editorId);
+ let container = document.getElementById("smilies-" + this.editorId);
if (!container) {
// form builder
- container = document.getElementById(this.editorId + 'SmiliesTabContainer');
+ container = document.getElementById(this.editorId + "SmiliesTabContainer");
if (!container) {
- throw new Error('Unable to find the message tab menu container containing the smilies.');
+ throw new Error("Unable to find the message tab menu container containing the smilies.");
}
}
this.container = container;
- this.container.addEventListener('keydown', (ev) => this.keydown(ev));
- this.container.addEventListener('mousedown', (ev) => this.mousedown(ev));
+ this.container.addEventListener("keydown", (ev) => this.keydown(ev));
+ this.container.addEventListener("mousedown", (ev) => this.mousedown(ev));
}
keydown(event: KeyboardEvent): void {
const activeButton = document.activeElement as HTMLAnchorElement;
- if (!activeButton.classList.contains('jsSmiley')) {
+ if (!activeButton.classList.contains("jsSmiley")) {
return;
}
- if (['ArrowLeft', 'ArrowRight', 'End', 'Home'].includes(event.key)) {
+ if (["ArrowLeft", "ArrowRight", "End", "Home"].includes(event.key)) {
event.preventDefault();
const target = event.currentTarget as HTMLAnchorElement;
- const smilies: HTMLAnchorElement[] = Array.from(target.querySelectorAll('.jsSmiley'));
- if (event.key === 'ArrowLeft') {
+ const smilies: HTMLAnchorElement[] = Array.from(target.querySelectorAll(".jsSmiley"));
+ if (event.key === "ArrowLeft") {
smilies.reverse();
}
let index = smilies.indexOf(activeButton);
- if (event.key === 'Home') {
+ if (event.key === "Home") {
index = 0;
- } else if (event.key === 'End') {
+ } else if (event.key === "End") {
index = smilies.length - 1;
} else {
index = index + 1;
}
smilies[index].focus();
- } else if (event.key === 'Enter' || event.key === 'Space') {
+ } else if (event.key === "Enter" || event.key === "Space") {
event.preventDefault();
- const image = activeButton.querySelector('img') as HTMLImageElement;
+ const image = activeButton.querySelector("img") as HTMLImageElement;
this.insert(image);
}
}
const target = event.target as HTMLElement;
// Clicks may occur on a few different elements, but we are only looking for the image.
- const listItem = target.closest('li');
+ const listItem = target.closest("li");
if (listItem && this.container.contains(listItem)) {
event.preventDefault();
- const img = listItem.querySelector('img');
+ const img = listItem.querySelector("img");
if (img) {
this.insert(img);
}
}
insert(img: HTMLImageElement): void {
- EventHandler.fire('com.woltlab.wcf.redactor2', 'insertSmiley_' + this.editorId, {
+ EventHandler.fire("com.woltlab.wcf.redactor2", "insertSmiley_" + this.editorId, {
img,
});
}
}
-export = UiSmileyInsert
+export = UiSmileyInsert;
* @module WoltLabSuite/Core/Ui/Suggestion
*/
-import * as Ajax from '../Ajax';
-import * as Core from '../Core';
+import * as Ajax from "../Ajax";
+import * as Core from "../Core";
import {
AjaxCallbackObject,
DatabaseObjectActionPayload,
DatabaseObjectActionResponse,
RequestPayload,
-} from '../Ajax/Data';
-import UiDropdownSimple from './Dropdown/Simple';
+} from "../Ajax/Data";
+import UiDropdownSimple from "./Dropdown/Simple";
class UiSuggestion implements AjaxCallbackObject {
private readonly ajaxPayload: DatabaseObjectActionPayload;
private readonly excludedSearchValues: Set<string>;
private readonly element: HTMLElement;
private readonly threshold: number;
- private value = '';
+ private value = "";
/**
* Initializes a new suggestion input.
this.element = element;
- this.ajaxPayload = Core.extend({
- actionName: 'getSearchResultList',
- className: '',
- interfaceName: 'wcf\\data\\ISearchAction',
- parameters: {
- data: {},
+ this.ajaxPayload = Core.extend(
+ {
+ actionName: "getSearchResultList",
+ className: "",
+ interfaceName: "wcf\\data\\ISearchAction",
+ parameters: {
+ data: {},
+ },
},
- }, options.ajax) as DatabaseObjectActionPayload;
+ options.ajax
+ ) as DatabaseObjectActionPayload;
- if (typeof options.callbackSelect !== 'function') {
+ if (typeof options.callbackSelect !== "function") {
throw new Error("Expected a valid callback for option 'callbackSelect'.");
}
this.callbackSelect = options.callbackSelect;
- this.excludedSearchValues = new Set(Array.isArray(options.excludedSearchValues) ? options.excludedSearchValues : []);
+ this.excludedSearchValues = new Set(
+ Array.isArray(options.excludedSearchValues) ? options.excludedSearchValues : []
+ );
this.threshold = options.threshold === undefined ? 3 : options.threshold;
- this.element.addEventListener('click', (ev) => ev.preventDefault());
- this.element.addEventListener('keydown', (ev) => this.keyDown(ev));
- this.element.addEventListener('keyup', (ev) => this.keyUp(ev));
+ this.element.addEventListener("click", (ev) => ev.preventDefault());
+ this.element.addEventListener("keydown", (ev) => this.keyDown(ev));
+ this.element.addEventListener("keyup", (ev) => this.keyUp(ev));
}
/**
return true;
}
- if (['ArrowDown', 'ArrowUp', 'Enter', 'Escape'].indexOf(event.key) === -1) {
+ if (["ArrowDown", "ArrowUp", "Enter", "Escape"].indexOf(event.key) === -1) {
return true;
}
let active!: HTMLElement;
- let i = 0, length = this.dropdownMenu!.childElementCount;
+ let i = 0,
+ length = this.dropdownMenu!.childElementCount;
while (i < length) {
active = this.dropdownMenu!.children[i] as HTMLElement;
- if (active.classList.contains('active')) {
+ if (active.classList.contains("active")) {
break;
}
i++;
}
- if (event.key === 'Enter') {
+ if (event.key === "Enter") {
UiDropdownSimple.close(this.element.id);
this.select(undefined, active);
- } else if (event.key === 'Escape') {
+ } else if (event.key === "Escape") {
if (UiDropdownSimple.isOpen(this.element.id)) {
UiDropdownSimple.close(this.element.id);
} else {
}
} else {
let index = 0;
- if (event.key === 'ArrowUp') {
- index = ((i === 0) ? length : i) - 1;
- } else if (event.key === 'ArrowDown') {
+ if (event.key === "ArrowUp") {
+ index = (i === 0 ? length : i) - 1;
+ } else if (event.key === "ArrowDown") {
index = i + 1;
- if (index === length)
- index = 0;
+ if (index === length) index = 0;
}
if (index !== i) {
- active.classList.remove('active');
- this.dropdownMenu!.children[index].classList.add('active');
+ active.classList.remove("active");
+ this.dropdownMenu!.children[index].classList.add("active");
}
}
const anchor = item!.children[0] as HTMLElement;
this.callbackSelect(this.element.id, {
objectId: +(anchor.dataset.objectId || 0),
- value: item!.textContent || '',
- type: anchor.dataset.type || '',
+ value: item!.textContent || "",
+ type: anchor.dataset.type || "",
});
if (event instanceof MouseEvent) {
*/
_ajaxSuccess(data: DatabaseObjectActionResponse): void {
if (this.dropdownMenu === null) {
- this.dropdownMenu = document.createElement('div');
- this.dropdownMenu.className = 'dropdownMenu';
+ this.dropdownMenu = document.createElement("div");
+ this.dropdownMenu.className = "dropdownMenu";
UiDropdownSimple.initFragment(this.element, this.dropdownMenu);
} else {
- this.dropdownMenu.innerHTML = '';
+ this.dropdownMenu.innerHTML = "";
}
if (Array.isArray(data.returnValues)) {
data.returnValues.forEach((item, index) => {
- const anchor = document.createElement('a');
+ const anchor = document.createElement("a");
if (item.icon) {
- anchor.className = 'box16';
- anchor.innerHTML = item.icon + ' <span></span>';
+ anchor.className = "box16";
+ anchor.innerHTML = item.icon + " <span></span>";
anchor.children[1].textContent = item.label;
} else {
anchor.textContent = item.label;
if (item.type) {
anchor.dataset.type = item.type;
}
- anchor.addEventListener('click', (ev) => this.select(ev));
+ anchor.addEventListener("click", (ev) => this.select(ev));
- const listItem = document.createElement('li');
+ const listItem = document.createElement("li");
if (index === 0) {
- listItem.className = 'active';
+ listItem.className = "active";
}
listItem.appendChild(anchor);
this.dropdownMenu!.appendChild(listItem);
}
}
-export = UiSuggestion
+export = UiSuggestion;
interface CallbackSelectData {
objectId: number;
* @module WoltLabSuite/Core/Ui/TabMenu
*/
-import DomChangeListener from '../Dom/Change/Listener';
-import DomUtil from '../Dom/Util';
-import TabMenuSimple from './TabMenu/Simple';
-import UiCloseOverlay from './CloseOverlay';
-import * as UiScreen from './Screen';
-import * as UiScroll from './Scroll';
+import DomChangeListener from "../Dom/Change/Listener";
+import DomUtil from "../Dom/Util";
+import TabMenuSimple from "./TabMenu/Simple";
+import UiCloseOverlay from "./CloseOverlay";
+import * as UiScreen from "./Screen";
+import * as UiScroll from "./Scroll";
let _activeList: HTMLUListElement | null = null;
let _enableTabScroll = false;
* Initializes available tab menus.
*/
function init() {
- document.querySelectorAll('.tabMenuContainer:not(.staticTabMenuContainer)').forEach(container => {
+ document.querySelectorAll(".tabMenuContainer:not(.staticTabMenuContainer)").forEach((container) => {
const containerId = DomUtil.identify(container);
if (_tabMenus.has(containerId)) {
return;
}
}
- const list = document.querySelector('#' + containerId + ' > nav > ul') as HTMLUListElement;
- list.addEventListener('click', event => {
+ const list = document.querySelector("#" + containerId + " > nav > ul") as HTMLUListElement;
+ list.addEventListener("click", (event) => {
event.preventDefault();
event.stopPropagation();
if (event.target === list) {
- list.classList.add('active');
+ list.classList.add("active");
_activeList = list;
} else {
- list.classList.remove('active');
+ list.classList.remove("active");
_activeList = null;
}
});
// bind scroll listener
- container.querySelectorAll('.tabMenu, .menu').forEach(menu => {
+ container.querySelectorAll(".tabMenu, .menu").forEach((menu) => {
function callback() {
timeout = null;
}
let timeout: number | null = null;
- menu.querySelector('ul')!.addEventListener('scroll', () => {
- if (timeout !== null) {
- window.clearTimeout(timeout);
- }
+ menu.querySelector("ul")!.addEventListener(
+ "scroll",
+ () => {
+ if (timeout !== null) {
+ window.clearTimeout(timeout);
+ }
- // slight delay to avoid calling this function too often
- timeout = window.setTimeout(callback, 10);
- }, {passive: true});
+ // slight delay to avoid calling this function too often
+ timeout = window.setTimeout(callback, 10);
+ },
+ { passive: true }
+ );
});
// The validation of input fields, e.g. [required], yields strange results when
// to not work and a warning is displayed on the console. We can work around this
// by manually checking if the input fields validate on submit and display the
// parent tab ourselves.
- const form = container.closest('form');
+ const form = container.closest("form");
if (form !== null) {
const submitButton = form.querySelector('input[type="submit"]');
if (submitButton !== null) {
- submitButton.addEventListener('click', event => {
+ submitButton.addEventListener("click", (event) => {
if (event.defaultPrevented) {
return;
}
- container.querySelectorAll('input, select').forEach((element: HTMLInputElement | HTMLSelectElement) => {
+ container.querySelectorAll("input, select").forEach((element: HTMLInputElement | HTMLSelectElement) => {
if (!element.checkValidity()) {
event.preventDefault();
// Select the tab that contains the erroneous element.
- const tabMenu = getTabMenu(element.closest('.tabMenuContainer')!.id)!;
- const tabMenuContent = element.closest('.tabMenuContent') as HTMLElement;
- tabMenu.select(tabMenuContent.dataset.name || '');
+ const tabMenu = getTabMenu(element.closest(".tabMenuContainer")!.id)!;
+ const tabMenuContent = element.closest(".tabMenuContent") as HTMLElement;
+ tabMenu.select(tabMenuContent.dataset.name || "");
UiScroll.element(element, () => {
element.reportValidity();
});
* Selects the first tab containing an element with class `formError`.
*/
function selectErroneousTabs(): void {
- _tabMenus.forEach(tabMenu => {
+ _tabMenus.forEach((tabMenu) => {
let foundError = false;
- tabMenu.getContainers().forEach(container => {
- if (!foundError && container.querySelector('.formError') !== null) {
+ tabMenu.getContainers().forEach((container) => {
+ if (!foundError && container.querySelector(".formError") !== null) {
foundError = true;
tabMenu.select(container.id);
}
function scrollEnable(isSetup) {
_enableTabScroll = true;
- _tabMenus.forEach(tabMenu => {
+ _tabMenus.forEach((tabMenu) => {
const activeTab = tabMenu.getActiveTab();
if (isSetup) {
- rebuildMenuOverflow(activeTab.closest('.menu, .tabMenu'));
+ rebuildMenuOverflow(activeTab.closest(".menu, .tabMenu"));
} else {
scrollToTab(activeTab);
}
return;
}
- list.classList.add('enableAnimation');
+ list.classList.add("enableAnimation");
// new value is larger, we're scrolling towards the end
if (scrollLeft < left) {
- list.firstElementChild.style.setProperty('margin-left', (scrollLeft - left) + 'px', '');
+ list.firstElementChild.style.setProperty("margin-left", scrollLeft - left + "px", "");
} else {
// new value is smaller, we're scrolling towards the start
- list.style.setProperty('padding-left', (scrollLeft - left) + 'px', '');
+ list.style.setProperty("padding-left", scrollLeft - left + "px", "");
}
setTimeout(() => {
- list.classList.remove('enableAnimation');
- list.firstElementChild.style.removeProperty('margin-left');
- list.style.removeProperty('padding-left');
+ list.classList.remove("enableAnimation");
+ list.firstElementChild.style.removeProperty("margin-left");
+ list.style.removeProperty("padding-left");
list.scrollLeft = left;
}, 300);
}
}
const width = menu.clientWidth;
- const list = menu.querySelector('ul') as HTMLElement;
+ const list = menu.querySelector("ul") as HTMLElement;
const scrollLeft = list.scrollLeft;
const scrollWidth = list.scrollWidth;
- const overflowLeft = (scrollLeft > 0);
+ const overflowLeft = scrollLeft > 0;
- let overlayLeft = menu.querySelector('.tabMenuOverlayLeft');
+ let overlayLeft = menu.querySelector(".tabMenuOverlayLeft");
if (overflowLeft) {
if (overlayLeft === null) {
- overlayLeft = document.createElement('span');
- overlayLeft.className = 'tabMenuOverlayLeft icon icon24 fa-angle-left';
- overlayLeft.addEventListener('click', () => {
+ overlayLeft = document.createElement("span");
+ overlayLeft.className = "tabMenuOverlayLeft icon icon24 fa-angle-left";
+ overlayLeft.addEventListener("click", () => {
const listWidth = list.clientWidth;
scrollMenu(list, list.scrollLeft - ~~(listWidth / 2), list.scrollLeft, list.scrollWidth, listWidth, 0);
});
menu.insertBefore(overlayLeft, menu.firstChild);
}
- overlayLeft.classList.add('active');
+ overlayLeft.classList.add("active");
} else if (overlayLeft !== null) {
- overlayLeft.classList.remove('active');
+ overlayLeft.classList.remove("active");
}
- const overflowRight = (width + scrollLeft < scrollWidth);
- let overlayRight = menu.querySelector('.tabMenuOverlayRight');
+ const overflowRight = width + scrollLeft < scrollWidth;
+ let overlayRight = menu.querySelector(".tabMenuOverlayRight");
if (overflowRight) {
if (overlayRight === null) {
- overlayRight = document.createElement('span');
- overlayRight.className = 'tabMenuOverlayRight icon icon24 fa-angle-right';
- overlayRight.addEventListener('click', () => {
+ overlayRight = document.createElement("span");
+ overlayRight.className = "tabMenuOverlayRight icon icon24 fa-angle-right";
+ overlayRight.addEventListener("click", () => {
const listWidth = list.clientWidth;
scrollMenu(list, list.scrollLeft + ~~(listWidth / 2), list.scrollLeft, list.scrollWidth, listWidth, 0);
});
menu.appendChild(overlayRight);
}
- overlayRight.classList.add('active');
+ overlayRight.classList.add("active");
} else if (overlayRight !== null) {
- overlayRight.classList.remove('active');
+ overlayRight.classList.remove("active");
}
}
-
/**
* Sets up tab menus and binds listeners.
*/
init();
selectErroneousTabs();
- DomChangeListener.add('WoltLabSuite/Core/Ui/TabMenu', init);
- UiCloseOverlay.add('WoltLabSuite/Core/Ui/TabMenu', () => {
+ DomChangeListener.add("WoltLabSuite/Core/Ui/TabMenu", init);
+ UiCloseOverlay.add("WoltLabSuite/Core/Ui/TabMenu", () => {
if (_activeList) {
- _activeList.classList.remove('active');
+ _activeList.classList.remove("active");
_activeList = null;
}
});
- UiScreen.on('screen-sm-down', {
+ UiScreen.on("screen-sm-down", {
match() {
scrollEnable(false);
},
},
});
- window.addEventListener('hashchange', () => {
+ window.addEventListener("hashchange", () => {
const hash = TabMenuSimple.getIdentifierFromHash();
const element = hash ? document.getElementById(hash) : null;
- if (element !== null && element.classList.contains('tabMenuContent')) {
- _tabMenus.forEach(tabMenu => {
+ if (element !== null && element.classList.contains("tabMenuContent")) {
+ _tabMenus.forEach((tabMenu) => {
if (tabMenu.hasTab(hash)) {
tabMenu.select(hash);
}
window.setTimeout(() => {
// check if page was initially scrolled using a tab id
const tabMenuContent = document.getElementById(hash);
- if (tabMenuContent && tabMenuContent.classList.contains('tabMenuContent')) {
- const scrollY = (window.scrollY || window.pageYOffset);
+ if (tabMenuContent && tabMenuContent.classList.contains("tabMenuContent")) {
+ const scrollY = window.scrollY || window.pageYOffset;
if (scrollY > 0) {
const parent = tabMenuContent.parentNode as HTMLElement;
return;
}
- const list = tab.closest('ul');
+ const list = tab.closest("ul");
const width = list.clientWidth;
const scrollLeft = list.scrollLeft;
const scrollWidth = list.scrollWidth;
* @module WoltLabSuite/Core/Ui/TabMenu/Simple
*/
-import * as DomTraverse from '../../Dom/Traverse';
-import DomUtil from '../../Dom/Util';
-import * as Environment from '../../Environment';
-import * as EventHandler from '../../Event/Handler';
+import * as DomTraverse from "../../Dom/Traverse";
+import DomUtil from "../../Dom/Util";
+import * as Environment from "../../Environment";
+import * as EventHandler from "../../Event/Handler";
class TabMenuSimple {
private readonly container: HTMLElement;
* </div>
*/
validate(): boolean {
- if (!this.container.classList.contains('tabMenuContainer')) {
+ if (!this.container.classList.contains("tabMenuContainer")) {
return false;
}
- const nav = DomTraverse.childByTag(this.container, 'NAV') as HTMLElement;
+ const nav = DomTraverse.childByTag(this.container, "NAV") as HTMLElement;
if (nav === null) {
return false;
}
// get children
- const tabs = nav.querySelectorAll('li');
+ const tabs = nav.querySelectorAll("li");
if (tabs.length === 0) {
return false;
}
- DomTraverse.childrenByTag(this.container, 'DIV').forEach((container: HTMLElement) => {
+ DomTraverse.childrenByTag(this.container, "DIV").forEach((container: HTMLElement) => {
let name = container.dataset.name;
if (!name) {
name = DomUtil.identify(container);
});
const containerId = this.container.id;
- tabs.forEach(tab => {
+ tabs.forEach((tab) => {
const name = this._getTabName(tab);
if (!name) {
return;
}
if (this.tabs.has(name)) {
- throw new Error("Tab names must be unique, li[data-name='" + name + "'] (tab menu id: '" + containerId + "') exists more than once.");
+ throw new Error(
+ "Tab names must be unique, li[data-name='" +
+ name +
+ "'] (tab menu id: '" +
+ containerId +
+ "') exists more than once."
+ );
}
const container = this.containers.get(name);
if (container === undefined) {
- throw new Error("Expected content element for li[data-name='" + name + "'] (tab menu id: '" + containerId + "').");
+ throw new Error(
+ "Expected content element for li[data-name='" + name + "'] (tab menu id: '" + containerId + "')."
+ );
} else if (container.parentNode !== this.container) {
- throw new Error("Expected content element '" + name + "' (tab menu id: '" + containerId + "') to be a direct children.");
+ throw new Error(
+ "Expected content element '" + name + "' (tab menu id: '" + containerId + "') to be a direct children."
+ );
}
// check if tab holds exactly one children which is an anchor element
- if (tab.childElementCount !== 1 || tab.children[0].nodeName !== 'A') {
- throw new Error("Expected exactly one <a> as children for li[data-name='" + name + "'] (tab menu id: '" + containerId + "').");
+ if (tab.childElementCount !== 1 || tab.children[0].nodeName !== "A") {
+ throw new Error(
+ "Expected exactly one <a> as children for li[data-name='" + name + "'] (tab menu id: '" + containerId + "')."
+ );
}
this.tabs.set(name, tab);
}
if (this.isLegacy) {
- this.container.dataset.isLegacy = 'true';
+ this.container.dataset.isLegacy = "true";
this.tabs.forEach(function (tab, name) {
- tab.setAttribute('aria-controls', name);
+ tab.setAttribute("aria-controls", name);
});
}
*/
init(oldTabs?: Map<string, HTMLLIElement> | null): HTMLElement | null {
// bind listeners
- this.tabs.forEach(tab => {
- if (!oldTabs || oldTabs.get(tab.dataset.name || '') !== tab) {
+ this.tabs.forEach((tab) => {
+ if (!oldTabs || oldTabs.get(tab.dataset.name || "") !== tab) {
const firstChild = tab.children[0] as HTMLElement;
- firstChild.addEventListener('click', (ev) => this._onClick(ev));
+ firstChild.addEventListener("click", (ev) => this._onClick(ev));
// iOS 13 changed the behavior for click events after scrolling the menu. It prevents
// the synthetic mouse events like "click" from triggering for a short duration after
// a scrolling has occurred. If the user scrolls to the end of the list and immediately
// attempts to click the tab, nothing will happen. However, if the user waits for some
// time, the tap will trigger a "click" event again.
- //
+ //
// A "click" event is basically the result of a touch without any (significant) finger
// movement indicated by a "touchmove" event. This changes allows the user to scroll
// both the menu and the page normally, but still benefit from snappy reactions when
// tapping a menu item.
- if (Environment.platform() === 'ios') {
+ if (Environment.platform() === "ios") {
let isClick = false;
- firstChild.addEventListener('touchstart', () => {
+ firstChild.addEventListener("touchstart", () => {
isClick = true;
});
- firstChild.addEventListener('touchmove', () => {
+ firstChild.addEventListener("touchmove", () => {
isClick = false;
});
- firstChild.addEventListener('touchend', (event) => {
+ firstChild.addEventListener("touchend", (event) => {
if (isClick) {
isClick = false;
if (!oldTabs) {
const hash = TabMenuSimple.getIdentifierFromHash();
let selectTab: HTMLLIElement | undefined = undefined;
- if (hash !== '') {
+ if (hash !== "") {
selectTab = this.tabs.get(hash);
// check for parent tab menu
if (selectTab) {
const item = this.container.parentNode as HTMLElement;
- if (item.classList.contains('tabMenuContainer')) {
+ if (item.classList.contains("tabMenuContainer")) {
returnValue = item;
}
}
if (preselect === true) {
this.tabs.forEach(function (tab) {
- if (!selectTab && !DomUtil.isHidden(tab) && (!tab.previousElementSibling || DomUtil.isHidden(tab.previousElementSibling as HTMLElement))) {
+ if (
+ !selectTab &&
+ !DomUtil.isHidden(tab) &&
+ (!tab.previousElementSibling || DomUtil.isHidden(tab.previousElementSibling as HTMLElement))
+ ) {
selectTab = tab;
}
});
- } else if (typeof preselect === 'string' && preselect !== "false") {
+ } else if (typeof preselect === "string" && preselect !== "false") {
selectTab = this.tabs.get(preselect);
}
}
if (selectTab) {
- this.containers.forEach(container => {
- container.classList.add('hidden');
+ this.containers.forEach((container) => {
+ container.classList.add("hidden");
});
this.select(null, selectTab, true);
const store = this.container.dataset.store;
if (store) {
- const input = document.createElement('input');
- input.type = 'hidden';
+ const input = document.createElement("input");
+ input.type = "hidden";
input.name = store;
- input.value = this.getActiveTab().dataset.name || '';
+ input.value = this.getActiveTab().dataset.name || "";
this.container.appendChild(input);
* @param {boolean=} disableEvent suppress event handling
*/
select(name: number | string | null, tab?: HTMLLIElement, disableEvent?: boolean): void {
- name = (name) ? name.toString() : '';
+ name = name ? name.toString() : "";
tab = tab || this.tabs.get(name);
if (!tab) {
name = ~~name;
let i = 0;
- this.tabs.forEach(item => {
+ this.tabs.forEach((item) => {
if (i === name) {
tab = item;
}
}
}
- name = (name || tab.dataset.name || '') as string;
+ name = (name || tab.dataset.name || "") as string;
// unmark active tab
const oldTab = this.getActiveTab();
}
if (!disableEvent) {
- EventHandler.fire('com.woltlab.wcf.simpleTabMenu_' + this.container.id, 'beforeSelect', {
+ EventHandler.fire("com.woltlab.wcf.simpleTabMenu_" + this.container.id, "beforeSelect", {
tab: oldTab,
tabName: oldTabName,
});
}
- oldTab.classList.remove('active');
- oldContent = this.containers.get(oldTab.dataset.name || '')!;
- oldContent.classList.remove('active');
- oldContent.classList.add('hidden');
+ oldTab.classList.remove("active");
+ oldContent = this.containers.get(oldTab.dataset.name || "")!;
+ oldContent.classList.remove("active");
+ oldContent.classList.add("hidden");
if (this.isLegacy) {
- oldTab.classList.remove('ui-state-active');
- oldContent.classList.remove('ui-state-active');
+ oldTab.classList.remove("ui-state-active");
+ oldContent.classList.remove("ui-state-active");
}
}
- tab.classList.add('active');
+ tab.classList.add("active");
const newContent = this.containers.get(name)!;
- newContent.classList.add('active');
- newContent.classList.remove('hidden');
+ newContent.classList.add("active");
+ newContent.classList.remove("hidden");
if (this.isLegacy) {
- tab.classList.add('ui-state-active');
- newContent.classList.add('ui-state-active');
+ tab.classList.add("ui-state-active");
+ newContent.classList.add("ui-state-active");
}
if (this.store) {
}
if (!disableEvent) {
- EventHandler.fire('com.woltlab.wcf.simpleTabMenu_' + this.container.id, 'select', {
+ EventHandler.fire("com.woltlab.wcf.simpleTabMenu_" + this.container.id, "select", {
active: tab,
activeName: name,
previous: oldTab,
previousName: oldTab ? oldTab.dataset.name : null,
});
- const jQuery = (this.isLegacy && typeof window.jQuery === 'function') ? window.jQuery : null;
+ const jQuery = this.isLegacy && typeof window.jQuery === "function" ? window.jQuery : null;
if (jQuery) {
// simulate jQuery UI Tabs event
- jQuery(this.container).trigger('wcftabsbeforeactivate', {
+ jQuery(this.container).trigger("wcftabsbeforeactivate", {
newTab: jQuery(tab),
oldTab: jQuery(oldTab),
newPanel: jQuery(newContent),
});
}
- let location = window.location.href.replace(/#+[^#]*$/, '');
+ let location = window.location.href.replace(/#+[^#]*$/, "");
if (TabMenuSimple.getIdentifierFromHash() === name) {
location += window.location.hash;
} else {
- location += '#' + name;
+ location += "#" + name;
}
// update history
- window.history.replaceState(
- undefined,
- '',
- location,
- );
+ window.history.replaceState(undefined, "", location);
}
// TODO
*/
selectFirstVisible(): boolean {
let selectTab: HTMLLIElement | null = null;
- this.tabs.forEach(tab => {
+ this.tabs.forEach((tab) => {
if (!selectTab && !DomUtil.isHidden(tab)) {
selectTab = tab;
}
// handle legacy tab menus
if (!name) {
- if (tab.childElementCount === 1 && tab.children[0].nodeName === 'A') {
+ if (tab.childElementCount === 1 && tab.children[0].nodeName === "A") {
const link = tab.children[0] as HTMLAnchorElement;
if (link.href.match(/#([^#]+)$/)) {
name = RegExp.$1;
* Returns the currently active tab.
*/
getActiveTab(): HTMLLIElement {
- return document.querySelector('#' + this.container.id + ' > nav > ul > li.active') as HTMLLIElement;
+ return document.querySelector("#" + this.container.id + " > nav > ul > li.active") as HTMLLIElement;
}
/**
return RegExp.$1;
}
- return '';
- };
+ return "";
+ }
}
export = TabMenuSimple;
-
* @module WoltLabSuite/Core/Ui/Toggle/Input
*/
-import DomUtil from '../../Dom/Util';
+import DomUtil from "../../Dom/Util";
class UiToggleInput {
private readonly element: HTMLInputElement;
throw new Error("Unable to find element by selector '" + elementSelector + "'.");
}
- const type = (element.nodeName === 'INPUT') ? element.type : '';
- if (type !== 'checkbox' && type !== 'radio') {
+ const type = element.nodeName === "INPUT" ? element.type : "";
+ if (type !== "checkbox" && type !== "radio") {
throw new Error("Illegal element, expected input[type='checkbox'] or input[type='radio'].");
}
this.element = element;
- this.hide = this.getElements('hide', Array.isArray(options.hide) ? options.hide : []);
- this.hide = this.getElements('show', Array.isArray(options.show) ? options.show : []);
+ this.hide = this.getElements("hide", Array.isArray(options.hide) ? options.hide : []);
+ this.hide = this.getElements("show", Array.isArray(options.show) ? options.show : []);
- this.element.addEventListener('change', (ev) => this.change(ev));
+ this.element.addEventListener("change", (ev) => this.change(ev));
this.updateVisibility(this.show, this.element.checked);
this.updateVisibility(this.hide, !this.element.checked);
private getElements(type: string, items: ElementOrSelector[]): HTMLElement[] {
const elements: HTMLElement[] = [];
- items.forEach(item => {
+ items.forEach((item) => {
let element: HTMLElement | null = null;
- if (typeof item === 'string') {
+ if (typeof item === "string") {
element = document.querySelector(item);
if (element === null) {
throw new Error(`Unable to find an element with the selector '${item}'.`);
* Loops through the target elements and shows / hides them.
*/
private updateVisibility(elements: HTMLElement[], showElement: boolean) {
- elements.forEach(element => {
- DomUtil[showElement ? 'show' : 'hide'](element);
+ elements.forEach((element) => {
+ DomUtil[showElement ? "show" : "hide"](element);
});
}
}
* @module WoltLabSuite/Core/Ui/Tooltip
*/
-import DomChangeListener from '../Dom/Change/Listener';
-import * as Environment from '../Environment';
-import * as UiAlignment from './Alignment';
+import DomChangeListener from "../Dom/Change/Listener";
+import * as Environment from "../Environment";
+import * as UiAlignment from "./Alignment";
let _pointer: HTMLElement;
let _text: HTMLElement;
const element = event.currentTarget as HTMLElement;
let title = element.title.trim();
- if (title !== '') {
+ if (title !== "") {
element.dataset.tooltip = title;
- element.setAttribute('aria-label', title);
- element.removeAttribute('title');
+ element.setAttribute("aria-label", title);
+ element.removeAttribute("title");
}
- title = element.dataset.tooltip || '';
+ title = element.dataset.tooltip || "";
// reset tooltip position
- _tooltip.style.removeProperty('top');
- _tooltip.style.removeProperty('left');
+ _tooltip.style.removeProperty("top");
+ _tooltip.style.removeProperty("left");
// ignore empty tooltip
if (!title.length) {
- _tooltip.classList.remove('active');
+ _tooltip.classList.remove("active");
return;
} else {
- _tooltip.classList.add('active');
+ _tooltip.classList.add("active");
}
_text.textContent = title;
UiAlignment.set(_tooltip, element, {
- horizontal: 'center',
+ horizontal: "center",
verticalOffset: 4,
pointer: true,
- pointerClassNames: ['inverse'],
- vertical: 'top',
+ pointerClassNames: ["inverse"],
+ vertical: "top",
});
}
* Hides the tooltip once the mouse leaves the element.
*/
function mouseLeave(): void {
- _tooltip.classList.remove('active');
+ _tooltip.classList.remove("active");
}
/**
* Initializes the tooltip element and binds event listener.
*/
export function setup(): void {
- if (Environment.platform() !== 'desktop') {
+ if (Environment.platform() !== "desktop") {
return;
}
- _tooltip = document.createElement('div');
- _tooltip.id = 'balloonTooltip';
- _tooltip.classList.add('balloonTooltip');
- _tooltip.addEventListener('transitionend', () => {
- if (!_tooltip.classList.contains('active')) {
+ _tooltip = document.createElement("div");
+ _tooltip.id = "balloonTooltip";
+ _tooltip.classList.add("balloonTooltip");
+ _tooltip.addEventListener("transitionend", () => {
+ if (!_tooltip.classList.contains("active")) {
// reset back to the upper left corner, prevent it from staying outside
// the viewport if the body overflow was previously hidden
- ['bottom', 'left', 'right', 'top'].forEach(property => {
+ ["bottom", "left", "right", "top"].forEach((property) => {
_tooltip.style.removeProperty(property);
});
}
});
- _text = document.createElement('span');
- _text.id = 'balloonTooltipText';
+ _text = document.createElement("span");
+ _text.id = "balloonTooltipText";
_tooltip.appendChild(_text);
- _pointer = document.createElement('span');
- _pointer.classList.add('elementPointer');
- _pointer.appendChild(document.createElement('span'));
+ _pointer = document.createElement("span");
+ _pointer.classList.add("elementPointer");
+ _pointer.appendChild(document.createElement("span"));
_tooltip.appendChild(_pointer);
document.body.appendChild(_tooltip);
init();
- DomChangeListener.add('WoltLabSuite/Core/Ui/Tooltip', init);
- window.addEventListener('scroll', mouseLeave);
+ DomChangeListener.add("WoltLabSuite/Core/Ui/Tooltip", init);
+ window.addEventListener("scroll", mouseLeave);
}
/**
* Initializes tooltip elements.
*/
export function init(): void {
- document.querySelectorAll('.jsTooltip').forEach((element: HTMLElement) => {
- element.classList.remove('jsTooltip');
+ document.querySelectorAll(".jsTooltip").forEach((element: HTMLElement) => {
+ element.classList.remove("jsTooltip");
const title = element.title.trim();
if (title.length) {
element.dataset.tooltip = title;
- element.removeAttribute('title');
- element.setAttribute('aria-label', title);
+ element.removeAttribute("title");
+ element.setAttribute("aria-label", title);
- element.addEventListener('mouseenter', mouseEnter);
- element.addEventListener('mouseleave', mouseLeave);
- element.addEventListener('click', mouseLeave);
+ element.addEventListener("mouseenter", mouseEnter);
+ element.addEventListener("mouseleave", mouseLeave);
+ element.addEventListener("click", mouseLeave);
}
});
}
* @module WoltLabSuite/Core/Ui/User/Editor
*/
-import * as Ajax from '../../Ajax';
-import { AjaxCallbackObject } from '../../Ajax/Data';
-import * as Core from '../../Core';
-import { DialogCallbackObject, DialogSettings } from '../Dialog/Data';
-import DomUtil from '../../Dom/Util';
-import * as Language from '../../Language';
-import * as StringUtil from '../../StringUtil';
-import UiDialog from '../Dialog';
-import * as UiNotification from '../Notification';
+import * as Ajax from "../../Ajax";
+import { AjaxCallbackObject } from "../../Ajax/Data";
+import * as Core from "../../Core";
+import { DialogCallbackObject, DialogSettings } from "../Dialog/Data";
+import DomUtil from "../../Dom/Util";
+import * as Language from "../../Language";
+import * as StringUtil from "../../StringUtil";
+import UiDialog from "../Dialog";
+import * as UiNotification from "../Notification";
class UserEditor implements AjaxCallbackObject, DialogCallbackObject {
- private actionName = '';
+ private actionName = "";
private readonly header: HTMLElement;
constructor() {
- this.header = document.querySelector('.userProfileUser') as HTMLElement;
+ this.header = document.querySelector(".userProfileUser") as HTMLElement;
- ['ban', 'disableAvatar', 'disableCoverPhoto', 'disableSignature', 'enable'].forEach(action => {
- const button = document.querySelector('.userProfileButtonMenu .jsButtonUser' + StringUtil.ucfirst(action)) as HTMLElement;
+ ["ban", "disableAvatar", "disableCoverPhoto", "disableSignature", "enable"].forEach((action) => {
+ const button = document.querySelector(
+ ".userProfileButtonMenu .jsButtonUser" + StringUtil.ucfirst(action)
+ ) as HTMLElement;
// The button is missing if the current user lacks the permission.
if (button) {
button.dataset.action = action;
- button.addEventListener('click', (ev) => this._click(ev));
+ button.addEventListener("click", (ev) => this._click(ev));
}
});
}
event.preventDefault();
const target = event.currentTarget as HTMLElement;
- const action = target.dataset.action || '';
- let actionName = '';
+ const action = target.dataset.action || "";
+ let actionName = "";
switch (action) {
- case 'ban':
- if (Core.stringToBool(this.header.dataset.banned || '')) {
- actionName = 'unban';
+ case "ban":
+ if (Core.stringToBool(this.header.dataset.banned || "")) {
+ actionName = "unban";
}
break;
- case 'disableAvatar':
- if (Core.stringToBool(this.header.dataset.disableAvatar || '')) {
- actionName = 'enableAvatar';
+ case "disableAvatar":
+ if (Core.stringToBool(this.header.dataset.disableAvatar || "")) {
+ actionName = "enableAvatar";
}
break;
- case 'disableCoverPhoto':
- if (Core.stringToBool(this.header.dataset.disableCoverPhoto || '')) {
- actionName = 'enableCoverPhoto';
+ case "disableCoverPhoto":
+ if (Core.stringToBool(this.header.dataset.disableCoverPhoto || "")) {
+ actionName = "enableCoverPhoto";
}
break;
- case 'disableSignature':
- if (Core.stringToBool(this.header.dataset.disableSignature || '')) {
- actionName = 'enableSignature';
+ case "disableSignature":
+ if (Core.stringToBool(this.header.dataset.disableSignature || "")) {
+ actionName = "enableSignature";
}
break;
- case 'enable':
- actionName = (Core.stringToBool(this.header.dataset.isDisabled || '')) ? 'enable' : 'disable';
+ case "enable":
+ actionName = Core.stringToBool(this.header.dataset.isDisabled || "") ? "enable" : "disable";
break;
}
- if (actionName === '') {
+ if (actionName === "") {
this.actionName = action;
UiDialog.open(this);
_submit(event: Event): void {
event.preventDefault();
- const label = document.getElementById('wcfUiUserEditorExpiresLabel') as HTMLElement;
+ const label = document.getElementById("wcfUiUserEditorExpiresLabel") as HTMLElement;
- let expires = '';
- let errorMessage = '';
- const neverExpires = document.getElementById('wcfUiUserEditorNeverExpires') as HTMLInputElement;
+ let expires = "";
+ let errorMessage = "";
+ const neverExpires = document.getElementById("wcfUiUserEditorNeverExpires") as HTMLInputElement;
if (!neverExpires.checked) {
- const expireValue = document.getElementById('wcfUiUserEditorExpiresDatePicker') as HTMLInputElement;
+ const expireValue = document.getElementById("wcfUiUserEditorExpiresDatePicker") as HTMLInputElement;
expires = expireValue.value;
- if (expires === '') {
- errorMessage = Language.get('wcf.global.form.error.empty');
+ if (expires === "") {
+ errorMessage = Language.get("wcf.global.form.error.empty");
}
}
DomUtil.innerError(label, errorMessage);
const parameters = {};
- parameters[this.actionName + 'Expires'] = expires;
- const reason = document.getElementById('wcfUiUserEditorReason') as HTMLTextAreaElement;
- parameters[this.actionName + 'Reason'] = reason.value.trim();
+ parameters[this.actionName + "Expires"] = expires;
+ const reason = document.getElementById("wcfUiUserEditorReason") as HTMLTextAreaElement;
+ parameters[this.actionName + "Reason"] = reason.value.trim();
Ajax.api(this, {
actionName: this.actionName,
_ajaxSuccess(data) {
let button: HTMLElement;
switch (data.actionName) {
- case 'ban':
- case 'unban':
- this.header.dataset.banned = (data.actionName === 'ban') ? 'true' : 'false';
- button = document.querySelector('.userProfileButtonMenu .jsButtonUserBan') as HTMLElement;
- button.textContent = Language.get('wcf.user.' + (data.actionName === 'ban' ? 'unban' : 'ban'));
-
- const contentTitle = this.header.querySelector('.contentTitle') as HTMLElement;
- let banIcon = contentTitle.querySelector('.jsUserBanned') as HTMLElement;
- if (data.actionName === 'ban') {
- banIcon = document.createElement('span');
- banIcon.className = 'icon icon24 fa-lock jsUserBanned jsTooltip';
+ case "ban":
+ case "unban":
+ this.header.dataset.banned = data.actionName === "ban" ? "true" : "false";
+ button = document.querySelector(".userProfileButtonMenu .jsButtonUserBan") as HTMLElement;
+ button.textContent = Language.get("wcf.user." + (data.actionName === "ban" ? "unban" : "ban"));
+
+ const contentTitle = this.header.querySelector(".contentTitle") as HTMLElement;
+ let banIcon = contentTitle.querySelector(".jsUserBanned") as HTMLElement;
+ if (data.actionName === "ban") {
+ banIcon = document.createElement("span");
+ banIcon.className = "icon icon24 fa-lock jsUserBanned jsTooltip";
banIcon.title = data.returnValues;
contentTitle.appendChild(banIcon);
} else if (banIcon) {
}
break;
- case 'disableAvatar':
- case 'enableAvatar':
- this.header.dataset.disableAvatar = (data.actionName === 'disableAvatar') ? 'true' : 'false';
- button = document.querySelector('.userProfileButtonMenu .jsButtonUserDisableAvatar') as HTMLElement;
- button.textContent = Language.get('wcf.user.' + (data.actionName === 'disableAvatar' ? 'enable' : 'disable') + 'Avatar');
+ case "disableAvatar":
+ case "enableAvatar":
+ this.header.dataset.disableAvatar = data.actionName === "disableAvatar" ? "true" : "false";
+ button = document.querySelector(".userProfileButtonMenu .jsButtonUserDisableAvatar") as HTMLElement;
+ button.textContent = Language.get(
+ "wcf.user." + (data.actionName === "disableAvatar" ? "enable" : "disable") + "Avatar"
+ );
break;
- case 'disableCoverPhoto':
- case 'enableCoverPhoto':
- this.header.dataset.disableCoverPhoto = (data.actionName === 'disableCoverPhoto') ? 'true' : 'false';
- button = document.querySelector('.userProfileButtonMenu .jsButtonUserDisableCoverPhoto') as HTMLElement;
- button.textContent = Language.get('wcf.user.' + (data.actionName === 'disableCoverPhoto' ? 'enable' : 'disable') + 'CoverPhoto');
+ case "disableCoverPhoto":
+ case "enableCoverPhoto":
+ this.header.dataset.disableCoverPhoto = data.actionName === "disableCoverPhoto" ? "true" : "false";
+ button = document.querySelector(".userProfileButtonMenu .jsButtonUserDisableCoverPhoto") as HTMLElement;
+ button.textContent = Language.get(
+ "wcf.user." + (data.actionName === "disableCoverPhoto" ? "enable" : "disable") + "CoverPhoto"
+ );
break;
- case 'disableSignature':
- case 'enableSignature':
- this.header.dataset.disableSignature = (data.actionName === 'disableSignature') ? 'true' : 'false';
- button = document.querySelector('.userProfileButtonMenu .jsButtonUserDisableSignature') as HTMLElement;
- button.textContent = Language.get('wcf.user.' + (data.actionName === 'disableSignature' ? 'enable' : 'disable') + 'Signature');
+ case "disableSignature":
+ case "enableSignature":
+ this.header.dataset.disableSignature = data.actionName === "disableSignature" ? "true" : "false";
+ button = document.querySelector(".userProfileButtonMenu .jsButtonUserDisableSignature") as HTMLElement;
+ button.textContent = Language.get(
+ "wcf.user." + (data.actionName === "disableSignature" ? "enable" : "disable") + "Signature"
+ );
break;
- case 'enable':
- case 'disable':
- this.header.dataset.isDisabled = (data.actionName === 'disable') ? 'true' : 'false';
- button = document.querySelector('.userProfileButtonMenu .jsButtonUserEnable') as HTMLElement;
- button.textContent = Language.get('wcf.acp.user.' + (data.actionName === 'enable' ? 'disable' : 'enable'));
+ case "enable":
+ case "disable":
+ this.header.dataset.isDisabled = data.actionName === "disable" ? "true" : "false";
+ button = document.querySelector(".userProfileButtonMenu .jsButtonUserEnable") as HTMLElement;
+ button.textContent = Language.get("wcf.acp.user." + (data.actionName === "enable" ? "disable" : "enable"));
break;
}
- if (['ban', 'disableAvatar', 'disableCoverPhoto', 'disableSignature'].indexOf(data.actionName) !== -1) {
+ if (["ban", "disableAvatar", "disableCoverPhoto", "disableSignature"].indexOf(data.actionName) !== -1) {
UiDialog.close(this);
}
_ajaxSetup() {
return {
data: {
- className: 'wcf\\data\\user\\UserAction',
+ className: "wcf\\data\\user\\UserAction",
objectIDs: [+this.header.dataset.objectId!],
},
};
_dialogSetup(): DialogSettings {
return {
- id: 'wcfUiUserEditor',
+ id: "wcfUiUserEditor",
options: {
- onSetup: content => {
- const checkbox = document.getElementById('wcfUiUserEditorNeverExpires') as HTMLInputElement;
- checkbox.addEventListener('change', () => {
- const settings = document.getElementById('wcfUiUserEditorExpiresSettings') as HTMLElement;
- DomUtil[checkbox.checked ? 'hide' : 'show'](settings);
+ onSetup: (content) => {
+ const checkbox = document.getElementById("wcfUiUserEditorNeverExpires") as HTMLInputElement;
+ checkbox.addEventListener("change", () => {
+ const settings = document.getElementById("wcfUiUserEditorExpiresSettings") as HTMLElement;
+ DomUtil[checkbox.checked ? "hide" : "show"](settings);
});
- const submitButton = content.querySelector('button.buttonPrimary') as HTMLButtonElement;
- submitButton.addEventListener('click', this._submit.bind(this));
+ const submitButton = content.querySelector("button.buttonPrimary") as HTMLButtonElement;
+ submitButton.addEventListener("click", this._submit.bind(this));
},
- onShow: content => {
- UiDialog.setTitle('wcfUiUserEditor', Language.get('wcf.user.' + this.actionName + '.confirmMessage'));
+ onShow: (content) => {
+ UiDialog.setTitle("wcfUiUserEditor", Language.get("wcf.user." + this.actionName + ".confirmMessage"));
- const reason = document.getElementById('wcfUiUserEditorReason') as HTMLElement;
+ const reason = document.getElementById("wcfUiUserEditorReason") as HTMLElement;
let label = reason.nextElementSibling as HTMLElement;
- const phrase = 'wcf.user.' + this.actionName + '.reason.description';
+ const phrase = "wcf.user." + this.actionName + ".reason.description";
label.textContent = Language.get(phrase);
- window[(label.textContent === phrase) ? 'elHide' : 'elShow'](label);
+ window[label.textContent === phrase ? "elHide" : "elShow"](label);
- label = document.getElementById('wcfUiUserEditorNeverExpires')!.nextElementSibling as HTMLElement;
- label.textContent = Language.get('wcf.user.' + this.actionName + '.neverExpires');
+ label = document.getElementById("wcfUiUserEditorNeverExpires")!.nextElementSibling as HTMLElement;
+ label.textContent = Language.get("wcf.user." + this.actionName + ".neverExpires");
label = content.querySelector('label[for="wcfUiUserEditorExpires"]') as HTMLElement;
- label.textContent = Language.get('wcf.user.' + this.actionName + '.expires');
+ label.textContent = Language.get("wcf.user." + this.actionName + ".expires");
- label = document.getElementById('wcfUiUserEditorExpiresLabel') as HTMLElement;
- label.textContent = Language.get('wcf.user.' + this.actionName + '.expires.description');
+ label = document.getElementById("wcfUiUserEditorExpiresLabel") as HTMLElement;
+ label.textContent = Language.get("wcf.user." + this.actionName + ".expires.description");
},
},
source: `<div class="section">
<dl>
- <dt><label for="wcfUiUserEditorReason">${Language.get('wcf.global.reason')}</label></dt>
+ <dt><label for="wcfUiUserEditorReason">${Language.get("wcf.global.reason")}</label></dt>
<dd><textarea id="wcfUiUserEditorReason" cols="40" rows="3"></textarea><small></small></dd>
</dl>
<dl>
<dl id="wcfUiUserEditorExpiresSettings" style="display: none">
<dt><label for="wcfUiUserEditorExpires"></label></dt>
<dd>
- <input type="date" name="wcfUiUserEditorExpires" id="wcfUiUserEditorExpires" class="medium" min="${new Date(window.TIME_NOW * 1000).toISOString()}" data-ignore-timezone="true">
+ <input type="date" name="wcfUiUserEditorExpires" id="wcfUiUserEditorExpires" class="medium" min="${new Date(
+ window.TIME_NOW * 1000
+ ).toISOString()}" data-ignore-timezone="true">
<small id="wcfUiUserEditorExpiresLabel"></small>
</dd>
</dl>
</div>
<div class="formSubmit">
- <button class="buttonPrimary">${Language.get('wcf.global.button.submit')}</button>
+ <button class="buttonPrimary">${Language.get("wcf.global.button.submit")}</button>
</div>`,
};
}
* @module WoltLabSuite/Core/Ui/User/Ignore
*/
-import DomChangeListener from '../../Dom/Change/Listener';
+import DomChangeListener from "../../Dom/Change/Listener";
-const _availableMessages = document.getElementsByClassName('ignoredUserMessage');
+const _availableMessages = document.getElementsByClassName("ignoredUserMessage");
const _knownMessages = new Set<HTMLElement>();
/**
const message = _availableMessages[i] as HTMLElement;
if (!_knownMessages.has(message)) {
- message.addEventListener('click', showMessage, {once: true});
+ message.addEventListener("click", showMessage, { once: true });
_knownMessages.add(message);
}
event.preventDefault();
const message = event.currentTarget as HTMLElement;
- message.classList.remove('ignoredUserMessage');
+ message.classList.remove("ignoredUserMessage");
_knownMessages.delete(message);
// Firefox selects the entire message on click for no reason
export function init() {
rebuild();
- DomChangeListener.add('WoltLabSuite/Core/Ui/User/Ignore', rebuild);
+ DomChangeListener.add("WoltLabSuite/Core/Ui/User/Ignore", rebuild);
}
* @module WoltLabSuite/Core/Ui/User/List
*/
-import * as Ajax from '../../Ajax';
-import * as Core from '../../Core';
-import DomUtil from '../../Dom/Util';
-import UiDialog from '../Dialog';
-import UiPagination from '../Pagination';
-import { AjaxCallbackObject, DatabaseObjectActionResponse, RequestOptions } from '../../Ajax/Data';
-import { DialogCallbackObject, DialogData, DialogSettings } from '../Dialog/Data';
+import * as Ajax from "../../Ajax";
+import * as Core from "../../Core";
+import DomUtil from "../../Dom/Util";
+import UiDialog from "../Dialog";
+import UiPagination from "../Pagination";
+import { AjaxCallbackObject, DatabaseObjectActionResponse, RequestOptions } from "../../Ajax/Data";
+import { DialogCallbackObject, DialogData, DialogSettings } from "../Dialog/Data";
/**
* @constructor
* @param {object} options list of initialization options
*/
constructor(options: AjaxRequestOptions) {
- this.options = Core.extend({
- className: '',
- dialogTitle: '',
- parameters: {},
- }, options) as AjaxRequestOptions;
+ this.options = Core.extend(
+ {
+ className: "",
+ dialogTitle: "",
+ parameters: {},
+ },
+ options
+ ) as AjaxRequestOptions;
}
/**
* Shows the current or given page.
*/
private showPage(pageNo?: number): void {
- if (typeof pageNo === 'number') {
+ if (typeof pageNo === "number") {
this.pageNo = +pageNo;
}
const dialog = UiDialog.open(this, this.cache.get(this.pageNo)) as DialogData;
if (this.pageCount > 1) {
- const element = dialog.content.querySelector('.jsPagination') as HTMLElement;
+ const element = dialog.content.querySelector(".jsPagination") as HTMLElement;
if (element !== null) {
new UiPagination(element, {
activePage: this.pageNo,
_ajaxSetup(): RequestOptions {
return {
data: {
- actionName: 'getGroupedUserList',
+ actionName: "getGroupedUserList",
className: this.options.className,
- interfaceName: 'wcf\\data\\IGroupedUserListAction',
+ interfaceName: "wcf\\data\\IGroupedUserListAction",
},
};
}
}
}
-export = UiUserList
+export = UiUserList;
interface AjaxRequestOptions {
className: string;
returnValues: {
pageCount?: number;
template: string;
- }
+ };
}
* @see module:WoltLabSuite/Core/Ui/Search/Input
*/
-import * as Core from '../../../Core';
-import UiSearchInput from '../../Search/Input';
+import * as Core from "../../../Core";
+import UiSearchInput from "../../Search/Input";
class UiUserSearchInput extends UiSearchInput {
constructor(element, options) {
- const includeUserGroups = (Core.isPlainObject(options) && options.includeUserGroups === true);
-
- options = Core.extend({
- ajax: {
- className: 'wcf\\data\\user\\UserAction',
- parameters: {
- data: {
- includeUserGroups: (includeUserGroups ? 1 : 0),
+ const includeUserGroups = Core.isPlainObject(options) && options.includeUserGroups === true;
+
+ options = Core.extend(
+ {
+ ajax: {
+ className: "wcf\\data\\user\\UserAction",
+ parameters: {
+ data: {
+ includeUserGroups: includeUserGroups ? 1 : 0,
+ },
},
},
},
- }, options);
+ options
+ );
super(element, options);
}
const listItem = super.createListItem(item);
listItem.dataset.type = item.type;
- const box = document.createElement('div');
- box.className = 'box16';
- box.innerHTML = (item.type === 'group') ? '<span class="icon icon16 fa-users"></span>' : item.icon;
+ const box = document.createElement("div");
+ box.className = "box16";
+ box.innerHTML = item.type === "group" ? '<span class="icon icon16 fa-users"></span>' : item.icon;
box.appendChild(listItem.children[0]);
listItem.appendChild(box);
}
}
-export = UiUserSearchInput
+export = UiUserSearchInput;
// https://stackoverflow.com/a/50677584/782822
// This is a dirty hack, because the ListItemData cannot be exported for compatibility reasons.
* @module WoltLabSuite/Core/Ui/User/Trophy/List
*/
-import * as Ajax from '../../../Ajax';
-import { AjaxCallbackObject, DatabaseObjectActionResponse } from '../../../Ajax/Data';
-import { DialogCallbackObject, DialogData } from '../../Dialog/Data';
-import DomChangeListener from '../../../Dom/Change/Listener';
-import UiDialog from '../../Dialog';
-import UiPagination from '../../Pagination';
+import * as Ajax from "../../../Ajax";
+import { AjaxCallbackObject, DatabaseObjectActionResponse } from "../../../Ajax/Data";
+import { DialogCallbackObject, DialogData } from "../../Dialog/Data";
+import DomChangeListener from "../../../Dom/Change/Listener";
+import UiDialog from "../../Dialog";
+import UiPagination from "../../Pagination";
class CacheData {
private readonly cache = new Map<number, string>();
- constructor(readonly pageCount: number, readonly title: string) {
- }
+ constructor(readonly pageCount: number, readonly title: string) {}
has(pageNo: number): boolean {
return this.cache.has(pageNo);
* Initializes the user trophy list.
*/
constructor() {
- DomChangeListener.add('WoltLabSuite/Core/Ui/User/Trophy/List', this.rebuild.bind(this));
+ DomChangeListener.add("WoltLabSuite/Core/Ui/User/Trophy/List", this.rebuild.bind(this));
this.rebuild();
}
* Adds event userTrophyOverlayList elements.
*/
private rebuild(): void {
- document.querySelectorAll('.userTrophyOverlayList').forEach((element: HTMLElement) => {
+ document.querySelectorAll(".userTrophyOverlayList").forEach((element: HTMLElement) => {
if (!this.knownElements.has(element)) {
- element.addEventListener('click', (ev) => this.open(element, ev));
+ element.addEventListener("click", (ev) => this.open(element, ev));
this.knownElements.add(element);
}
if (data && data.has(this.currentPageNo)) {
const dialog = UiDialog.open(this, data.get(this.currentPageNo)) as DialogData;
- UiDialog.setTitle('userTrophyListOverlay', data.title);
+ UiDialog.setTitle("userTrophyListOverlay", data.title);
if (data.pageCount > 1) {
- const element = dialog.content.querySelector('.jsPagination') as HTMLElement;
+ const element = dialog.content.querySelector(".jsPagination") as HTMLElement;
if (element !== null) {
new UiPagination(element, {
activePage: this.currentPageNo,
_ajaxSetup() {
return {
data: {
- actionName: 'getGroupedUserTrophyList',
- className: 'wcf\\data\\user\\trophy\\UserTrophyAction',
+ actionName: "getGroupedUserTrophyList",
+ className: "wcf\\data\\user\\trophy\\UserTrophyAction",
},
};
}
_dialogSetup() {
return {
- id: 'userTrophyListOverlay',
+ id: "userTrophyListOverlay",
options: {
title: "",
},
}
}
-export = UiUserTrophyList
+export = UiUserTrophyList;
interface AjaxResponse extends DatabaseObjectActionResponse {
returnValues: {
pageCount?: number;
template: string;
title?: string;
- }
+ };
}
*/
class User {
- constructor(readonly userId: number, readonly username: string, readonly link: string) {
- }
+ constructor(readonly userId: number, readonly username: string, readonly link: string) {}
}
let user: User;
*/
init(userId: number, username: string, link: string): void {
if (user) {
- throw new Error('User has already been initialized.');
+ throw new Error("User has already been initialized.");
}
user = new User(userId, username, link);
get username(): string {
return user.username;
},
-}
+};