2 * Provides the basic core functionality.
4 * @author Alexander Ebert
5 * @copyright 2001-2019 WoltLab GmbH
6 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
8 define(["require", "exports"], function (require
, exports
) {
10 Object
.defineProperty(exports
, "__esModule", { value
: true });
11 exports
.clone
= clone
;
12 exports
.convertLegacyUrl
= convertLegacyUrl
;
13 exports
.extend
= extend
;
14 exports
.inherit
= inherit
;
15 exports
.isPlainObject
= isPlainObject
;
16 exports
.getType
= getType
;
17 exports
.getUuid
= getUuid
;
18 exports
.serialize
= serialize
;
19 exports
.triggerEvent
= triggerEvent
;
20 exports
.getStoragePrefix
= getStoragePrefix
;
21 exports
.stringToBool
= stringToBool
;
22 exports
.debounce
= debounce
;
23 exports
.enableLegacyInheritance
= enableLegacyInheritance
;
24 exports
.getXsrfToken
= getXsrfToken
;
25 const _clone = function (variable
) {
26 if (typeof variable
=== "object" && (Array
.isArray(variable
) || isPlainObject(variable
))) {
27 return _cloneObject(variable
);
31 const _cloneObject = function (obj
) {
35 if (Array
.isArray(obj
)) {
39 Object
.keys(obj
).forEach((key
) => (newObj
[key
] = _clone(obj
[key
])));
42 const _prefix
= "wsc" + window
.WCF_PATH
.hashCode() + "-";
44 * Deep clones an object.
50 * Converts WCF 2.0-style URLs into the default URL layout.
52 function convertLegacyUrl(url
) {
53 return url
.replace(/^index\.php\/(.*?)\/\?/, (match
, controller
) => {
54 const parts
= controller
.split(/([A-Z][a-z0-9]+)/);
56 for (let i
= 0, length
= parts
.length
; i
< length
; i
++) {
57 const part
= parts
[i
].trim();
59 if (controller
.length
) {
62 controller
+= part
.toLowerCase();
65 return `index.php?${controller}/&`;
69 * Merges objects with the first argument.
71 * @param {object} out destination object
72 * @param {...object} args variable number of objects to be merged into the destination object
73 * @return {object} destination object with all provided objects merged into
75 function extend(out
, ...args
) {
77 const newObj
= clone(out
);
78 for (let i
= 0, length
= args
.length
; i
< length
; i
++) {
83 Object
.keys(obj
).forEach((key
) => {
84 if (!Array
.isArray(obj
[key
]) && typeof obj
[key
] === "object") {
85 if (isPlainObject(obj
[key
])) {
86 // object literals have the prototype of Object which in return has no parent prototype
87 newObj
[key
] = extend(out
[key
], obj
[key
]);
90 newObj
[key
] = obj
[key
];
94 newObj
[key
] = obj
[key
];
101 * Inherits the prototype methods from one constructor to another
106 * function MyDerivedClass() {}
107 * Core.inherit(MyDerivedClass, TheAwesomeBaseClass, {
108 * // regular prototype for `MyDerivedClass`
110 * overwrittenMethodFromBaseClass: function(foo, bar) {
114 * MyDerivedClass._super.prototype.overwrittenMethodFromBaseClass.call(this, foo, bar);
118 * @see https://github.com/nodejs/node/blob/7d14dd9b5e78faabb95d454a79faa513d0bbc2a5/lib/util.js#L697-L735
119 * @deprecated 5.4 Use the native `class` and `extends` keywords instead.
121 function inherit(constructor, superConstructor
, propertiesObject
) {
122 if (constructor === undefined || constructor === null) {
123 throw new TypeError("The constructor must not be undefined or null.");
125 if (superConstructor
=== undefined || superConstructor
=== null) {
126 throw new TypeError("The super constructor must not be undefined or null.");
128 if (superConstructor
.prototype === undefined) {
129 throw new TypeError("The super constructor must have a prototype.");
131 constructor._super
= superConstructor
;
132 constructor.prototype = extend(Object
.create(superConstructor
.prototype, {
139 }), propertiesObject
|| {});
142 * Returns true if `obj` is an object literal.
144 function isPlainObject(obj
) {
145 if (typeof obj
!== "object" || obj
=== null) {
148 return Object
.getPrototypeOf(obj
) === Object
.prototype;
151 * Returns the object's class name.
153 function getType(obj
) {
154 return Object
.prototype.toString
.call(obj
).replace(/^\[object (.+)]$/, "$1");
157 * Returns a RFC4122 version 4 compilant UUID.
159 * @see http://stackoverflow.com/a/2117523
162 return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c
) => {
163 const r
= (Math
.random() * 16) | 0, v
= c
== "x" ? r
: (r
& 0x3) | 0x8;
164 return v
.toString(16);
168 * Recursively serializes an object into an encoded URI parameter string.
170 function serialize(obj
, prefix
) {
174 const parameters
= [];
175 Object
.keys(obj
).forEach((key
) => {
176 const parameterKey
= prefix
? prefix
+ "[" + key
+ "]" : key
;
177 const value
= obj
[key
];
178 if (typeof value
=== "object") {
179 parameters
.push(serialize(value
, parameterKey
));
182 parameters
.push(encodeURIComponent(parameterKey
) + "=" + encodeURIComponent(value
));
185 return parameters
.join("&");
188 * Triggers a custom or built-in event.
190 function triggerEvent(element
, eventName
) {
191 if (eventName
=== "click" && element
instanceof HTMLElement
) {
195 const event
= new Event(eventName
, {
199 element
.dispatchEvent(event
);
202 * Returns the unique prefix for the localStorage.
204 function getStoragePrefix() {
208 * Interprets a string value as a boolean value similar to the behavior of the
209 * legacy functions `elAttrBool()` and `elDataBool()`.
211 function stringToBool(value
) {
212 return value
=== "1" || value
=== "true";
215 * A function that emits a side effect and does not return anything.
217 * @see https://github.com/chodorowicz/ts-debounce/blob/62f30f2c3379b7b5e778fb1793e1fbfa17354894/src/index.ts
219 function debounce(func
, waitMilliseconds
= 50, options
= {
223 return function (...args
) {
224 const doLater
= () => {
225 timeoutId
= undefined;
226 if (!options
.isImmediate
) {
227 func
.apply(this, args
);
230 const shouldCallNow
= options
.isImmediate
&& timeoutId
=== undefined;
231 if (timeoutId
!== undefined) {
232 clearTimeout(timeoutId
);
234 timeoutId
= setTimeout(doLater
, waitMilliseconds
);
236 func
.apply(this, args
);
243 function enableLegacyInheritance(legacyClass
) {
244 // This MUST NOT be an error to prevent bricking installations during the upgrade.
245 console
.error("Relying on the legacy inheritance is no longer supported. Please migrate your code to use ES6 classes and inheritance.", legacyClass
);
247 function getXsrfToken() {
248 const cookies
= document
.cookie
.split(";").map((c
) => c
.trim());
249 const xsrfToken
= cookies
.find((c
) => c
.startsWith("XSRF-TOKEN="));
250 if (xsrfToken
=== undefined) {
251 return "COOKIE_NOT_FOUND";
253 const [_key
, value
] = xsrfToken
.split(/=/, 2);
254 return decodeURIComponent(value
.trim());