+import Devtools from './wcfsetup/install/files/ts/WoltLabSuite/Core/Devtools';
+import ColorUtil from './wcfsetup/install/files/ts/WoltLabSuite/Core/ColorUtil';
+
+declare global {
+ interface Window {
+ Devtools?: typeof Devtools;
+ WCF_PATH: string;
+
+ __wcf_bc_colorUtil: typeof ColorUtil;
+ }
+
+ interface String {
+ hashCode: () => string;
+ }
+}
* Helper functions to convert between different color formats.
*
* @author Alexander Ebert
- * @copyright 2001-2019 WoltLab GmbH
+ * @copyright 2001-2019 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module ColorUtil (alias)
+ * @module ColorUtil (alias)
* @module WoltLabSuite/Core/ColorUtil
*/
-define([], function () {
- "use strict";
-
- /**
- * @exports WoltLabSuite/Core/ColorUtil
- */
- var ColorUtil = {
- /**
- * Converts a HSV color into RGB.
- *
- * @see https://secure.wikimedia.org/wikipedia/de/wiki/HSV-Farbraum#Transformation_von_RGB_und_HSV
- *
- * @param {int} h
- * @param {int} s
- * @param {int} v
- * @return {Object}
- */
- hsvToRgb: function(h, s, v) {
- var rgb = { r: 0, g: 0, b: 0 };
- var h2, f, p, q, t;
-
- h2 = Math.floor(h / 60);
- f = h / 60 - h2;
-
- s /= 100;
- v /= 100;
-
- p = v * (1 - s);
- q = v * (1 - s * f);
- t = v * (1 - s * (1 - f));
-
- if (s == 0) {
- rgb.r = rgb.g = rgb.b = v;
- }
- else {
- switch (h2) {
- case 1:
- rgb.r = q;
- rgb.g = v;
- rgb.b = p;
- break;
-
- case 2:
- rgb.r = p;
- rgb.g = v;
- rgb.b = t;
- break;
-
- case 3:
- rgb.r = p;
- rgb.g = q;
- rgb.b = v;
- break;
-
- case 4:
- rgb.r = t;
- rgb.g = p;
- rgb.b = v;
- break;
-
- case 5:
- rgb.r = v;
- rgb.g = p;
- rgb.b = q;
- break;
-
- case 0:
- case 6:
- rgb.r = v;
- rgb.g = t;
- rgb.b = p;
- break;
- }
- }
-
- return {
- r: Math.round(rgb.r * 255),
- g: Math.round(rgb.g * 255),
- b: Math.round(rgb.b * 255)
- };
- },
-
- /**
- * Converts a RGB color into HSV.
- *
- * @see https://secure.wikimedia.org/wikipedia/de/wiki/HSV-Farbraum#Transformation_von_RGB_und_HSV
- *
- * @param {int} r
- * @param {int} g
- * @param {int} b
- * @return {Object}
- */
- rgbToHsv: function(r, g, b) {
- var h, s, v;
- var max, min, diff;
-
- r /= 255;
- g /= 255;
- b /= 255;
-
- max = Math.max(Math.max(r, g), b);
- min = Math.min(Math.min(r, g), b);
- diff = max - min;
-
- h = 0;
- if (max !== min) {
- switch (max) {
- case r:
- h = 60 * ((g - b) / diff);
- break;
-
- case g:
- h = 60 * (2 + (b - r) / diff);
- break;
-
- case b:
- h = 60 * (4 + (r - g) / diff);
- break;
- }
-
- if (h < 0) {
- h += 360;
- }
- }
-
- if (max === 0) {
- s = 0;
- }
- else {
- s = diff / max;
- }
-
- v = max;
-
- return {
- h: Math.round(h),
- s: Math.round(s * 100),
- v: Math.round(v * 100)
- };
- },
-
- /**
- * Converts HEX into RGB.
- *
- * @param {string} hex
- * @return {Object}
- */
- hexToRgb: function(hex) {
- if (/^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(hex)) {
- // only convert #abc and #abcdef
- var parts = hex.split('');
-
- // drop the hashtag
- 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)
- };
- }
- else {
- return {
- r: parseInt(parts[0] + '' + parts[1], 16),
- g: parseInt(parts[2] + '' + parts[3], 16),
- b: parseInt(parts[4] + '' + parts[5], 16)
- };
- }
- }
-
- return Number.NaN;
- },
-
- /**
- * Converts a RGB into HEX.
- *
- * @see http://www.linuxtopia.org/online_books/javascript_guides/javascript_faq/rgbtohex.htm
- *
- * @param {int} r
- * @param {int} g
- * @param {int} b
- * @return {string}
- */
- rgbToHex: function(r, g, b) {
- var charList = "0123456789ABCDEF";
-
- if (g === undefined) {
- if (r.toString().match(/^rgba?\((\d+), ?(\d+), ?(\d+)(?:, ?[0-9.]+)?\)$/)) {
- r = RegExp.$1;
- g = RegExp.$2;
- 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));
- }
- };
-
- // WCF.ColorPicker compatibility (color format conversion)
- window.__wcf_bc_colorUtil = ColorUtil;
-
- return ColorUtil;
+define(["require", "exports"], function (require, exports) {
+ "use strict";
+ const ColorUtil = {
+ /**
+ * Converts a HSV color into RGB.
+ *
+ * @see https://secure.wikimedia.org/wikipedia/de/wiki/HSV-Farbraum#Transformation_von_RGB_und_HSV
+ */
+ hsvToRgb: (h, s, v) => {
+ const rgb = { r: 0, g: 0, b: 0 };
+ let h2, f, p, q, t;
+ h2 = Math.floor(h / 60);
+ f = h / 60 - h2;
+ s /= 100;
+ v /= 100;
+ p = v * (1 - s);
+ q = v * (1 - s * f);
+ t = v * (1 - s * (1 - f));
+ if (s == 0) {
+ rgb.r = rgb.g = rgb.b = v;
+ }
+ else {
+ switch (h2) {
+ case 1:
+ rgb.r = q;
+ rgb.g = v;
+ rgb.b = p;
+ break;
+ case 2:
+ rgb.r = p;
+ rgb.g = v;
+ rgb.b = t;
+ break;
+ case 3:
+ rgb.r = p;
+ rgb.g = q;
+ rgb.b = v;
+ break;
+ case 4:
+ rgb.r = t;
+ rgb.g = p;
+ rgb.b = v;
+ break;
+ case 5:
+ rgb.r = v;
+ rgb.g = p;
+ rgb.b = q;
+ break;
+ case 0:
+ case 6:
+ rgb.r = v;
+ rgb.g = t;
+ rgb.b = p;
+ break;
+ }
+ }
+ return {
+ r: Math.round(rgb.r * 255),
+ g: Math.round(rgb.g * 255),
+ b: Math.round(rgb.b * 255),
+ };
+ },
+ /**
+ * Converts a RGB color into HSV.
+ *
+ * @see https://secure.wikimedia.org/wikipedia/de/wiki/HSV-Farbraum#Transformation_von_RGB_und_HSV
+ */
+ rgbToHsv: (r, g, b) => {
+ let h, s, v;
+ let max, min, diff;
+ r /= 255;
+ g /= 255;
+ b /= 255;
+ max = Math.max(Math.max(r, g), b);
+ min = Math.min(Math.min(r, g), b);
+ diff = max - min;
+ h = 0;
+ if (max !== min) {
+ switch (max) {
+ case r:
+ h = 60 * ((g - b) / diff);
+ break;
+ case g:
+ h = 60 * (2 + (b - r) / diff);
+ break;
+ case b:
+ h = 60 * (4 + (r - g) / diff);
+ break;
+ }
+ if (h < 0) {
+ h += 360;
+ }
+ }
+ if (max === 0) {
+ s = 0;
+ }
+ else {
+ s = diff / max;
+ }
+ v = max;
+ return {
+ h: Math.round(h),
+ s: Math.round(s * 100),
+ v: Math.round(v * 100),
+ };
+ },
+ /**
+ * Converts HEX into RGB.
+ */
+ hexToRgb: (hex) => {
+ if (/^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(hex)) {
+ // only convert #abc and #abcdef
+ const parts = hex.split('');
+ // drop the hashtag
+ 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),
+ };
+ }
+ else {
+ return {
+ r: parseInt(parts[0] + '' + parts[1], 16),
+ g: parseInt(parts[2] + '' + parts[3], 16),
+ b: parseInt(parts[4] + '' + parts[5], 16),
+ };
+ }
+ }
+ return Number.NaN;
+ },
+ /**
+ * Converts a RGB into HEX.
+ *
+ * @see http://www.linuxtopia.org/online_books/javascript_guides/javascript_faq/rgbtohex.htm
+ */
+ rgbToHex: (r, g, b) => {
+ const charList = '0123456789ABCDEF';
+ if (g === undefined) {
+ if (r.toString().match(/^rgba?\((\d+), ?(\d+), ?(\d+)(?:, ?[0-9.]+)?\)$/)) {
+ r = +RegExp.$1;
+ g = +RegExp.$2;
+ 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));
+ },
+ };
+ // WCF.ColorPicker compatibility (color format conversion)
+ window.__wcf_bc_colorUtil = ColorUtil;
+ return ColorUtil;
});
Object.keys(obj).forEach(key => newObj[key] = _clone(obj[key]));
return newObj;
};
- //noinspection JSUnresolvedVariable
- const _prefix = 'wsc1337' + /*window.WCF_PATH.hashCode()*/ +'-';
+ const _prefix = 'wsc' + window.WCF_PATH.hashCode() + '-';
/**
* Deep clones an object.
*/
/**
* Developer tools for WoltLab Suite.
- *
- * @author Alexander Ebert
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module Devtools (alias)
- * @module WoltLabSuite/Core/Devtools
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module Devtools (alias)
+ * @module WoltLabSuite/Core/Devtools
*/
-define([], function() {
- "use strict";
-
- if (!COMPILER_TARGET_DEFAULT) {
- return {
- help: function () {},
- toggleEditorAutosave: function () {},
- toggleEventLogging: function () {},
- _internal_: {
- enable: function () {},
- editorAutosave: function () {},
- eventLog: function() {}
- }
- };
- }
-
- var _settings = {
- editorAutosave: true,
- eventLogging: false
- };
-
- var _updateConfig = function () {
- if (window.sessionStorage) {
- window.sessionStorage.setItem("__wsc_devtools_config", JSON.stringify(_settings));
- }
- };
-
- var Devtools = {
- /**
- * Prints the list of available commands.
- */
- help: function () {
- window.console.log("");
- window.console.log("%cAvailable commands:", "text-decoration: underline");
-
- var cmds = [];
- for (var cmd in Devtools) {
- if (cmd !== '_internal_' && Devtools.hasOwnProperty(cmd)) {
- cmds.push(cmd);
- }
- }
- cmds.sort().forEach(function(cmd) {
- window.console.log("\tDevtools." + cmd + "()");
- });
-
- window.console.log("");
- },
-
- /**
- * Disables/re-enables the editor autosave feature.
- *
- * @param {boolean} forceDisable
- */
- toggleEditorAutosave: function(forceDisable) {
- _settings.editorAutosave = (forceDisable === true) ? false : !_settings.editorAutosave;
- _updateConfig();
-
- window.console.log("%c\tEditor autosave " + (_settings.editorAutosave ? "enabled" : "disabled"), "font-style: italic");
- },
-
- /**
- * Enables/disables logging for fired event listener events.
- *
- * @param {boolean} forceEnable
- */
- toggleEventLogging: function(forceEnable) {
- _settings.eventLogging = (forceEnable === true) ? true : !_settings.eventLogging;
- _updateConfig();
-
- window.console.log("%c\tEvent logging " + (_settings.eventLogging ? "enabled" : "disabled"), "font-style: italic");
- },
-
- /**
- * Internal methods not meant to be called directly.
- */
- _internal_: {
- enable: function () {
- window.Devtools = Devtools;
-
- window.console.log("%cDevtools for WoltLab Suite loaded", "font-weight: bold");
-
- if (window.sessionStorage) {
- var settings = window.sessionStorage.getItem("__wsc_devtools_config");
- try {
- if (settings !== null) {
- _settings = JSON.parse(settings);
- }
- }
- 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("");
- },
-
- editorAutosave: function () {
- return _settings.editorAutosave;
- },
-
- eventLog: function(identifier, action) {
- if (_settings.eventLogging) {
- window.console.log("[Devtools.EventLogging] Firing event: " + action + " @ " + identifier);
- }
- }
- }
- };
-
- return Devtools;
+define(["require", "exports"], function (require, exports) {
+ "use strict";
+ let _settings = {
+ editorAutosave: true,
+ eventLogging: false,
+ };
+ function _updateConfig() {
+ if (window.sessionStorage) {
+ 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');
+ const commands = [];
+ for (const cmd in Devtools) {
+ if (cmd !== '_internal_' && Devtools.hasOwnProperty(cmd)) {
+ commands.push(cmd);
+ }
+ }
+ commands.sort().forEach(function (cmd) {
+ window.console.log('\tDevtools.' + cmd + '()');
+ });
+ 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');
+ },
+ /**
+ * Enables/disables logging for fired event listener events.
+ */
+ toggleEventLogging: function (forceEnable) {
+ _settings.eventLogging = forceEnable ? true : !_settings.eventLogging;
+ _updateConfig();
+ 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');
+ if (window.sessionStorage) {
+ const settings = window.sessionStorage.getItem('__wsc_devtools_config');
+ try {
+ if (settings !== null) {
+ _settings = JSON.parse(settings);
+ }
+ }
+ 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('');
+ },
+ editorAutosave: () => _settings.editorAutosave,
+ eventLog: (identifier, action) => {
+ if (_settings.eventLogging) {
+ window.console.log('[Devtools.EventLogging] Firing event: ' + action + ' @ ' + identifier);
+ }
+ },
+ },
+ };
+ return Devtools;
});
* 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.');
+ }
this._dictionary.forEach(callback);
}
/**
/**
* Provides basic details on the JavaScript environment.
- *
- * @author Alexander Ebert
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module Environment (alias)
- * @module WoltLabSuite/Core/Environment
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module Environment (alias)
+ * @module WoltLabSuite/Core/Environment
*/
-define([], function() {
- "use strict";
-
- var _browser = 'other';
- var _editor = 'none';
- var _platform = 'desktop';
- var _touch = false;
-
- /**
- * @exports WoltLabSuite/Core/Environment
- */
- return {
- /**
- * Determines environment variables.
- */
- setup: function() {
- if (typeof window.chrome === 'object') {
- // this detects Opera as well, we could check for window.opr if we need to
- _browser = 'chrome';
- }
- else {
- var styles = window.getComputedStyle(document.documentElement);
- for (var i = 0, length = styles.length; i < length; i++) {
- var property = styles[i];
-
- 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';
- }
- }
- }
-
- var ua = window.navigator.userAgent.toLowerCase();
- 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';
- }
-
- 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 DocumentTouch);
-
- // The iPad Pro 12.9" masquerades as a desktop browser.
- if (window.navigator.platform === 'MacIntel' && window.navigator.maxTouchPoints > 1) {
- _browser = 'safari';
- _platform = 'ios';
- }
- },
-
- /**
- * Returns the lower-case browser identifier.
- *
- * Possible values:
- * - chrome: Chrome and Opera
- * - firefox
- * - microsoft: Internet Explorer and Microsoft Edge
- * - safari
- *
- * @return {string} browser identifier
- */
- browser: function() {
- return _browser;
- },
-
- /**
- * Returns the available editor's name or an empty string.
- *
- * @return {string} editor name
- */
- editor: function() {
- return _editor;
- },
-
- /**
- * Returns the browser platform.
- *
- * Possible values:
- * - desktop
- * - android
- * - ios: iPhone, iPad and iPod
- * - windows: Windows on phones/tablets
- *
- * @return {string} browser platform
- */
- platform: function() {
- return _platform;
- },
-
- /**
- * Returns true if browser is potentially used with a touchscreen.
- *
- * Warning: Detecting touch is unreliable and should be avoided at all cost.
- *
- * @deprecated 3.0 - exists for backward-compatibility only, will be removed in the future
- *
- * @return {boolean} true if a touchscreen is present
- */
- touch: function() {
- return _touch;
- }
- };
+define(["require", "exports"], function (require, exports) {
+ "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 _touch = false;
+ /**
+ * Determines environment variables.
+ */
+ function setup() {
+ if (typeof window.chrome === 'object') {
+ // this detects Opera as well, we could check for window.opr if we need to
+ _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) {
+ // 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';
+ }
+ }
+ }
+ const ua = window.navigator.userAgent.toLowerCase();
+ 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';
+ }
+ 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);
+ // The iPad Pro 12.9" masquerades as a desktop browser.
+ if (window.navigator.platform === 'MacIntel' && window.navigator.maxTouchPoints > 1) {
+ _browser = 'safari';
+ _platform = 'ios';
+ }
+ }
+ exports.setup = setup;
+ /**
+ * Returns the lower-case browser identifier.
+ *
+ * Possible values:
+ * - chrome: Chrome and Opera
+ * - firefox
+ * - microsoft: Internet Explorer and Microsoft Edge
+ * - safari
+ */
+ function browser() {
+ return _browser;
+ }
+ exports.browser = browser;
+ /**
+ * Returns the available editor's name or an empty string.
+ */
+ function editor() {
+ return _editor;
+ }
+ exports.editor = editor;
+ /**
+ * Returns the browser platform.
+ *
+ * Possible values:
+ * - desktop
+ * - android
+ * - ios: iPhone, iPad and iPod
+ * - windows: Windows on phones/tablets
+ */
+ function platform() {
+ return _platform;
+ }
+ exports.platform = platform;
+ /**
+ * Returns true if browser is potentially used with a touchscreen.
+ *
+ * Warning: Detecting touch is unreliable and should be avoided at all cost.
+ *
+ * @deprecated 3.0 - exists for backward-compatibility only, will be removed in the future
+ */
+ function touch() {
+ return _touch;
+ }
+ exports.touch = touch;
});
/**
* Provides helper functions for file handling.
- *
- * @author Matthias Schmidt
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module WoltLabSuite/Core/FileUtil
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/FileUtil
*/
-define(['Dictionary', 'StringUtil'], function(Dictionary, StringUtil) {
- "use strict";
-
- var _fileExtensionIconMapping = Dictionary.fromObject({
- // 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'
- });
-
- var _mimeTypeExtensionMapping = Dictionary.fromObject({
- // 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'
- });
-
- return {
- /**
- * Formats the given filesize.
- *
- * @param {integer} byte number of bytes
- * @param {integer} precision number of decimals
- * @return {string} formatted filesize
- */
- formatFilesize: function(byte, precision) {
- if (precision === undefined) {
- precision = 2;
- }
-
- var symbol = 'Byte';
- if (byte >= 1000) {
- byte /= 1000;
- symbol = 'kB';
- }
- if (byte >= 1000) {
- byte /= 1000;
- symbol = 'MB';
- }
- if (byte >= 1000) {
- byte /= 1000;
- symbol = 'GB';
- }
- if (byte >= 1000) {
- byte /= 1000;
- symbol = 'TB';
- }
-
- return StringUtil.formatNumeric(byte, -precision) + ' ' + symbol;
- },
-
- /**
- * Returns the icon name for given filename.
- *
- * Note: For any file icon name like `fa-file-word`, only `word`
- * will be returned by this method.
- *
- * @parsm {string} filename name of file for which icon name will be returned
- * @return {string} FontAwesome icon name
- */
- getIconNameByFilename: function(filename) {
- var lastDotPosition = filename.lastIndexOf('.');
- if (lastDotPosition !== false) {
- var extension = filename.substr(lastDotPosition + 1);
-
- if (_fileExtensionIconMapping.has(extension)) {
- return _fileExtensionIconMapping.get(extension);
- }
- }
-
- return '';
- },
-
- /**
- * Returns a known file extension including a leading dot or an empty string.
- *
- * @param mimetype the mimetype to get the common file extension for
- * @returns {string} the file dot prefixed extension or an empty string
- */
- getExtensionByMimeType: function (mimetype) {
- if (_mimeTypeExtensionMapping.has(mimetype)) {
- return '.' + _mimeTypeExtensionMapping.get(mimetype);
- }
-
- return '';
- },
-
- /**
- * Constructs a File object from a Blob
- *
- * @param blob the blob to convert
- * @param filename the filename
- * @returns {File} the File object
- */
- blobToFile: function (blob, filename) {
- var ext = this.getExtensionByMimeType(blob.type);
- var File = window.File;
-
- try {
- // IE11 does not support the file constructor
- new File([], 'ie11-check');
- }
- catch (error) {
- // Create a good enough File object based on the Blob prototype
- File = function File(chunks, filename, options) {
- var self = Blob.call(this, chunks, options);
-
- self.name = filename;
- self.lastModifiedDate = new Date();
-
- return self;
- };
-
- File.prototype = Object.create(window.File.prototype);
- }
-
- return new File([blob], filename + ext, {type: blob.type});
- },
- };
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+define(["require", "exports", "./Dictionary", "./StringUtil"], function (require, exports, Dictionary_1, StringUtil) {
+ "use strict";
+ Object.defineProperty(exports, "__esModule", { value: true });
+ exports.blobToFile = exports.getExtensionByMimeType = exports.getIconNameByFilename = exports.formatFilesize = void 0;
+ Dictionary_1 = __importDefault(Dictionary_1);
+ StringUtil = __importStar(StringUtil);
+ const _fileExtensionIconMapping = Dictionary_1.default.fromObject({
+ // 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 = Dictionary_1.default.fromObject({
+ // 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.
+ */
+ function formatFilesize(byte, precision) {
+ if (precision === undefined) {
+ precision = 2;
+ }
+ let symbol = 'Byte';
+ if (byte >= 1000) {
+ byte /= 1000;
+ symbol = 'kB';
+ }
+ if (byte >= 1000) {
+ byte /= 1000;
+ symbol = 'MB';
+ }
+ if (byte >= 1000) {
+ byte /= 1000;
+ symbol = 'GB';
+ }
+ if (byte >= 1000) {
+ byte /= 1000;
+ symbol = 'TB';
+ }
+ return StringUtil.formatNumeric(byte, -precision) + ' ' + symbol;
+ }
+ exports.formatFilesize = formatFilesize;
+ /**
+ * Returns the icon name for given filename.
+ *
+ * Note: For any file icon name like `fa-file-word`, only `word`
+ * will be returned by this method.
+ */
+ function getIconNameByFilename(filename) {
+ const lastDotPosition = filename.lastIndexOf('.');
+ if (lastDotPosition !== -1) {
+ const extension = filename.substr(lastDotPosition + 1);
+ if (_fileExtensionIconMapping.has(extension)) {
+ return _fileExtensionIconMapping.get(extension);
+ }
+ }
+ return '';
+ }
+ exports.getIconNameByFilename = getIconNameByFilename;
+ /**
+ * Returns a known file extension including a leading dot or an empty string.
+ */
+ function getExtensionByMimeType(mimetype) {
+ if (_mimeTypeExtensionMapping.has(mimetype)) {
+ return '.' + _mimeTypeExtensionMapping.get(mimetype);
+ }
+ return '';
+ }
+ exports.getExtensionByMimeType = getExtensionByMimeType;
+ /**
+ * Constructs a File object from a Blob
+ *
+ * @param blob the blob to convert
+ * @param filename the filename
+ * @returns {File} the File object
+ */
+ function blobToFile(blob, filename) {
+ const ext = this.getExtensionByMimeType(blob.type);
+ return new File([blob], filename + ext, { type: blob.type });
+ }
+ exports.blobToFile = blobToFile;
});
/**
* Generates plural phrases for the `plural` template plugin.
- *
- * @author Matthias Schmidt, Marcel Werk
- * @copyright 2001-2020 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module WoltLabSuite/Core/I18n/Plural
+ *
+ * @author Matthias Schmidt, Marcel Werk
+ * @copyright 2001-2020 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/I18n/Plural
*/
-define(['StringUtil'], function(StringUtil) {
- "use strict";
-
- var PLURAL_FEW = 'few';
- var PLURAL_MANY = 'many';
- var PLURAL_ONE = 'one';
- var PLURAL_OTHER = 'other';
- var PLURAL_TWO = 'two';
- var PLURAL_ZERO = 'zero';
-
- return {
- /**
- * Returns the plural category for the given value.
- *
- * @param {number} value
- * @param {?string} languageCode
- * @return string
- */
- getCategory: function(value, languageCode) {
- if (!languageCode) {
- languageCode = document.documentElement.lang;
- }
-
- // Fallback: handle unknown languages as English
- if (typeof this[languageCode] !== 'function') {
- languageCode = 'en';
- }
-
- var category = this[languageCode](value);
- if (category) {
- return category;
- }
-
- return PLURAL_OTHER;
- },
-
- /**
- * Returns the value for a `plural` element used in the template.
- *
- * @param {object} parameters
- * @see wcf\system\template\plugin\PluralFunctionTemplatePlugin::execute()
- */
- getCategoryFromTemplateParameters: function(parameters) {
- if (!parameters['value'] ) {
- throw new Error('Missing parameter value');
- }
- if (!parameters['other']) {
- throw new Error('Missing parameter other');
- }
-
- var value = parameters['value'];
- if (Array.isArray(value)) {
- value = value.length;
- }
-
- // handle numeric attributes
- for (var key in parameters) {
- if (objOwns(parameters, key) && key == ~~key && key == value) {
- return parameters[key];
- }
- }
-
- var category = this.getCategory(value);
- if (!parameters[category]) {
- category = PLURAL_OTHER;
- }
-
- var string = parameters[category];
- if (string.indexOf('#') !== -1) {
- return string.replace('#', StringUtil.formatNumeric(value));
- }
-
- return string;
- },
-
- /**
- * `f` is the fractional number as a whole number (1.234 yields 234)
- *
- * @param {number} n
- * @return {integer}
- */
- getF: function(n) {
- n = n.toString();
- var pos = n.indexOf('.');
- if (pos === -1) {
- return 0;
- }
-
- return parseInt(n.substr(pos + 1), 10);
- },
-
- /**
- * `v` represents the number of digits of the fractional part (1.234 yields 3)
- *
- * @param {number} n
- * @return {integer}
- */
- getV: function(n) {
- return n.toString().replace(/^[^.]*\.?/, '').length;
- },
-
- // Afrikaans
- af: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Amharic
- am: function(n) {
- var i = Math.floor(Math.abs(n));
- if (n == 1 || i === 0) return PLURAL_ONE;
- },
-
- // Arabic
- ar: function(n) {
- if (n == 0) return PLURAL_ZERO;
- if (n == 1) return PLURAL_ONE;
- if (n == 2) return PLURAL_TWO;
-
- var mod100 = n % 100;
- if (mod100 >= 3 && mod100 <= 10) return PLURAL_FEW;
- if (mod100 >= 11 && mod100 <= 99) return PLURAL_MANY;
- },
-
- // Assamese
- as: function(n) {
- var i = Math.floor(Math.abs(n));
- if (n == 1 || i === 0) return PLURAL_ONE;
- },
-
- // Azerbaijani
- az: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Belarusian
- be: function(n) {
- var mod10 = n % 10;
- var mod100 = n % 100;
-
- if (mod10 == 1 && mod100 != 11) return PLURAL_ONE;
- if (mod10 >= 2 && mod10 <= 4 && !(mod100 >= 12 && mod100 <= 14)) return PLURAL_FEW;
- if (mod10 == 0 || (mod10 >= 5 && mod10 <= 9) || (mod100 >= 11 && mod100 <= 14)) return PLURAL_MANY;
- },
-
- // Bulgarian
- bg: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Bengali
- bn: function(n) {
- var i = Math.floor(Math.abs(n));
- if (n == 1 || i === 0) return PLURAL_ONE;
- },
-
- // Tibetan
- bo: function(n) {},
-
- // Bosnian
- bs: function(n) {
- var v = this.getV(n);
- var f = this.getF(n);
- var mod10 = n % 10;
- var mod100 = n % 100;
- var fMod10 = f % 10;
- var 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;
- },
-
- // Czech
- cs: function(n) {
- var v = this.getV(n);
-
- if (n == 1 && v === 0) return PLURAL_ONE;
- if (n >= 2 && n <= 4 && v === 0) return PLURAL_FEW;
- if (v === 0) return PLURAL_MANY;
- },
-
- // Welsh
- cy: function(n) {
- if (n == 0) return PLURAL_ZERO;
- if (n == 1) return PLURAL_ONE;
- if (n == 2) return PLURAL_TWO;
- if (n == 3) return PLURAL_FEW;
- if (n == 6) return PLURAL_MANY;
- },
-
- // Danish
- da: function(n) {
- if (n > 0 && n < 2) return PLURAL_ONE;
- },
-
- // Greek
- el: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Catalan (ca)
- // German (de)
- // English (en)
- // Estonian (et)
- // Finnish (fi)
- // Italian (it)
- // Dutch (nl)
- // Swedish (sv)
- // Swahili (sw)
- // Urdu (ur)
- en: function(n) {
- if (n == 1 && this.getV(n) === 0) return PLURAL_ONE;
- },
-
- // Spanish
- es: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Basque
- eu: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Persian
- fa: function(n) {
- if (n >= 0 && n <= 1) return PLURAL_ONE;
- },
-
- // French
- fr: function(n) {
- if (n >= 0 && n < 2) return PLURAL_ONE;
- },
-
- // Irish
- ga: function(n) {
- if (n == 1) return PLURAL_ONE;
- if (n == 2) return PLURAL_TWO;
- if (n == 3 || n == 4 || n == 5 || n == 6) return PLURAL_FEW;
- if (n == 7 || n == 8 || n == 9 || n == 10) return PLURAL_MANY;
- },
-
- // Gujarati
- gu: function(n) {
- if (n >= 0 && n <= 1) return PLURAL_ONE;
- },
-
- // Hebrew
- he: function(n) {
- var v = this.getV(n);
-
- if (n == 1 && v === 0) return PLURAL_ONE;
- if (n == 2 && v === 0) return PLURAL_TWO;
- if (n > 10 && v === 0 && n % 10 == 0) return PLURAL_MANY;
- },
-
- // Hindi
- hi: function(n) {
- if (n >= 0 && n <= 1) return PLURAL_ONE;
- },
-
- // Croatian
- hr: function(n) {
- // same as Bosnian
- return this.bs(n);
- },
-
- // Hungarian
- hu: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Armenian
- hy: function(n) {
- if (n >= 0 && n < 2) return PLURAL_ONE;
- },
-
- // Indonesian
- id: function(n) {},
-
- // Icelandic
- is: function(n) {
- var f = this.getF(n);
-
- if (f === 0 && n % 10 === 1 && !(n % 100 === 11) || !(f === 0)) return PLURAL_ONE;
- },
-
- // Japanese
- ja: function(n) {},
-
- // Javanese
- jv: function(n) {},
-
- // Georgian
- ka: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Kazakh
- kk: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Khmer
- km: function(n) {},
-
- // Kannada
- kn: function(n) {
- if (n >= 0 && n <= 1) return PLURAL_ONE;
- },
-
- // Korean
- ko: function(n) {},
-
- // Kurdish
- ku: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Kyrgyz
- ky: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Luxembourgish
- lb: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Lao
- lo: function(n) {},
-
- // Lithuanian
- lt: function(n) {
- var mod10 = n % 10;
- var mod100 = n % 100;
-
- if (mod10 == 1 && !(mod100 >= 11 && mod100 <= 19)) return PLURAL_ONE;
- if (mod10 >= 2 && mod10 <= 9 && !(mod100 >= 11 && mod100 <= 19)) return PLURAL_FEW;
- if (this.getF(n) != 0) return PLURAL_MANY;
- },
-
- // Latvian
- lv: function(n) {
- var mod10 = n % 10;
- var mod100 = n % 100;
- var v = this.getV(n);
- var f = this.getF(n);
- var fMod10 = f % 10;
- var 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;
- },
-
- // Macedonian
- mk: function(n) {
- var v = this.getV(n);
- var f = this.getF(n);
- var mod10 = n % 10;
- var mod100 = n % 100;
- var fMod10 = f % 10;
- var fMod100 = f % 100;
-
- if ((v == 0 && mod10 == 1 && mod100 != 11) || (fMod10 == 1 && fMod100 != 11)) return PLURAL_ONE;
- },
-
- // Malayalam
- ml: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Mongolian
- mn: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Marathi
- mr: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Malay
- ms: function(n) {},
-
- // Maltese
- mt: function(n) {
- var mod100 = n % 100;
-
- if (n == 1) return PLURAL_ONE;
- if (n == 0 || (mod100 >= 2 && mod100 <= 10)) return PLURAL_FEW;
- if (mod100 >= 11 && mod100 <= 19) return PLURAL_MANY;
- },
-
- // Burmese
- my: function(n) {},
-
- // Norwegian
- no: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Nepali
- ne: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Odia
- or: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Punjabi
- pa: function(n) {
- if (n == 1 || n == 0) return PLURAL_ONE;
- },
-
- // Polish
- pl: function(n) {
- var v = this.getV(n);
- var mod10 = n % 10;
- var mod100 = n % 100;
-
- 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;
- },
-
- // Pashto
- ps: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Portuguese
- pt: function(n) {
- if (n >= 0 && n < 2) return PLURAL_ONE;
- },
-
- // Romanian
- ro: function(n) {
- var v = this.getV(n);
- var mod100 = n % 100;
-
- if (n == 1 && v === 0) return PLURAL_ONE;
- if (v != 0 || n == 0 || (mod100 >= 2 && mod100 <= 19)) return PLURAL_FEW;
- },
-
- // Russian
- ru: function(n) {
- var mod10 = n % 10;
- var mod100 = n % 100;
-
- if (this.getV(n) == 0) {
- if (mod10 == 1 && mod100 != 11) return PLURAL_ONE;
- if (mod10 >= 2 && mod10 <= 4 && !(mod100 >= 12 && mod100 <= 14)) return PLURAL_FEW;
- if (mod10 == 0 || (mod10 >= 5 && mod10 <= 9) || (mod100 >= 11 && mod100 <= 14)) return PLURAL_MANY;
- }
- },
-
- // Sindhi
- sd: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Sinhala
- si: function(n) {
- if (n == 0 || n == 1 || (Math.floor(n) == 0 && this.getF(n) == 1)) return PLURAL_ONE;
- },
-
- // Slovak
- sk: function(n) {
- // same as Czech
- return this.cs(n);
- },
-
- // Slovenian
- sl: function(n) {
- var v = this.getV(n);
- var mod100 = n % 100;
-
- if (v == 0 && mod100 == 1) return PLURAL_ONE;
- if (v == 0 && mod100 == 2) return PLURAL_TWO;
- if ((v == 0 && (mod100 == 3 || mod100 == 4)) || v != 0) return PLURAL_FEW;
- },
-
- // Albanian
- sq: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Serbian
- sr: function(n) {
- // same as Bosnian
- return this.bs(n);
- },
-
- // Tamil
- ta: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Telugu
- te: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Tajik
- tg: function(n) {},
-
- // Thai
- th: function(n) {},
-
- // Turkmen
- tk: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Turkish
- tr: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Uyghur
- ug: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Ukrainian
- uk: function(n) {
- // same as Russian
- return this.ru(n);
- },
-
- // Uzbek
- uz: function(n) {
- if (n == 1) return PLURAL_ONE;
- },
-
- // Vietnamese
- vi: function(n) {},
-
- // Chinese
- zh: function(n) {}
- };
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
+define(["require", "exports", "../StringUtil"], function (require, exports, StringUtil) {
+ "use strict";
+ StringUtil = __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 = {
+ /**
+ * Returns the plural category for the given value.
+ */
+ getCategory: function (value, languageCode) {
+ if (!languageCode) {
+ languageCode = document.documentElement.lang;
+ }
+ // Fallback: handle unknown languages as English
+ if (typeof this[languageCode] !== 'function') {
+ languageCode = 'en';
+ }
+ const category = this[languageCode](value);
+ if (category) {
+ return category;
+ }
+ return PLURAL_OTHER;
+ },
+ /**
+ * Returns the value for a `plural` element used in the template.
+ *
+ * @see wcf\system\template\plugin\PluralFunctionTemplatePlugin::execute()
+ */
+ getCategoryFromTemplateParameters: function (parameters) {
+ if (!parameters['value']) {
+ throw new Error('Missing parameter value');
+ }
+ if (!parameters['other']) {
+ throw new Error('Missing parameter other');
+ }
+ let value = parameters['value'];
+ if (Array.isArray(value)) {
+ value = value.length;
+ }
+ // handle numeric attributes
+ for (const key in parameters) {
+ if (parameters.hasOwnProperty(key) && key.toString() === (~~key).toString() && key == value) {
+ return parameters[key];
+ }
+ }
+ let category = this.getCategory(value);
+ if (!parameters[category]) {
+ category = PLURAL_OTHER;
+ }
+ const string = parameters[category];
+ if (string.indexOf('#') !== -1) {
+ return string.replace('#', StringUtil.formatNumeric(value));
+ }
+ return string;
+ },
+ /**
+ * `f` is the fractional number as a whole number (1.234 yields 234)
+ */
+ getF: function (n) {
+ const tmp = n.toString();
+ const pos = tmp.indexOf('.');
+ if (pos === -1) {
+ return 0;
+ }
+ return parseInt(tmp.substr(pos + 1), 10);
+ },
+ /**
+ * `v` represents the number of digits of the fractional part (1.234 yields 3)
+ */
+ getV: function (n) {
+ return n.toString().replace(/^[^.]*\.?/, '').length;
+ },
+ // Afrikaans
+ af: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Amharic
+ am: function (n) {
+ const i = Math.floor(Math.abs(n));
+ if (n == 1 || i === 0)
+ return PLURAL_ONE;
+ },
+ // Arabic
+ ar: function (n) {
+ if (n == 0)
+ return PLURAL_ZERO;
+ if (n == 1)
+ return PLURAL_ONE;
+ if (n == 2)
+ return PLURAL_TWO;
+ const mod100 = n % 100;
+ if (mod100 >= 3 && mod100 <= 10)
+ return PLURAL_FEW;
+ if (mod100 >= 11 && mod100 <= 99)
+ return PLURAL_MANY;
+ },
+ // Assamese
+ as: function (n) {
+ const i = Math.floor(Math.abs(n));
+ if (n == 1 || i === 0)
+ return PLURAL_ONE;
+ },
+ // Azerbaijani
+ az: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Belarusian
+ be: function (n) {
+ const mod10 = n % 10;
+ const mod100 = n % 100;
+ if (mod10 == 1 && mod100 != 11)
+ return PLURAL_ONE;
+ if (mod10 >= 2 && mod10 <= 4 && !(mod100 >= 12 && mod100 <= 14))
+ return PLURAL_FEW;
+ if (mod10 == 0 || (mod10 >= 5 && mod10 <= 9) || (mod100 >= 11 && mod100 <= 14))
+ return PLURAL_MANY;
+ },
+ // Bulgarian
+ bg: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Bengali
+ bn: function (n) {
+ const i = Math.floor(Math.abs(n));
+ if (n == 1 || i === 0)
+ return PLURAL_ONE;
+ },
+ // Tibetan
+ bo: function (n) {
+ },
+ // Bosnian
+ bs: function (n) {
+ const v = this.getV(n);
+ const f = this.getF(n);
+ const mod10 = n % 10;
+ const mod100 = n % 100;
+ const fMod10 = f % 10;
+ 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;
+ },
+ // Czech
+ cs: function (n) {
+ const v = this.getV(n);
+ if (n == 1 && v === 0)
+ return PLURAL_ONE;
+ if (n >= 2 && n <= 4 && v === 0)
+ return PLURAL_FEW;
+ if (v === 0)
+ return PLURAL_MANY;
+ },
+ // Welsh
+ cy: function (n) {
+ if (n == 0)
+ return PLURAL_ZERO;
+ if (n == 1)
+ return PLURAL_ONE;
+ if (n == 2)
+ return PLURAL_TWO;
+ if (n == 3)
+ return PLURAL_FEW;
+ if (n == 6)
+ return PLURAL_MANY;
+ },
+ // Danish
+ da: function (n) {
+ if (n > 0 && n < 2)
+ return PLURAL_ONE;
+ },
+ // Greek
+ el: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Catalan (ca)
+ // German (de)
+ // English (en)
+ // Estonian (et)
+ // Finnish (fi)
+ // Italian (it)
+ // Dutch (nl)
+ // Swedish (sv)
+ // Swahili (sw)
+ // Urdu (ur)
+ en: function (n) {
+ if (n == 1 && this.getV(n) === 0)
+ return PLURAL_ONE;
+ },
+ // Spanish
+ es: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Basque
+ eu: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Persian
+ fa: function (n) {
+ if (n >= 0 && n <= 1)
+ return PLURAL_ONE;
+ },
+ // French
+ fr: function (n) {
+ if (n >= 0 && n < 2)
+ return PLURAL_ONE;
+ },
+ // Irish
+ ga: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ if (n == 2)
+ return PLURAL_TWO;
+ if (n == 3 || n == 4 || n == 5 || n == 6)
+ return PLURAL_FEW;
+ if (n == 7 || n == 8 || n == 9 || n == 10)
+ return PLURAL_MANY;
+ },
+ // Gujarati
+ gu: function (n) {
+ if (n >= 0 && n <= 1)
+ return PLURAL_ONE;
+ },
+ // Hebrew
+ he: function (n) {
+ const v = this.getV(n);
+ if (n == 1 && v === 0)
+ return PLURAL_ONE;
+ if (n == 2 && v === 0)
+ return PLURAL_TWO;
+ if (n > 10 && v === 0 && n % 10 == 0)
+ return PLURAL_MANY;
+ },
+ // Hindi
+ hi: function (n) {
+ if (n >= 0 && n <= 1)
+ return PLURAL_ONE;
+ },
+ // Croatian
+ hr: function (n) {
+ // same as Bosnian
+ return this.bs(n);
+ },
+ // Hungarian
+ hu: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Armenian
+ hy: function (n) {
+ if (n >= 0 && n < 2)
+ return PLURAL_ONE;
+ },
+ // Indonesian
+ id: function (n) {
+ },
+ // Icelandic
+ is: function (n) {
+ const f = this.getF(n);
+ if (f === 0 && n % 10 === 1 && !(n % 100 === 11) || !(f === 0))
+ return PLURAL_ONE;
+ },
+ // Japanese
+ ja: function (n) {
+ },
+ // Javanese
+ jv: function (n) {
+ },
+ // Georgian
+ ka: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Kazakh
+ kk: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Khmer
+ km: function (n) {
+ },
+ // Kannada
+ kn: function (n) {
+ if (n >= 0 && n <= 1)
+ return PLURAL_ONE;
+ },
+ // Korean
+ ko: function (n) {
+ },
+ // Kurdish
+ ku: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Kyrgyz
+ ky: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Luxembourgish
+ lb: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Lao
+ lo: function (n) {
+ },
+ // Lithuanian
+ lt: function (n) {
+ const mod10 = n % 10;
+ const mod100 = n % 100;
+ if (mod10 == 1 && !(mod100 >= 11 && mod100 <= 19))
+ return PLURAL_ONE;
+ if (mod10 >= 2 && mod10 <= 9 && !(mod100 >= 11 && mod100 <= 19))
+ return PLURAL_FEW;
+ if (this.getF(n) != 0)
+ return PLURAL_MANY;
+ },
+ // Latvian
+ lv: function (n) {
+ const mod10 = n % 10;
+ const mod100 = n % 100;
+ const v = this.getV(n);
+ const f = this.getF(n);
+ const fMod10 = f % 10;
+ 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;
+ },
+ // Macedonian
+ mk: function (n) {
+ return this.bs(n);
+ },
+ // Malayalam
+ ml: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Mongolian
+ mn: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Marathi
+ mr: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Malay
+ ms: function (n) {
+ },
+ // Maltese
+ mt: function (n) {
+ const mod100 = n % 100;
+ if (n == 1)
+ return PLURAL_ONE;
+ if (n == 0 || (mod100 >= 2 && mod100 <= 10))
+ return PLURAL_FEW;
+ if (mod100 >= 11 && mod100 <= 19)
+ return PLURAL_MANY;
+ },
+ // Burmese
+ my: function (n) {
+ },
+ // Norwegian
+ no: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Nepali
+ ne: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Odia
+ or: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Punjabi
+ pa: function (n) {
+ if (n == 1 || n == 0)
+ return PLURAL_ONE;
+ },
+ // Polish
+ pl: function (n) {
+ const v = this.getV(n);
+ const mod10 = n % 10;
+ const mod100 = n % 100;
+ 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;
+ },
+ // Pashto
+ ps: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Portuguese
+ pt: function (n) {
+ if (n >= 0 && n < 2)
+ return PLURAL_ONE;
+ },
+ // Romanian
+ ro: function (n) {
+ const v = this.getV(n);
+ const mod100 = n % 100;
+ if (n == 1 && v === 0)
+ return PLURAL_ONE;
+ if (v != 0 || n == 0 || (mod100 >= 2 && mod100 <= 19))
+ return PLURAL_FEW;
+ },
+ // Russian
+ ru: function (n) {
+ const mod10 = n % 10;
+ const mod100 = n % 100;
+ if (this.getV(n) == 0) {
+ if (mod10 == 1 && mod100 != 11)
+ return PLURAL_ONE;
+ if (mod10 >= 2 && mod10 <= 4 && !(mod100 >= 12 && mod100 <= 14))
+ return PLURAL_FEW;
+ if (mod10 == 0 || (mod10 >= 5 && mod10 <= 9) || (mod100 >= 11 && mod100 <= 14))
+ return PLURAL_MANY;
+ }
+ },
+ // Sindhi
+ sd: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Sinhala
+ si: function (n) {
+ if (n == 0 || n == 1 || (Math.floor(n) == 0 && this.getF(n) == 1))
+ return PLURAL_ONE;
+ },
+ // Slovak
+ sk: function (n) {
+ // same as Czech
+ return this.cs(n);
+ },
+ // Slovenian
+ sl: function (n) {
+ const v = this.getV(n);
+ const mod100 = n % 100;
+ if (v == 0 && mod100 == 1)
+ return PLURAL_ONE;
+ if (v == 0 && mod100 == 2)
+ return PLURAL_TWO;
+ if ((v == 0 && (mod100 == 3 || mod100 == 4)) || v != 0)
+ return PLURAL_FEW;
+ },
+ // Albanian
+ sq: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Serbian
+ sr: function (n) {
+ // same as Bosnian
+ return this.bs(n);
+ },
+ // Tamil
+ ta: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Telugu
+ te: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Tajik
+ tg: function (n) {
+ },
+ // Thai
+ th: function (n) {
+ },
+ // Turkmen
+ tk: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Turkish
+ tr: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Uyghur
+ ug: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Ukrainian
+ uk: function (n) {
+ // same as Russian
+ return this.ru(n);
+ },
+ // Uzbek
+ uz: function (n) {
+ if (n == 1)
+ return PLURAL_ONE;
+ },
+ // Vietnamese
+ vi: function (n) {
+ },
+ // Chinese
+ zh: function (n) {
+ },
+ };
+ return Plural;
});
-/**
- * Manages language items.
- *
- * @author Tim Duesterhus
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module Language (alias)
- * @module WoltLabSuite/Core/Language
- */
-define(['Dictionary', './Template'], function(Dictionary, Template) {
- "use strict";
-
- var _languageItems = new Dictionary();
-
- /**
- * @exports WoltLabSuite/Core/Language
- */
- var Language = {
- /**
- * Adds all the language items in the given object to the store.
- *
- * @param {Object.<string, string>} object
- */
- addObject: function(object) {
- _languageItems.merge(Dictionary.fromObject(object));
- },
-
- /**
- * Adds a single language item to the store.
- *
- * @param {string} key
- * @param {string} value
- */
- add: function(key, value) {
- _languageItems.set(key, value);
- },
-
- /**
- * Fetches the language item specified by the given key.
- * If the language item is a string it will be evaluated as
- * WoltLabSuite/Core/Template with the given parameters.
- *
- * @param {string} key Language item to return.
- * @param {Object=} parameters Parameters to provide to WoltLabSuite/Core/Template.
- * @return {string}
- */
- get: function(key, parameters) {
- if (!parameters) parameters = { };
-
- var value = _languageItems.get(key);
-
- if (value === undefined) {
- return key;
- }
-
- // fetch Template, as it cannot be provided because of a circular dependency
- if (Template === undefined) Template = require('WoltLabSuite/Core/Template');
-
- 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}'));
- }
- value = _languageItems.get(key);
- }
-
- if (value instanceof Template) {
- value = value.fetch(parameters);
- }
-
- return value;
- }
- };
-
- return Language;
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+define(["require", "exports", "./Dictionary", "./Template"], function (require, exports, Dictionary_1, Template_1) {
+ "use strict";
+ Object.defineProperty(exports, "__esModule", { value: true });
+ exports.get = exports.add = exports.addObject = void 0;
+ Dictionary_1 = __importDefault(Dictionary_1);
+ Template_1 = __importDefault(Template_1);
+ const _languageItems = new Dictionary_1.default();
+ /**
+ * Adds all the language items in the given object to the store.
+ */
+ function addObject(object) {
+ _languageItems.merge(Dictionary_1.default.fromObject(object));
+ }
+ exports.addObject = addObject;
+ /**
+ * Adds a single language item to the store.
+ */
+ function add(key, value) {
+ _languageItems.set(key, value);
+ }
+ exports.add = add;
+ /**
+ * Fetches the language item specified by the given key.
+ * If the language item is a string it will be evaluated as
+ * WoltLabSuite/Core/Template with the given parameters.
+ *
+ * @param {string} key Language item to return.
+ * @param {Object=} parameters Parameters to provide to WoltLabSuite/Core/Template.
+ * @return {string}
+ */
+ function get(key, parameters) {
+ let value = _languageItems.get(key);
+ if (value === undefined) {
+ 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 (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}'));
+ }
+ value = _languageItems.get(key);
+ }
+ if (value instanceof Template_1.default) {
+ value = value.fetch(parameters || {});
+ }
+ return value;
+ }
+ exports.get = get;
});
-/**
- * List implementation relying on an array or if supported on a Set to hold values.
- *
- * @author Alexander Ebert
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module List (alias)
- * @module WoltLabSuite/Core/List
- */
-define([], function() {
- "use strict";
-
- var _hasSet = objOwns(window, 'Set') && typeof window.Set === 'function';
-
- /**
- * @constructor
- */
- function List() {
- this._set = (_hasSet) ? new Set() : [];
- }
- List.prototype = {
- /**
- * Appends an element to the list, silently rejects adding an already existing value.
- *
- * @param {?} value unique element
- */
- add: function(value) {
- if (_hasSet) {
- this._set.add(value);
- }
- else if (!this.has(value)) {
- this._set.push(value);
- }
- },
-
- /**
- * Removes all elements from the list.
- */
- clear: function() {
- if (_hasSet) {
- this._set.clear();
- }
- else {
- this._set = [];
- }
- },
-
- /**
- * Removes an element from the list, returns true if the element was in the list.
- *
- * @param {?} value element
- * @return {boolean} true if element was in the list
- */
- 'delete': function(value) {
- if (_hasSet) {
- return this._set['delete'](value);
- }
- else {
- var index = this._set.indexOf(value);
- if (index === -1) {
- return false;
- }
-
- this._set.splice(index, 1);
- return true;
- }
- },
-
- /**
- * Calls `callback` for each element in the list.
- */
- forEach: function(callback) {
- if (_hasSet) {
- this._set.forEach(callback);
- }
- else {
- for (var i = 0, length = this._set.length; i < length; i++) {
- callback(this._set[i]);
- }
- }
- },
-
- /**
- * Returns true if the list contains the element.
- *
- * @param {?} value element
- * @return {boolean} true if element is in the list
- */
- has: function(value) {
- if (_hasSet) {
- return this._set.has(value);
- }
- else {
- return (this._set.indexOf(value) !== -1);
- }
- }
- };
-
- Object.defineProperty(List.prototype, 'size', {
- enumerable: false,
- configurable: true,
- get: function() {
- if (_hasSet) {
- return this._set.size;
- }
- else {
- return this._set.length;
- }
- }
- });
-
- return List;
+define(["require", "exports"], function (require, exports) {
+ "use strict";
+ /**
+ * List implementation relying on an array or if supported on a Set to hold values.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module List (alias)
+ * @module WoltLabSuite/Core/List
+ */
+ /**
+ * @constructor
+ */
+ class List {
+ constructor() {
+ this._set = new Set();
+ }
+ /**
+ * Appends an element to the list, silently rejects adding an already existing value.
+ */
+ add(value) {
+ this._set.add(value);
+ }
+ /**
+ * Removes all elements from the list.
+ */
+ clear() {
+ this._set.clear();
+ }
+ /**
+ * Removes an element from the list, returns true if the element was in the list.
+ */
+ delete(value) {
+ return this._set.delete(value);
+ }
+ /**
+ * Invokes the `callback` for each element in the list.
+ */
+ forEach(callback) {
+ this._set.forEach(callback);
+ }
+ /**
+ * Returns true if the list contains the element.
+ */
+ has(value) {
+ return this._set.has(value);
+ }
+ get size() {
+ return this._set.size;
+ }
+ }
+ return List;
});
/**
* Provides helper functions for Number handling.
- *
- * @author Tim Duesterhus
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module WoltLabSuite/Core/NumberUtil
+ *
+ * @author Tim Duesterhus
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/NumberUtil
*/
-define([], function() {
- "use strict";
-
- /**
- * @exports WoltLabSuite/Core/NumberUtil
- */
- var NumberUtil = {
- /**
- * Decimal adjustment of a number.
- *
- * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
- * @param {Number} value The number.
- * @param {Integer} exp The exponent (the 10 logarithm of the adjustment base).
- * @returns {Number} The adjusted value.
- */
- round: function (value, exp) {
- // If the exp is undefined or zero...
- 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)) {
- return NaN;
- }
-
- // Shift
- value = value.toString().split('e');
- value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp)));
-
- // Shift back
- value = value.toString().split('e');
- return +(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp));
- }
- };
-
- return NumberUtil;
+define(["require", "exports"], function (require, exports) {
+ "use strict";
+ Object.defineProperty(exports, "__esModule", { value: true });
+ exports.round = void 0;
+ /**
+ * Decimal adjustment of a number.
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
+ */
+ function round(value, exp) {
+ // If the exp is undefined or zero...
+ 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)) {
+ return NaN;
+ }
+ // Shift
+ 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));
+ }
+ exports.round = round;
});
/**
- * Simple `object` to `object` map using a native WeakMap on supported browsers, otherwise a set of two arrays.
- *
+ * Simple `object` to `object` map using a WeakMap.
+ *
* If you're looking for a dictionary with string keys, please see `WoltLabSuite/Core/Dictionary`.
- *
- * @author Alexander Ebert
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module ObjectMap (alias)
- * @module WoltLabSuite/Core/ObjectMap
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module ObjectMap (alias)
+ * @module WoltLabSuite/Core/ObjectMap
*/
-define([], function() {
- "use strict";
-
- var _hasMap = objOwns(window, 'WeakMap') && typeof window.WeakMap === 'function';
-
- /**
- * @constructor
- */
- function ObjectMap() {
- this._map = (_hasMap) ? new WeakMap() : { key: [], value: [] };
- }
- ObjectMap.prototype = {
- /**
- * Sets a new key with given value, will overwrite an existing key.
- *
- * @param {object} key key
- * @param {object} value value
- */
- set: function(key, value) {
- 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 (_hasMap) {
- this._map.set(key, value);
- }
- else {
- this._map.key.push(key);
- this._map.value.push(value);
- }
- },
-
- /**
- * Removes a key from the map.
- *
- * @param {object} key key
- */
- 'delete': function(key) {
- if (_hasMap) {
- this._map['delete'](key);
- }
- else {
- var index = this._map.key.indexOf(key);
- this._map.key.splice(index);
- this._map.value.splice(index);
- }
- },
-
- /**
- * Returns true if dictionary contains a value for given key.
- *
- * @param {object} key key
- * @return {boolean} true if key exists
- */
- has: function(key) {
- if (_hasMap) {
- return this._map.has(key);
- }
- else {
- return (this._map.key.indexOf(key) !== -1);
- }
- },
-
- /**
- * Retrieves a value by key, returns undefined if there is no match.
- *
- * @param {object} key key
- * @return {*}
- */
- get: function(key) {
- if (_hasMap) {
- return this._map.get(key);
- }
- else {
- var index = this._map.key.indexOf(key);
- if (index !== -1) {
- return this._map.value[index];
- }
-
- return undefined;
- }
- }
- };
-
- return ObjectMap;
+define(["require", "exports"], function (require, exports) {
+ "use strict";
+ class ObjectMap {
+ constructor() {
+ this._map = new WeakMap();
+ }
+ /**
+ * 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 value !== 'object' || value === null) {
+ throw new TypeError('Only objects can be used as value');
+ }
+ this._map.set(key, value);
+ }
+ /**
+ * Removes a key from the map.
+ */
+ delete(key) {
+ this._map.delete(key);
+ }
+ /**
+ * Returns true if dictionary contains a value for given key.
+ */
+ has(key) {
+ return this._map.has(key);
+ }
+ /**
+ * Retrieves a value by key, returns undefined if there is no match.
+ */
+ get(key) {
+ return this._map.get(key);
+ }
+ }
+ return ObjectMap;
});
/**
* Manages user permissions.
- *
- * @author Matthias Schmidt
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module Permission (alias)
- * @module WoltLabSuite/Core/Permission
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module Permission (alias)
+ * @module WoltLabSuite/Core/Permission
*/
-define(['Dictionary'], function(Dictionary) {
- "use strict";
-
- var _permissions = new Dictionary();
-
- /**
- * @exports WoltLabSuite/Core/Permission
- */
- return {
- /**
- * Adds a single permission to the store.
- *
- * @param {string} permission permission name
- * @param {boolean} value permission value
- */
- add: function(permission, value) {
- if (typeof value !== "boolean") {
- throw new TypeError("Permission value has to be boolean.");
- }
-
- _permissions.set(permission, value);
- },
-
- /**
- * Adds all the permissions in the given object to the store.
- *
- * @param {Object.<string, boolean>} object permission list
- */
- addObject: function(object) {
- for (var key in object) {
- if (objOwns(object, key)) {
- this.add(key, object[key]);
- }
- }
- },
-
- /**
- * Returns the value of a permission.
- *
- * If the permission is unknown, false is returned.
- *
- * @param {string} permission permission name
- * @return {boolean} permission value
- */
- get: function(permission) {
- if (_permissions.has(permission)) {
- return _permissions.get(permission);
- }
-
- return false;
- }
- };
+define(["require", "exports"], function (require, exports) {
+ "use strict";
+ Object.defineProperty(exports, "__esModule", { value: true });
+ exports.get = exports.addObject = exports.add = void 0;
+ const _permissions = new Map();
+ /**
+ * 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.');
+ }
+ _permissions.set(permission, value);
+ }
+ exports.add = add;
+ /**
+ * Adds all the permissions in the given object to the store.
+ */
+ function addObject(object) {
+ for (const key in object) {
+ if (object.hasOwnProperty(key)) {
+ this.add(key, object[key]);
+ }
+ }
+ }
+ exports.addObject = addObject;
+ /**
+ * Returns the value of a permission.
+ *
+ * If the permission is unknown, false is returned.
+ */
+ function get(permission) {
+ if (_permissions.has(permission)) {
+ return _permissions.get(permission);
+ }
+ return false;
+ }
+ exports.get = get;
});
-/**
- * Provides helper functions for String handling.
- *
- * @author Tim Duesterhus, Joshua Ruesweg
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module StringUtil (alias)
- * @module WoltLabSuite/Core/StringUtil
- */
-define(['Language', './NumberUtil'], function(Language, NumberUtil) {
- "use strict";
-
- /**
- * @exports WoltLabSuite/Core/StringUtil
- */
- return {
- /**
- * Adds thousands separators to a given number.
- *
- * @see http://stackoverflow.com/a/6502556/782822
- * @param {?} number
- * @return {String}
- */
- addThousandsSeparator: function(number) {
- // Fetch Language, as it cannot be provided because of a circular dependency
- if (Language === undefined) Language = require('Language');
-
- 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
- *
- * @param {?} string
- * @return {String}
- */
- escapeHTML: function (string) {
- return String(string).replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
- },
-
- /**
- * Escapes a String to work with RegExp.
- *
- * @see https://github.com/sstephenson/prototype/blob/master/src/prototype/lang/regexp.js#L25
- * @param {?} string
- * @return {String}
- */
- escapeRegExp: function(string) {
- return String(string).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
- },
-
- /**
- * Rounds number to given count of floating point digits, localizes decimal-point and inserts thousands separators.
- *
- * @param {?} number
- * @param {int} decimalPlaces The number of decimal places to leave after rounding.
- * @return {String}
- */
- formatNumeric: function(number, decimalPlaces) {
- // Fetch Language, as it cannot be provided because of a circular dependency
- if (Language === undefined) Language = require('Language');
-
- number = String(NumberUtil.round(number, decimalPlaces || -2));
- var numberParts = number.split('.');
-
- number = this.addThousandsSeparator(numberParts[0]);
- if (numberParts.length > 1) number += Language.get('wcf.global.decimalPoint') + numberParts[1];
-
- number = number.replace('-', '\u2212');
-
- return number;
- },
-
- /**
- * Makes a string's first character lowercase.
- *
- * @param {?} string
- * @return {String}
- */
- lcfirst: function(string) {
- return String(string).substring(0, 1).toLowerCase() + string.substring(1);
- },
-
- /**
- * Makes a string's first character uppercase.
- *
- * @param {?} string
- * @return {String}
- */
- ucfirst: function(string) {
- return String(string).substring(0, 1).toUpperCase() + string.substring(1);
- },
-
- /**
- * Unescapes special HTML-characters within a string.
- *
- * @param {?} string
- * @return {String}
- */
- unescapeHTML: function(string) {
- return String(string).replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
- },
-
- /**
- * Shortens numbers larger than 1000 by using unit suffixes.
- *
- * @param {?} number
- * @return {String}
- */
- shortUnit: function(number) {
- var unitSuffix = '';
-
- if (number >= 1000000) {
- number /= 1000000;
-
- if (number > 10) {
- number = Math.floor(number);
- }
- else {
- number = NumberUtil.round(number, -1);
- }
-
- unitSuffix = 'M';
- }
- else if (number >= 1000) {
- number /= 1000;
-
- if (number > 10) {
- number = Math.floor(number);
- }
- else {
- number = NumberUtil.round(number, -1);
- }
-
- unitSuffix = 'k';
- }
-
- return this.formatNumeric(number) + unitSuffix;
- }
- };
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
+define(["require", "exports", "./Language", "./NumberUtil"], function (require, exports, Language, NumberUtil) {
+ "use strict";
+ Object.defineProperty(exports, "__esModule", { value: true });
+ exports.shortUnit = exports.unescapeHTML = exports.ucfirst = exports.lcfirst = exports.formatNumeric = exports.escapeRegExp = exports.escapeHTML = exports.addThousandsSeparator = void 0;
+ Language = __importStar(Language);
+ NumberUtil = __importStar(NumberUtil);
+ /**
+ * Adds thousands separators to a given number.
+ *
+ * @see http://stackoverflow.com/a/6502556/782822
+ */
+ function addThousandsSeparator(number) {
+ // Fetch Language, as it cannot be provided because of a circular dependency
+ 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'));
+ }
+ exports.addThousandsSeparator = addThousandsSeparator;
+ /**
+ * Escapes special HTML-characters within a string
+ */
+ function escapeHTML(string) {
+ return String(string).replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
+ }
+ exports.escapeHTML = escapeHTML;
+ /**
+ * Escapes a String to work with RegExp.
+ *
+ * @see https://github.com/sstephenson/prototype/blob/master/src/prototype/lang/regexp.js#L25
+ */
+ function escapeRegExp(string) {
+ return String(string).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
+ }
+ exports.escapeRegExp = escapeRegExp;
+ /**
+ * Rounds number to given count of floating point digits, localizes decimal-point and inserts thousands separators.
+ */
+ function formatNumeric(number, decimalPlaces) {
+ // Fetch Language, as it cannot be provided because of a circular dependency
+ if (Language === undefined) { //@ts-ignore
+ Language = require('./Language');
+ }
+ let tmp = NumberUtil.round(number, decimalPlaces || -2).toString();
+ const numberParts = tmp.split('.');
+ tmp = this.addThousandsSeparator(+numberParts[0]);
+ if (numberParts.length > 1)
+ tmp += Language.get('wcf.global.decimalPoint') + numberParts[1];
+ tmp = tmp.replace('-', '\u2212');
+ return tmp;
+ }
+ exports.formatNumeric = formatNumeric;
+ /**
+ * Makes a string's first character lowercase.
+ */
+ function lcfirst(string) {
+ return String(string).substring(0, 1).toLowerCase() + string.substring(1);
+ }
+ exports.lcfirst = lcfirst;
+ /**
+ * Makes a string's first character uppercase.
+ */
+ function ucfirst(string) {
+ return String(string).substring(0, 1).toUpperCase() + string.substring(1);
+ }
+ exports.ucfirst = ucfirst;
+ /**
+ * Unescapes special HTML-characters within a string.
+ */
+ function unescapeHTML(string) {
+ 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 = '';
+ if (number >= 1000000) {
+ number /= 1000000;
+ if (number > 10) {
+ number = Math.floor(number);
+ }
+ else {
+ number = NumberUtil.round(number, -1);
+ }
+ unitSuffix = 'M';
+ }
+ else if (number >= 1000) {
+ number /= 1000;
+ if (number > 10) {
+ number = Math.floor(number);
+ }
+ else {
+ number = NumberUtil.round(number, -1);
+ }
+ unitSuffix = 'k';
+ }
+ return this.formatNumeric(number) + unitSuffix;
+ }
+ exports.shortUnit = shortUnit;
});
-/**
- * WoltLabSuite/Core/Template provides a template scripting compiler similar
- * to the PHP one of WoltLab Suite Core. It supports a limited
- * set of useful commands and compiles templates down to a pure
- * JavaScript Function.
- *
- * @author Tim Duesterhus
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module WoltLabSuite/Core/Template
- */
-define(['./Template.grammar', './StringUtil', 'Language', 'WoltLabSuite/Core/I18n/Plural'], function(parser, StringUtil, Language, I18nPlural) {
- "use strict";
-
- // work around bug in AMD module generation of Jison
- function Parser() {
- this.yy = {};
- }
- Parser.prototype = parser;
- parser.Parser = Parser;
- parser = new Parser();
-
- /**
- * Compiles the given template.
- *
- * @param {string} template Template to compile.
- * @constructor
- */
- function Template(template) {
- // Fetch Language/StringUtil, as it cannot be provided because of a circular dependency
- if (Language === undefined) Language = require('Language');
- if (StringUtil === undefined) 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);
- }
- catch (e) {
- console.debug(e.message);
- throw e;
- }
- }
-
- Object.defineProperty(Template, 'callbacks', {
- enumerable: false,
- configurable: false,
- get: function() {
- throw new Error('WCF.Template.callbacks is no longer supported');
- },
- set: function(value) {
- throw new Error('WCF.Template.callbacks is no longer supported');
- }
- });
-
- Template.prototype = {
- /**
- * Evaluates the Template using the given parameters.
- *
- * @param {object} v Parameters to pass to the template.
- */
- fetch: function(v) {
- // this will be replaced in the init function
- throw new Error('This Template is not initialized.');
- }
- };
-
- return Template;
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
+define(["require", "exports", "./Template.grammar", "./StringUtil", "./Language", "./I18n/Plural"], function (require, exports, parser, StringUtil, Language, I18nPlural) {
+ "use strict";
+ parser = __importStar(parser);
+ StringUtil = __importStar(StringUtil);
+ Language = __importStar(Language);
+ I18nPlural = __importStar(I18nPlural);
+ // @todo: still required?
+ // work around bug in AMD module generation of Jison
+ /*function Parser() {
+ this.yy = {};
+ }
+
+ Parser.prototype = parser;
+ parser.Parser = Parser;
+ parser = new Parser();*/
+ /**
+ * Compiles the given template.
+ *
+ * @param {string} template Template to compile.
+ * @constructor
+ */
+ 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 (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);
+ }
+ catch (e) {
+ console.debug(e.message);
+ throw e;
+ }
+ }
+ /**
+ * Evaluates the Template using the given parameters.
+ *
+ * @param {object} v Parameters to pass to the template.
+ */
+ fetch(v) {
+ // this will be replaced in the init function
+ throw new Error('This Template is not initialized.');
+ }
+ }
+ Object.defineProperty(Template, 'callbacks', {
+ enumerable: false,
+ configurable: false,
+ get: function () {
+ throw new Error('WCF.Template.callbacks is no longer supported');
+ },
+ set: function (value) {
+ throw new Error('WCF.Template.callbacks is no longer supported');
+ },
+ });
+ return Template;
});
/**
* Provides data of the active user.
- *
- * @author Matthias Schmidt
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module User (alias)
- * @module WoltLabSuite/Core/User
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module User (alias)
+ * @module WoltLabSuite/Core/User
*/
-define([], function() {
- "use strict";
-
- var _didInit = false;
- var _link;
-
- /**
- * @exports WoltLabSuite/Core/User
- */
- return {
- /**
- * Returns the link to the active user's profile or an empty string
- * if the active user is a guest.
- *
- * @return {string}
- */
- getLink: function() {
- return _link;
- },
-
- /**
- * Initializes the user object.
- *
- * @param {int} userId id of the user, `0` for guests
- * @param {string} username name of the user, empty for guests
- * @param {string} userLink link to the user's profile, empty for guests
- */
- init: function(userId, username, userLink) {
- if (_didInit) {
- throw new Error('User has already been initialized.');
- }
-
- // define non-writeable properties for userId and username
- Object.defineProperty(this, 'userId', {
- value: userId,
- writable: false
- });
- Object.defineProperty(this, 'username', {
- value: username,
- writable: false
- });
-
- _link = userLink;
-
- _didInit = true;
- }
- };
+define(["require", "exports"], function (require, exports) {
+ "use strict";
+ let _link;
+ return {
+ /**
+ * Returns the link to the active user's profile or an empty string
+ * if the active user is a guest.
+ */
+ getLink: () => _link || '',
+ /**
+ * Initializes the user object.
+ */
+ init: (userId, username, link) => {
+ if (_link !== undefined) {
+ throw new Error('User has already been initialized.');
+ }
+ // define non-writeable properties for userId and username
+ Object.defineProperty(this, 'userId', {
+ value: userId,
+ writable: false,
+ });
+ Object.defineProperty(this, 'username', {
+ value: username,
+ writable: false,
+ });
+ _link = link || '';
+ },
+ };
});
--- /dev/null
+/**
+ * Helper functions to convert between different color formats.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module ColorUtil (alias)
+ * @module WoltLabSuite/Core/ColorUtil
+ */
+
+const ColorUtil = {
+ /**
+ * Converts a HSV color into RGB.
+ *
+ * @see https://secure.wikimedia.org/wikipedia/de/wiki/HSV-Farbraum#Transformation_von_RGB_und_HSV
+ */
+ hsvToRgb: (h: number, s: number, v: number): RGB => {
+ 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);
+ f = h / 60 - h2;
+
+ s /= 100;
+ v /= 100;
+
+ p = v * (1 - s);
+ q = v * (1 - s * f);
+ t = v * (1 - s * (1 - f));
+
+ if (s == 0) {
+ rgb.r = rgb.g = rgb.b = v;
+ } else {
+ switch (h2) {
+ case 1:
+ rgb.r = q;
+ rgb.g = v;
+ rgb.b = p;
+ break;
+
+ case 2:
+ rgb.r = p;
+ rgb.g = v;
+ rgb.b = t;
+ break;
+
+ case 3:
+ rgb.r = p;
+ rgb.g = q;
+ rgb.b = v;
+ break;
+
+ case 4:
+ rgb.r = t;
+ rgb.g = p;
+ rgb.b = v;
+ break;
+
+ case 5:
+ rgb.r = v;
+ rgb.g = p;
+ rgb.b = q;
+ break;
+
+ case 0:
+ case 6:
+ rgb.r = v;
+ rgb.g = t;
+ rgb.b = p;
+ break;
+ }
+ }
+
+ return {
+ r: Math.round(rgb.r * 255),
+ g: Math.round(rgb.g * 255),
+ b: Math.round(rgb.b * 255),
+ };
+ },
+
+ /**
+ * Converts a RGB color into HSV.
+ *
+ * @see https://secure.wikimedia.org/wikipedia/de/wiki/HSV-Farbraum#Transformation_von_RGB_und_HSV
+ */
+ rgbToHsv: (r: number, g: number, b: number): HSV => {
+ let h: number, s: number, v: number;
+ let max: number, min: number, diff: number;
+
+ r /= 255;
+ g /= 255;
+ b /= 255;
+
+ max = Math.max(Math.max(r, g), b);
+ min = Math.min(Math.min(r, g), b);
+ diff = max - min;
+
+ h = 0;
+ if (max !== min) {
+ switch (max) {
+ case r:
+ h = 60 * ((g - b) / diff);
+ break;
+
+ case g:
+ h = 60 * (2 + (b - r) / diff);
+ break;
+
+ case b:
+ h = 60 * (4 + (r - g) / diff);
+ break;
+ }
+
+ if (h < 0) {
+ h += 360;
+ }
+ }
+
+ if (max === 0) {
+ s = 0;
+ } else {
+ s = diff / max;
+ }
+
+ v = max;
+
+ return {
+ h: Math.round(h),
+ s: Math.round(s * 100),
+ v: Math.round(v * 100),
+ };
+ },
+
+ /**
+ * Converts HEX into RGB.
+ */
+ 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('');
+
+ // drop the hashtag
+ 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),
+ };
+ } else {
+ return {
+ r: parseInt(parts[0] + '' + parts[1], 16),
+ g: parseInt(parts[2] + '' + parts[3], 16),
+ b: parseInt(parts[4] + '' + parts[5], 16),
+ };
+ }
+ }
+
+ return Number.NaN;
+ },
+
+ /**
+ * Converts a RGB into HEX.
+ *
+ * @see http://www.linuxtopia.org/online_books/javascript_guides/javascript_faq/rgbtohex.htm
+ */
+ rgbToHex: (r: number, g: number, b: number): string => {
+ const charList = '0123456789ABCDEF';
+
+ if (g === undefined) {
+ if (r.toString().match(/^rgba?\((\d+), ?(\d+), ?(\d+)(?:, ?[0-9.]+)?\)$/)) {
+ r = +RegExp.$1;
+ g = +RegExp.$2;
+ 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));
+ },
+};
+
+interface RGB {
+ r: number;
+ g: number;
+ b: number;
+}
+
+interface HSV {
+ h: number;
+ s: number;
+ v: number;
+}
+
+// WCF.ColorPicker compatibility (color format conversion)
+window.__wcf_bc_colorUtil = ColorUtil;
+
+export = ColorUtil;
return newObj;
};
-//noinspection JSUnresolvedVariable
-const _prefix = 'wsc1337' + /*window.WCF_PATH.hashCode()*/ +'-';
+const _prefix = 'wsc' + window.WCF_PATH.hashCode() +'-';
/**
* Deep clones an object.
--- /dev/null
+/**
+ * Developer tools for WoltLab Suite.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module Devtools (alias)
+ * @module WoltLabSuite/Core/Devtools
+ */
+
+let _settings = {
+ editorAutosave: true,
+ eventLogging: false,
+};
+
+function _updateConfig() {
+ if (window.sessionStorage) {
+ window.sessionStorage.setItem('__wsc_devtools_config', JSON.stringify(_settings));
+ }
+}
+
+const Devtools = {
+ /**
+ * Prints the list of available commands.
+ */
+ help: (): void => {
+ 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)) {
+ commands.push(cmd);
+ }
+ }
+ commands.sort().forEach(function (cmd) {
+ window.console.log('\tDevtools.' + cmd + '()');
+ });
+
+ window.console.log('');
+ },
+
+ /**
+ * Disables/re-enables the editor autosave feature.
+ */
+ toggleEditorAutosave: (forceDisable: boolean): void => {
+ _settings.editorAutosave = forceDisable ? false : !_settings.editorAutosave;
+ _updateConfig();
+
+ window.console.log('%c\tEditor autosave ' + (_settings.editorAutosave ? 'enabled' : 'disabled'), 'font-style: italic');
+ },
+
+ /**
+ * Enables/disables logging for fired event listener events.
+ */
+ toggleEventLogging: function (forceEnable: boolean): void {
+ _settings.eventLogging = forceEnable ? true : !_settings.eventLogging;
+ _updateConfig();
+
+ window.console.log('%c\tEvent logging ' + (_settings.eventLogging ? 'enabled' : 'disabled'), 'font-style: italic');
+ },
+
+ /**
+ * Internal methods not meant to be called directly.
+ */
+ _internal_: {
+ enable: (): void => {
+ window.Devtools = Devtools;
+
+ window.console.log('%cDevtools for WoltLab Suite loaded', 'font-weight: bold');
+
+ if (window.sessionStorage) {
+ const settings = window.sessionStorage.getItem('__wsc_devtools_config');
+ try {
+ if (settings !== null) {
+ _settings = JSON.parse(settings);
+ }
+ } 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('');
+ },
+
+ editorAutosave: (): boolean => _settings.editorAutosave,
+
+ eventLog: (identifier: string, action: string): void => {
+ if (_settings.eventLogging) {
+ window.console.log('[Devtools.EventLogging] Firing event: ' + action + ' @ ' + identifier);
+ }
+ },
+ },
+};
+
+export = Devtools;
* Dictionary implementation relying on an object or if supported on a Map to hold key => value data.
*
* If you're looking for a dictionary with object keys, please see `WoltLabSuite/Core/ObjectMap`.
- *
+ *
* This is a legacy implementation, that does not implement all methods of `Map`, furthermore it has
* the side effect of converting all numeric keys to string values, treating 1 === "1".
*
/**
* Retrieves a value by key, returns undefined if there is no match.
*/
- get(key: number | string): any {
+ get(key: number | string): unknown {
return this._dictionary.get(key.toString());
}
* 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.');
+ }
+
this._dictionary.forEach(callback);
}
* All properties that are owned by the object will be added
* as keys to the resulting Dictionary.
*/
- static fromObject (object: object): Dictionary {
+ static fromObject(object: object): Dictionary {
const result = new Dictionary();
for (const key in object) {
return result;
}
-
+
get size(): number {
return this._dictionary.size;
}
--- /dev/null
+/**
+ * Provides basic details on the JavaScript environment.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module Environment (alias)
+ * @module WoltLabSuite/Core/Environment
+ */
+
+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') {
+ // this detects Opera as well, we could check for window.opr if we need to
+ _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) {
+ // 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';
+ }
+ }
+ }
+
+ const ua = window.navigator.userAgent.toLowerCase();
+ 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';
+ }
+
+ 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);
+
+ // The iPad Pro 12.9" masquerades as a desktop browser.
+ if (window.navigator.platform === 'MacIntel' && window.navigator.maxTouchPoints > 1) {
+ _browser = 'safari';
+ _platform = 'ios';
+ }
+}
+
+/**
+ * Returns the lower-case browser identifier.
+ *
+ * Possible values:
+ * - chrome: Chrome and Opera
+ * - firefox
+ * - microsoft: Internet Explorer and Microsoft Edge
+ * - safari
+ */
+export function browser(): string {
+ return _browser;
+}
+
+/**
+ * Returns the available editor's name or an empty string.
+ */
+export function editor(): string {
+ return _editor;
+}
+
+/**
+ * Returns the browser platform.
+ *
+ * Possible values:
+ * - desktop
+ * - android
+ * - ios: iPhone, iPad and iPod
+ * - windows: Windows on phones/tablets
+ */
+export function platform(): string {
+ return _platform;
+}
+
+/**
+ * Returns true if browser is potentially used with a touchscreen.
+ *
+ * Warning: Detecting touch is unreliable and should be avoided at all cost.
+ *
+ * @deprecated 3.0 - exists for backward-compatibility only, will be removed in the future
+ */
+export function touch(): boolean {
+ return _touch;
+}
--- /dev/null
+/**
+ * Provides helper functions for file handling.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/FileUtil
+ */
+
+import Dictionary from './Dictionary';
+import * as StringUtil from './StringUtil';
+
+
+const _fileExtensionIconMapping = Dictionary.fromObject({
+ // 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 = Dictionary.fromObject({
+ // 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.
+ */
+export function formatFilesize(byte: number, precision: number): string {
+ if (precision === undefined) {
+ precision = 2;
+ }
+
+ let symbol = 'Byte';
+ if (byte >= 1000) {
+ byte /= 1000;
+ symbol = 'kB';
+ }
+ if (byte >= 1000) {
+ byte /= 1000;
+ symbol = 'MB';
+ }
+ if (byte >= 1000) {
+ byte /= 1000;
+ symbol = 'GB';
+ }
+ if (byte >= 1000) {
+ byte /= 1000;
+ symbol = 'TB';
+ }
+
+ return StringUtil.formatNumeric(byte, -precision) + ' ' + symbol;
+}
+
+/**
+ * Returns the icon name for given filename.
+ *
+ * Note: For any file icon name like `fa-file-word`, only `word`
+ * will be returned by this method.
+ */
+export function getIconNameByFilename(filename: string): string {
+ const lastDotPosition = filename.lastIndexOf('.');
+ if (lastDotPosition !== -1) {
+ const extension = filename.substr(lastDotPosition + 1);
+
+ if (_fileExtensionIconMapping.has(extension)) {
+ return _fileExtensionIconMapping.get(extension) as string;
+ }
+ }
+
+ return '';
+}
+
+/**
+ * Returns a known file extension including a leading dot or an empty string.
+ */
+export function getExtensionByMimeType(mimetype: string): string {
+ if (_mimeTypeExtensionMapping.has(mimetype)) {
+ return '.' + _mimeTypeExtensionMapping.get(mimetype);
+ }
+
+ return '';
+}
+
+
+/**
+ * Constructs a File object from a Blob
+ *
+ * @param blob the blob to convert
+ * @param filename the filename
+ * @returns {File} the File object
+ */
+export function blobToFile(blob: Blob, filename: string): File {
+ const ext = this.getExtensionByMimeType(blob.type);
+
+ return new File([blob], filename + ext, {type: blob.type});
+}
--- /dev/null
+/**
+ * Generates plural phrases for the `plural` template plugin.
+ *
+ * @author Matthias Schmidt, Marcel Werk
+ * @copyright 2001-2020 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/I18n/Plural
+ */
+
+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 = {
+ /**
+ * Returns the plural category for the given value.
+ */
+ getCategory: function (value: number, languageCode?: string): string {
+ if (!languageCode) {
+ languageCode = document.documentElement.lang;
+ }
+
+ // Fallback: handle unknown languages as English
+ if (typeof this[languageCode] !== 'function') {
+ languageCode = 'en';
+ }
+
+ const category = this[languageCode](value);
+ if (category) {
+ return category;
+ }
+
+ return PLURAL_OTHER;
+ },
+
+ /**
+ * Returns the value for a `plural` element used in the template.
+ *
+ * @see wcf\system\template\plugin\PluralFunctionTemplatePlugin::execute()
+ */
+ getCategoryFromTemplateParameters: function (parameters: object): string {
+ if (!parameters['value']) {
+ throw new Error('Missing parameter value');
+ }
+ if (!parameters['other']) {
+ throw new Error('Missing parameter other');
+ }
+
+ let value = parameters['value'];
+ if (Array.isArray(value)) {
+ value = value.length;
+ }
+
+ // handle numeric attributes
+ for (const key in parameters) {
+ if (parameters.hasOwnProperty(key) && key.toString() === (~~key).toString() && key == value) {
+ return parameters[key];
+ }
+ }
+
+ let category = this.getCategory(value);
+ if (!parameters[category]) {
+ category = PLURAL_OTHER;
+ }
+
+ const string = parameters[category];
+ if (string.indexOf('#') !== -1) {
+ return string.replace('#', StringUtil.formatNumeric(value));
+ }
+
+ return string;
+ },
+
+ /**
+ * `f` is the fractional number as a whole number (1.234 yields 234)
+ */
+ getF: function (n: number): number {
+ const tmp = n.toString();
+ const pos = tmp.indexOf('.');
+ if (pos === -1) {
+ return 0;
+ }
+
+ return parseInt(tmp.substr(pos + 1), 10);
+ },
+
+ /**
+ * `v` represents the number of digits of the fractional part (1.234 yields 3)
+ */
+ getV: function (n: number): number {
+ return n.toString().replace(/^[^.]*\.?/, '').length;
+ },
+
+ // Afrikaans
+ af: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Amharic
+ am: function (n: number): string | undefined {
+ const i = Math.floor(Math.abs(n));
+ if (n == 1 || i === 0) return PLURAL_ONE;
+ },
+
+ // Arabic
+ ar: function (n: number): string | undefined {
+ if (n == 0) return PLURAL_ZERO;
+ if (n == 1) return PLURAL_ONE;
+ if (n == 2) return PLURAL_TWO;
+
+ const mod100 = n % 100;
+ if (mod100 >= 3 && mod100 <= 10) return PLURAL_FEW;
+ if (mod100 >= 11 && mod100 <= 99) return PLURAL_MANY;
+ },
+
+ // Assamese
+ as: function (n: number): string | undefined {
+ const i = Math.floor(Math.abs(n));
+ if (n == 1 || i === 0) return PLURAL_ONE;
+ },
+
+ // Azerbaijani
+ az: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Belarusian
+ be: function (n: number): string | undefined {
+ const mod10 = n % 10;
+ const mod100 = n % 100;
+
+ if (mod10 == 1 && mod100 != 11) return PLURAL_ONE;
+ if (mod10 >= 2 && mod10 <= 4 && !(mod100 >= 12 && mod100 <= 14)) return PLURAL_FEW;
+ if (mod10 == 0 || (mod10 >= 5 && mod10 <= 9) || (mod100 >= 11 && mod100 <= 14)) return PLURAL_MANY;
+ },
+
+ // Bulgarian
+ bg: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Bengali
+ bn: function (n: number): string | undefined {
+ const i = Math.floor(Math.abs(n));
+ if (n == 1 || i === 0) return PLURAL_ONE;
+ },
+
+ // Tibetan
+ bo: function (n: number) {
+ },
+
+ // Bosnian
+ bs: function (n: number): string | undefined {
+ const v = this.getV(n);
+ const f = this.getF(n);
+ const mod10 = n % 10;
+ const mod100 = n % 100;
+ const fMod10 = f % 10;
+ 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;
+ },
+
+ // Czech
+ cs: function (n: number): string | undefined {
+ const v = this.getV(n);
+
+ if (n == 1 && v === 0) return PLURAL_ONE;
+ if (n >= 2 && n <= 4 && v === 0) return PLURAL_FEW;
+ if (v === 0) return PLURAL_MANY;
+ },
+
+ // Welsh
+ cy: function (n: number): string | undefined {
+ if (n == 0) return PLURAL_ZERO;
+ if (n == 1) return PLURAL_ONE;
+ if (n == 2) return PLURAL_TWO;
+ if (n == 3) return PLURAL_FEW;
+ if (n == 6) return PLURAL_MANY;
+ },
+
+ // Danish
+ da: function (n: number): string | undefined {
+ if (n > 0 && n < 2) return PLURAL_ONE;
+ },
+
+ // Greek
+ el: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Catalan (ca)
+ // German (de)
+ // English (en)
+ // Estonian (et)
+ // Finnish (fi)
+ // Italian (it)
+ // Dutch (nl)
+ // Swedish (sv)
+ // Swahili (sw)
+ // Urdu (ur)
+ en: function (n: number): string | undefined {
+ if (n == 1 && this.getV(n) === 0) return PLURAL_ONE;
+ },
+
+ // Spanish
+ es: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Basque
+ eu: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Persian
+ fa: function (n: number): string | undefined {
+ if (n >= 0 && n <= 1) return PLURAL_ONE;
+ },
+
+ // French
+ fr: function (n: number): string | undefined {
+ if (n >= 0 && n < 2) return PLURAL_ONE;
+ },
+
+ // Irish
+ ga: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ if (n == 2) return PLURAL_TWO;
+ if (n == 3 || n == 4 || n == 5 || n == 6) return PLURAL_FEW;
+ if (n == 7 || n == 8 || n == 9 || n == 10) return PLURAL_MANY;
+ },
+
+ // Gujarati
+ gu: function (n: number): string | undefined {
+ if (n >= 0 && n <= 1) return PLURAL_ONE;
+ },
+
+ // Hebrew
+ he: function (n: number): string | undefined {
+ const v = this.getV(n);
+
+ if (n == 1 && v === 0) return PLURAL_ONE;
+ if (n == 2 && v === 0) return PLURAL_TWO;
+ if (n > 10 && v === 0 && n % 10 == 0) return PLURAL_MANY;
+ },
+
+ // Hindi
+ hi: function (n: number): string | undefined {
+ if (n >= 0 && n <= 1) return PLURAL_ONE;
+ },
+
+ // Croatian
+ hr: function (n: number): string | undefined {
+ // same as Bosnian
+ return this.bs(n);
+ },
+
+ // Hungarian
+ hu: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Armenian
+ hy: function (n: number): string | undefined {
+ if (n >= 0 && n < 2) return PLURAL_ONE;
+ },
+
+ // Indonesian
+ id: function (n: number) {
+ },
+
+ // Icelandic
+ is: function (n: number): string | undefined {
+ const f = this.getF(n);
+
+ if (f === 0 && n % 10 === 1 && !(n % 100 === 11) || !(f === 0)) return PLURAL_ONE;
+ },
+
+ // Japanese
+ ja: function (n: number) {
+ },
+
+ // Javanese
+ jv: function (n: number) {
+ },
+
+ // Georgian
+ ka: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Kazakh
+ kk: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Khmer
+ km: function (n: number) {
+ },
+
+ // Kannada
+ kn: function (n: number): string | undefined {
+ if (n >= 0 && n <= 1) return PLURAL_ONE;
+ },
+
+ // Korean
+ ko: function (n: number) {
+ },
+
+ // Kurdish
+ ku: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Kyrgyz
+ ky: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Luxembourgish
+ lb: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Lao
+ lo: function (n: number) {
+ },
+
+ // Lithuanian
+ lt: function (n: number): string | undefined {
+ const mod10 = n % 10;
+ const mod100 = n % 100;
+
+ if (mod10 == 1 && !(mod100 >= 11 && mod100 <= 19)) return PLURAL_ONE;
+ if (mod10 >= 2 && mod10 <= 9 && !(mod100 >= 11 && mod100 <= 19)) return PLURAL_FEW;
+ if (this.getF(n) != 0) return PLURAL_MANY;
+ },
+
+ // Latvian
+ lv: function (n: number): string | undefined {
+ const mod10 = n % 10;
+ const mod100 = n % 100;
+ const v = this.getV(n);
+ const f = this.getF(n);
+ const fMod10 = f % 10;
+ 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;
+ },
+
+ // Macedonian
+ mk: function (n: number): string | undefined {
+ return this.bs(n);
+ },
+
+ // Malayalam
+ ml: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Mongolian
+ mn: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Marathi
+ mr: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Malay
+ ms: function (n: number) {
+ },
+
+ // Maltese
+ mt: function (n: number): string | undefined {
+ const mod100 = n % 100;
+
+ if (n == 1) return PLURAL_ONE;
+ if (n == 0 || (mod100 >= 2 && mod100 <= 10)) return PLURAL_FEW;
+ if (mod100 >= 11 && mod100 <= 19) return PLURAL_MANY;
+ },
+
+ // Burmese
+ my: function (n: number) {
+ },
+
+ // Norwegian
+ no: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Nepali
+ ne: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Odia
+ or: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Punjabi
+ pa: function (n: number): string | undefined {
+ if (n == 1 || n == 0) return PLURAL_ONE;
+ },
+
+ // Polish
+ pl: function (n: number): string | undefined {
+ const v = this.getV(n);
+ const mod10 = n % 10;
+ const mod100 = n % 100;
+
+ 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;
+ },
+
+ // Pashto
+ ps: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Portuguese
+ pt: function (n: number): string | undefined {
+ if (n >= 0 && n < 2) return PLURAL_ONE;
+ },
+
+ // Romanian
+ ro: function (n: number): string | undefined {
+ const v = this.getV(n);
+ const mod100 = n % 100;
+
+ if (n == 1 && v === 0) return PLURAL_ONE;
+ if (v != 0 || n == 0 || (mod100 >= 2 && mod100 <= 19)) return PLURAL_FEW;
+ },
+
+ // Russian
+ ru: function (n: number): string | undefined {
+ const mod10 = n % 10;
+ const mod100 = n % 100;
+
+ if (this.getV(n) == 0) {
+ if (mod10 == 1 && mod100 != 11) return PLURAL_ONE;
+ if (mod10 >= 2 && mod10 <= 4 && !(mod100 >= 12 && mod100 <= 14)) return PLURAL_FEW;
+ if (mod10 == 0 || (mod10 >= 5 && mod10 <= 9) || (mod100 >= 11 && mod100 <= 14)) return PLURAL_MANY;
+ }
+ },
+
+ // Sindhi
+ sd: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Sinhala
+ si: function (n: number): string | undefined {
+ if (n == 0 || n == 1 || (Math.floor(n) == 0 && this.getF(n) == 1)) return PLURAL_ONE;
+ },
+
+ // Slovak
+ sk: function (n: number): string | undefined {
+ // same as Czech
+ return this.cs(n);
+ },
+
+ // Slovenian
+ sl: function (n: number): string | undefined {
+ const v = this.getV(n);
+ const mod100 = n % 100;
+
+ if (v == 0 && mod100 == 1) return PLURAL_ONE;
+ if (v == 0 && mod100 == 2) return PLURAL_TWO;
+ if ((v == 0 && (mod100 == 3 || mod100 == 4)) || v != 0) return PLURAL_FEW;
+ },
+
+ // Albanian
+ sq: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Serbian
+ sr: function (n: number): string | undefined {
+ // same as Bosnian
+ return this.bs(n);
+ },
+
+ // Tamil
+ ta: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Telugu
+ te: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Tajik
+ tg: function (n: number) {
+ },
+
+ // Thai
+ th: function (n: number) {
+ },
+
+ // Turkmen
+ tk: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Turkish
+ tr: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Uyghur
+ ug: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Ukrainian
+ uk: function (n: number): string | undefined {
+ // same as Russian
+ return this.ru(n);
+ },
+
+ // Uzbek
+ uz: function (n: number): string | undefined {
+ if (n == 1) return PLURAL_ONE;
+ },
+
+ // Vietnamese
+ vi: function (n: number) {
+ },
+
+ // Chinese
+ zh: function (n: number) {
+ },
+};
+
+export = Plural
--- /dev/null
+/**
+ * Manages language items.
+ *
+ * @author Tim Duesterhus
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module Language (alias)
+ * @module WoltLabSuite/Core/Language
+ */
+import Dictionary from './Dictionary';
+import Template from './Template';
+
+const _languageItems = new Dictionary();
+
+/**
+ * Adds all the language items in the given object to the store.
+ */
+export function addObject(object: object): void {
+ _languageItems.merge(Dictionary.fromObject(object));
+}
+
+/**
+ * Adds a single language item to the store.
+ */
+export function add(key: string, value: string): void {
+ _languageItems.set(key, value);
+}
+
+/**
+ * Fetches the language item specified by the given key.
+ * If the language item is a string it will be evaluated as
+ * WoltLabSuite/Core/Template with the given parameters.
+ *
+ * @param {string} key Language item to return.
+ * @param {Object=} parameters Parameters to provide to WoltLabSuite/Core/Template.
+ * @return {string}
+ */
+export function get(key: string, parameters?: object): string {
+ let value = _languageItems.get(key);
+ if (value === undefined) {
+ return key;
+ }
+
+ // fetch Template, as it cannot be provided because of a circular dependency
+ if (Template === undefined) { //@ts-ignore
+ Template = require('./Template');
+ }
+
+ 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}'));
+ }
+ value = _languageItems.get(key);
+ }
+
+ if (value instanceof Template) {
+ value = (value as Template).fetch(parameters || {});
+ }
+
+ return value as string;
+}
--- /dev/null
+/**
+ * List implementation relying on an array or if supported on a Set to hold values.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module List (alias)
+ * @module WoltLabSuite/Core/List
+ */
+/**
+ * @constructor
+ */
+class List {
+ private _set = new Set<any>();
+
+ /**
+ * Appends an element to the list, silently rejects adding an already existing value.
+ */
+ add(value: any): void {
+ this._set.add(value);
+ }
+
+ /**
+ * Removes all elements from the list.
+ */
+ clear(): void {
+ this._set.clear();
+ }
+
+ /**
+ * Removes an element from the list, returns true if the element was in the list.
+ */
+ delete(value: any): boolean {
+ return this._set.delete(value);
+ }
+
+ /**
+ * Invokes the `callback` for each element in the list.
+ */
+ forEach(callback: (value: any) => void): void {
+ this._set.forEach(callback);
+ }
+
+ /**
+ * Returns true if the list contains the element.
+ */
+ has(value: any): boolean {
+ return this._set.has(value);
+ }
+
+ get size(): number {
+ return this._set.size;
+ }
+}
+
+export = List;
--- /dev/null
+/**
+ * Provides helper functions for Number handling.
+ *
+ * @author Tim Duesterhus
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/NumberUtil
+ */
+
+/**
+ * Decimal adjustment of a number.
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
+ */
+export function round(value: number, exp: number): number {
+ // If the exp is undefined or zero...
+ 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)) {
+ return NaN;
+ }
+
+ // Shift
+ 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));
+}
+
--- /dev/null
+/**
+ * Simple `object` to `object` map using a WeakMap.
+ *
+ * If you're looking for a dictionary with string keys, please see `WoltLabSuite/Core/Dictionary`.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module ObjectMap (alias)
+ * @module WoltLabSuite/Core/ObjectMap
+ */
+
+class ObjectMap {
+ private _map = new WeakMap<object, object>();
+
+ /**
+ * 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 value !== 'object' || value === null) {
+ throw new TypeError('Only objects can be used as value');
+ }
+
+ this._map.set(key, value);
+ }
+
+ /**
+ * Removes a key from the map.
+ */
+ delete(key: object): void {
+ this._map.delete(key);
+
+ }
+
+ /**
+ * Returns true if dictionary contains a value for given key.
+ */
+ has(key: object): boolean {
+ return this._map.has(key);
+ }
+
+
+ /**
+ * Retrieves a value by key, returns undefined if there is no match.
+ */
+ get(key: object): object | undefined {
+ return this._map.get(key);
+ }
+}
+
+export = ObjectMap
--- /dev/null
+/**
+ * Manages user permissions.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module Permission (alias)
+ * @module WoltLabSuite/Core/Permission
+ */
+
+const _permissions = new Map<string, boolean>();
+
+/**
+ * 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.');
+ }
+
+ _permissions.set(permission, value);
+}
+
+/**
+ * Adds all the permissions in the given object to the store.
+ */
+export function addObject(object: PermissionObject): void {
+ for (const key in object) {
+ if (object.hasOwnProperty(key)) {
+
+ this.add(key, object[key]);
+ }
+ }
+}
+
+
+/**
+ * Returns the value of a permission.
+ *
+ * If the permission is unknown, false is returned.
+ */
+export function get(permission: string): boolean {
+ if (_permissions.has(permission)) {
+ return _permissions.get(permission)!;
+ }
+
+ return false;
+}
+
+interface PermissionObject {
+ [key: string]: boolean;
+}
--- /dev/null
+/**
+ * Provides helper functions for String handling.
+ *
+ * @author Tim Duesterhus, Joshua Ruesweg
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module StringUtil (alias)
+ * @module WoltLabSuite/Core/StringUtil
+ */
+import * as Language from './Language';
+import * as NumberUtil from './NumberUtil';
+
+/**
+ * Adds thousands separators to a given number.
+ *
+ * @see http://stackoverflow.com/a/6502556/782822
+ */
+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');
+ }
+
+ 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, '>');
+}
+
+/**
+ * Escapes a String to work with RegExp.
+ *
+ * @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');
+}
+
+/**
+ * Rounds number to given count of floating point digits, localizes decimal-point and inserts thousands separators.
+ */
+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');
+ }
+
+ let tmp = NumberUtil.round(number, decimalPlaces || -2).toString();
+ const numberParts = tmp.split('.');
+
+ tmp = this.addThousandsSeparator(+numberParts[0]);
+ if (numberParts.length > 1) tmp += Language.get('wcf.global.decimalPoint') + numberParts[1];
+
+ tmp = tmp.replace('-', '\u2212');
+
+ return tmp;
+}
+
+/**
+ * Makes a string's first character lowercase.
+ */
+export function lcfirst(string: string): string {
+ return String(string).substring(0, 1).toLowerCase() + string.substring(1);
+}
+
+/**
+ * Makes a string's first character uppercase.
+ */
+export function ucfirst(string: string): string {
+ return String(string).substring(0, 1).toUpperCase() + string.substring(1);
+}
+
+/**
+ * Unescapes special HTML-characters within a string.
+ */
+export function unescapeHTML(string: string): string {
+ 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 = '';
+
+ if (number >= 1000000) {
+ number /= 1000000;
+
+ if (number > 10) {
+ number = Math.floor(number);
+ } else {
+ number = NumberUtil.round(number, -1);
+ }
+
+ unitSuffix = 'M';
+ } else if (number >= 1000) {
+ number /= 1000;
+
+ if (number > 10) {
+ number = Math.floor(number);
+ } else {
+ number = NumberUtil.round(number, -1);
+ }
+
+ unitSuffix = 'k';
+ }
+
+ return this.formatNumeric(number) + unitSuffix;
+}
--- /dev/null
+export function parse(input: string): unknown;
--- /dev/null
+/**
+ * WoltLabSuite/Core/Template provides a template scripting compiler similar
+ * to the PHP one of WoltLab Suite Core. It supports a limited
+ * set of useful commands and compiles templates down to a pure
+ * JavaScript Function.
+ *
+ * @author Tim Duesterhus
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @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';
+
+// @todo: still required?
+// work around bug in AMD module generation of Jison
+/*function Parser() {
+ this.yy = {};
+}
+
+Parser.prototype = parser;
+parser.Parser = Parser;
+parser = new Parser();*/
+
+/**
+ * Compiles the given template.
+ *
+ * @param {string} template Template to compile.
+ * @constructor
+ */
+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 (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;
+
+ this.fetch = new Function('StringUtil', 'Language', 'I18nPlural', 'v', template).bind(undefined, StringUtil, Language, I18nPlural);
+ } catch (e) {
+ console.debug(e.message);
+ throw e;
+ }
+ }
+
+ /**
+ * Evaluates the Template using the given parameters.
+ *
+ * @param {object} v Parameters to pass to the template.
+ */
+ fetch(v: object): string {
+ // this will be replaced in the init function
+ throw new Error('This Template is not initialized.');
+ }
+}
+
+Object.defineProperty(Template, 'callbacks', {
+ enumerable: false,
+ configurable: false,
+ get: function () {
+ throw new Error('WCF.Template.callbacks is no longer supported');
+ },
+ set: function (value) {
+ throw new Error('WCF.Template.callbacks is no longer supported');
+ },
+});
+
+export = Template;
--- /dev/null
+/**
+ * Provides data of the active user.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module User (alias)
+ * @module WoltLabSuite/Core/User
+ */
+
+let _link: string | undefined;
+
+export = {
+ /**
+ * Returns the link to the active user's profile or an empty string
+ * if the active user is a guest.
+ */
+ getLink: (): string => _link || '',
+
+ /**
+ * Initializes the user object.
+ */
+ init: (userId: number, username: string, link: string): void => {
+ if (_link !== undefined) {
+ throw new Error('User has already been initialized.');
+ }
+
+ // define non-writeable properties for userId and username
+ Object.defineProperty(this, 'userId', {
+ value: userId,
+ writable: false,
+ });
+ Object.defineProperty(this, 'username', {
+ value: username,
+ writable: false,
+ });
+
+ _link = link || '';
+ },
+}