Add content selection before removing content
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / js / WoltLabSuite / Core / Core.js
CommitLineData
4bbf6ff1
AE
1/**
2 * Provides the basic core functionality.
3 *
4 * @author Alexander Ebert
c839bd49 5 * @copyright 2001-2018 WoltLab GmbH
4bbf6ff1 6 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
58d7e8f8 7 * @module WoltLabSuite/Core/Core
4bbf6ff1 8 */
a3a09eff 9define([], function() {
565853e8
TD
10 "use strict";
11
b5a32d79 12 var _clone = function(variable) {
cb57f345 13 if (typeof variable === 'object' && (Array.isArray(variable) || Core.isPlainObject(variable))) {
b5a32d79
AE
14 return _cloneObject(variable);
15 }
16
17 return variable;
18 };
19
b5a32d79
AE
20 var _cloneObject = function(obj) {
21 if (!obj) {
22 return null;
23 }
24
25 if (Array.isArray(obj)) {
cb57f345 26 return obj.slice();
b5a32d79
AE
27 }
28
29 var newObj = {};
30 for (var key in obj) {
0e69f27c 31 if (obj.hasOwnProperty(key) && typeof obj[key] !== 'undefined') {
b5a32d79
AE
32 newObj[key] = _clone(obj[key]);
33 }
34 }
35
36 return newObj;
37 };
38
0e69f27c
AE
39 //noinspection JSUnresolvedVariable
40 var _prefix = 'wsc' + window.WCF_PATH.hashCode() + '-';
41
4bbf6ff1 42 /**
58d7e8f8 43 * @exports WoltLabSuite/Core/Core
4bbf6ff1 44 */
bc8cd0ff 45 var Core = {
b5a32d79
AE
46 /**
47 * Deep clones an object.
48 *
49 * @param {object} obj source object
50 * @return {object} cloned object
51 */
52 clone: function(obj) {
53 return _clone(obj);
54 },
55
827a69f3
AE
56 /**
57 * Converts WCF 2.0-style URLs into the default URL layout.
58 *
59 * @param string url target url
60 * @return rewritten url
61 */
62 convertLegacyUrl: function(url) {
827a69f3 63 return url.replace(/^index\.php\/(.*?)\/\?/, function(match, controller) {
bd969ed4 64 var parts = controller.split(/([A-Z][a-z0-9]+)/);
f0115fd9 65 controller = '';
bd969ed4
AE
66 for (var i = 0, length = parts.length; i < length; i++) {
67 var part = parts[i].trim();
68 if (part.length) {
69 if (controller.length) controller += '-';
70 controller += part.toLowerCase();
827a69f3
AE
71 }
72 }
73
bd969ed4 74 return 'index.php?' + controller + '/&';
827a69f3
AE
75 });
76 },
77
4bbf6ff1
AE
78 /**
79 * Merges objects with the first argument.
80 *
81 * @param {object} out destination object
82 * @param {...object} arguments variable number of objects to be merged into the destination object
83 * @return {object} destination object with all provided objects merged into
84 */
85 extend: function(out) {
86 out = out || {};
15a48bb3 87 var newObj = this.clone(out);
4bbf6ff1
AE
88
89 for (var i = 1, length = arguments.length; i < length; i++) {
90 var obj = arguments[i];
91
92 if (!obj) continue;
93
94 for (var key in obj) {
f5336f4f 95 if (objOwns(obj, key)) {
827a69f3 96 if (!Array.isArray(obj[key]) && typeof obj[key] === 'object') {
15a48bb3
AE
97 if (this.isPlainObject(obj[key])) {
98 // object literals have the prototype of Object which in return has no parent prototype
99 newObj[key] = this.extend(out[key], obj[key]);
100 }
101 else {
102 newObj[key] = obj[key];
103 }
4bbf6ff1
AE
104 }
105 else {
15a48bb3 106 newObj[key] = obj[key];
4bbf6ff1
AE
107 }
108 }
109 }
110 }
111
15a48bb3
AE
112 return newObj;
113 },
114
0de17700
MS
115 /**
116 * Inherits the prototype methods from one constructor to another
117 * constructor.
118 *
3696feff
AE
119 * Usage:
120 *
121 * function MyDerivedClass() {}
122 * Core.inherit(MyDerivedClass, TheAwesomeBaseClass, {
123 * // regular prototype for `MyDerivedClass`
124 *
125 * overwrittenMethodFromBaseClass: function(foo, bar) {
126 * // do stuff
127 *
128 * // invoke parent
129 * MyDerivedClass._super.prototype.overwrittenMethodFromBaseClass.call(this, foo, bar);
130 * }
131 * });
132 *
0de17700
MS
133 * @see https://github.com/nodejs/node/blob/7d14dd9b5e78faabb95d454a79faa513d0bbc2a5/lib/util.js#L697-L735
134 * @param {function} constructor inheriting constructor function
135 * @param {function} superConstructor inherited constructor function
136 * @param {object=} propertiesObject additional prototype properties
137 */
138 inherit: function(constructor, superConstructor, propertiesObject) {
139 if (constructor === undefined || constructor === null) {
140 throw new TypeError("The constructor must not be undefined or null.");
141 }
142 if (superConstructor === undefined || superConstructor === null) {
143 throw new TypeError("The super constructor must not be undefined or null.");
144 }
145 if (superConstructor.prototype === undefined) {
146 throw new TypeError("The super constructor must have a prototype.");
147 }
148
149 constructor._super = superConstructor;
150 constructor.prototype = Core.extend(Object.create(superConstructor.prototype, {
151 constructor: {
152 configurable: true,
153 enumerable: false,
154 value: constructor,
3b083558 155 writable: true
0de17700
MS
156 }
157 }), propertiesObject || {});
158 },
159
15a48bb3
AE
160 /**
161 * Returns true if `obj` is an object literal.
162 *
163 * @param {*} obj target object
164 * @returns {boolean} true if target is an object literal
165 */
166 isPlainObject: function(obj) {
87d33e2c 167 if (typeof obj !== 'object' || obj === null || obj.nodeType) {
15a48bb3
AE
168 return false;
169 }
170
87d33e2c 171 return (Object.getPrototypeOf(obj) === Object.prototype);
4bbf6ff1
AE
172 },
173
827a69f3
AE
174 /**
175 * Returns the object's class name.
176 *
177 * @param {object} obj target object
178 * @return {string} object class name
179 */
180 getType: function(obj) {
181 return Object.prototype.toString.call(obj).replace(/^\[object (.+)\]$/, '$1');
182 },
183
600d580f
TD
184 /**
185 * Returns a RFC4122 version 4 compilant UUID.
186 *
187 * @see http://stackoverflow.com/a/2117523
188 * @return {string}
189 */
34ec14c8 190 getUuid: function() {
600d580f
TD
191 return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
192 var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
193 return v.toString(16);
194 });
195 },
196
827a69f3
AE
197 /**
198 * Recursively serializes an object into an encoded URI parameter string.
199 *
200 * @param {object} obj target object
15a48bb3 201 * @param {string=} prefix parameter prefix
0e69f27c 202 * @return {string} encoded parameter string
827a69f3 203 */
15a48bb3 204 serialize: function(obj, prefix) {
827a69f3
AE
205 var parameters = [];
206
207 for (var key in obj) {
f5336f4f 208 if (objOwns(obj, key)) {
15a48bb3 209 var parameterKey = (prefix) ? prefix + '[' + key + ']' : key;
827a69f3
AE
210 var value = obj[key];
211
15a48bb3
AE
212 if (typeof value === 'object') {
213 parameters.push(this.serialize(value, parameterKey));
827a69f3 214 }
15a48bb3
AE
215 else {
216 parameters.push(encodeURIComponent(parameterKey) + '=' + encodeURIComponent(value));
827a69f3 217 }
827a69f3
AE
218 }
219 }
220
221 return parameters.join('&');
222 },
223
cb57f345
AE
224 /**
225 * Triggers a custom or built-in event.
226 *
227 * @param {Element} element target element
228 * @param {string} eventName event name
229 */
230 triggerEvent: function(element, eventName) {
231 var event;
232
233 try {
234 event = new Event(eventName, {
235 bubbles: true,
236 cancelable: true
237 });
4bbf6ff1 238 }
cb57f345
AE
239 catch (e) {
240 event = document.createEvent('Event');
241 event.initEvent(eventName, true, true);
4bbf6ff1 242 }
cb57f345
AE
243
244 element.dispatchEvent(event);
0e69f27c
AE
245 },
246
247 /**
248 * Returns the unique prefix for the localStorage.
249 *
250 * @return {string} prefix for the localStorage
251 */
252 getStoragePrefix: function() {
253 return _prefix;
4bbf6ff1
AE
254 }
255 };
256
bc8cd0ff 257 return Core;
4bbf6ff1 258});