PageSourceSearch

https://bakhtiniada.ru/lib/pkp/js/classes/Helper.js

js bakhtiniada.ru collected 2026-10-04 20:08:37 UTC 11,319 bytes, 371 lines download raw bytes

1/**
2 * @defgroup js_classes
3 */
4
5/**
6 * @file js/classes/Helper.js
7 *
8 * Copyright (c) 2014-2019 Simon Fraser University
9 * Copyright (c) 2000-2019 John Willinsky
10 * Distributed under the GNU GPL v2. For full terms see the file docs/COPYING.
11 *
12 * @class Helper
13 * @ingroup js_controllers
14 *
15 * @brief PKP helper methods
16 */
17(function($) {
18
19	// Create PKP namespaces.
20	/** @type {Object} */
21	$.pkp = $.pkp || { };
22
23
24	/** @type {Object} */
25	$.pkp.classes = $.pkp.classes || { };
26
27
28	/** @type {Object} */
29	$.pkp.controllers = $.pkp.controllers || { };
30
31
32	/** @type {Object} */
33	$.pkp.plugins = $.pkp.plugins || {};
34
35	/** @type {Object} */
36	$.pkp.plugins.metrics = $.pkp.plugins.metrics || {};
37
38
39	/** @type {Object} */
40	$.pkp.plugins.blocks = $.pkp.plugins.blocks || {};
41
42
43	/** @type {Object} */
44	$.pkp.plugins.generic = $.pkp.plugins.generic || {};
45
46
47	/** @type {Object} */
48	$.pkp.plugins.pubIds = $.pkp.plugins.pubIds || {};
49
50
51	/** @type {Object} */
52	$.pkp.plugins.importexport = $.pkp.plugins.importexport || {};
53
54
55
56	/**
57	 * Helper singleton
58	 * @constructor
59	 *
60	 * @extends $.pkp.classes.ObjectProxy
61	 */
62	$.pkp.classes.Helper = function() {
63		throw new Error('Trying to instantiate the Helper singleton!');
64	};
65
66
67	//
68	// Private class constants
69	//
70	/**
71	 * Characters available for UUID generation.
72	 * @const
73	 * @private
74	 * @type {Array}
75	 */
76	$.pkp.classes.Helper.CHARS_ = ['0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ',
77		'abcdefghijklmnopqrstuvwxyz'].join('').split('');
78
79
80	//
81	// Public static helper methods
82	//
83	/**
84	 * Generate a random UUID.
85	 *
86	 * Original code thanks to Robert Kieffer <[email protected]>,
87	 * http://www.broofa.com, adapted by PKP.
88	 *
89	 * Copyright (c) 2010 Robert Kieffer
90	 * Copyright (c) 2014-2019 Simon Fraser University
91	 * Copyright (c) 2010-2019 John Willinsky
92	 * Distributed under the GNU GPL v2 and MIT licenses. For full
93	 * terms see the file docs/COPYING.
94	 *
95	 * See discussion of randomness versus uniqueness:
96	 * http://www.broofa.com/2008/09/javascript-uuid-function/
97	 *
98	 * @return {string} an RFC4122v4 compliant UUID.
99	 */
100	$.pkp.classes.Helper.uuid = function() {
101		var chars = $.pkp.classes.Helper.CHARS_, uuid = new Array(36), rnd = 0, r, i;
102		for (i = 0; i < 36; i++) {
103			if (i == 8 || i == 13 || i == 18 || i == 23) {
104				uuid[i] = '-';
105			} else if (i == 14) {
106				uuid[i] = '4';
107			} else {
108				/*jslint bitwise: true*/
109				if (rnd <= 0x02) {
110					rnd = 0x2000000 + (Math.random() * 0x1000000) | 0;
111				}
112				r = rnd & 0xf;
113				rnd = rnd >> 4;
114				uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
115				/*jslint bitwise: false*/
116			}
117		}
118		return uuid.join('');
119	};
120
121
122	/**
123	 * Let one object inherit from another.
124	 *
125	 * Example:
126	 *  $.pkp.classes.Parent = function() {...};
127	 *  $.pkp.classes.Child = function() {...};
128	 *  $.pkp.classes.Helper.inherits($.pkp.classes.Child, $.pkp.classes.Parent);
129	 *
130	 * @param {Function} Child Constructor of the child object.
131	 * @param {Function} Parent Constructor of the parent object.
132	 */
133	$.pkp.classes.Helper.inherits = function(Child, Parent) {
134		// Use an empty temporary object to avoid
135		// calling a potentially costly constructor
136		// on the parent object which also may have
137		// undesired side effects. Also avoids instantiating
138		// a potentially big object.
139		/** @constructor */ var Temp = function() {};
140		Temp.prototype = Parent.prototype;
141
142		// Provide a way to reach the parent's
143		// method implementations even after
144		// overriding them in the child object.
145		Child.parent_ = Parent.prototype;
146
147		// Let the child object inherit from
148		// the parent object.
149		Child.prototype = new Temp();
150
151		// Need to fix the child constructor because
152		// it get's lost when setting the prototype
153		// to an object instance.
154		Child.prototype.constructor = Child;
155
156		// Make sure that we can always call the parent object's
157		// constructor without coupling the child constructor
158		// to it. This should work even when the parent inherits
159		// directly from an Object instance (i.e. the parent's
160		// prototype was set like this: Parent.prototype = {...})
161		// which wipes out the original constructor.
162		if (Parent.prototype.constructor == Object.prototype.constructor) {
163			Parent.prototype.constructor = Parent;
164		}
165	};
166
167
168	/**
169	 * Introduce a central object factory that maintains some
170	 * level of indirection so that we can enrich objects, e.g.
171	 * with aspects, provide different runtime-implementations
172	 * of objects, distinguish between singletons and prototypes
173	 * or even implement dependency injection if we want to.
174	 *
175	 * The standard implementation has a 'convention over
176	 * configuration' approach that assumes that an object's
177	 * name corresponds to the name of a constructor within
178	 * the global jQuery namespace ($).
179	 *
180	 * The factory also helps us to avoid the common pitfall to
181	 * use a constructor without the 'new' keyword.
182	 *
183	 * @param {string} objectName The name of an object.
184	 * @param {Array} args The arguments to be passed
185	 *  into the object's constructor.
186	 * @return {$.pkp.classes.ObjectProxy} the instantiated object.
187	 */
188	$.pkp.classes.Helper.objectFactory = function(objectName, args) {
189		var ObjectConstructor, ObjectProxyInstance, objectInstance;
190
191		// Resolve the object name.
192		ObjectConstructor = $.pkp.classes.Helper.resolveObjectName(objectName);
193
194		// Create a new proxy constructor instance.
195		ObjectProxyInstance = $.pkp.classes.Helper.getObjectProxyInstance();
196
197		// Copy static members over from the object proxy. (This may
198		// overwrite the proxy constructor's prototype in some
199		// browsers but we don't care because we'll replace the prototype
200		// anyway when we inherit.)
201		$.extend(true, ObjectProxyInstance, $.pkp.classes.ObjectProxy);
202
203		// Let the proxy inherit from the proxied object.
204		$.pkp.classes.Helper.inherits(ObjectProxyInstance, ObjectConstructor);
205
206		// Enrich the new proxy constructor prototype with proxy object
207		// prototype members.
208		$.extend(true, ObjectProxyInstance.prototype,
209				$.pkp.classes.ObjectProxy.prototype);
210
211		// Instantiate the proxy with the proxied object.
212		objectInstance = new ObjectProxyInstance(objectName, args);
213		return objectInstance;
214	};
215
216
217	/**
218	 * Resolves the given object name to an object implementation
219	 * (or better to it's constructor).
220	 * @param {string} objectName The object name to resolve.
221	 * @return {Function} The constructor of the object.
222	 */
223	$.pkp.classes.Helper.resolveObjectName = function(objectName) {
224		var objectNameParts, i, functionName, ObjectConstructor;
225
226		// Currently only objects in the $ namespace are
227		// supported.
228		objectNameParts = objectName.split('.');
229		if (objectNameParts.shift() != '$') {
230			throw new Error(['Namespace "', objectNameParts[0], '" for object "',
231				objectName, '" is currently not supported!'].join(''));
232		}
233
234		// Make sure that we actually have a constructor name
235		// (starts with an upper case letter).
236		functionName = objectNameParts[objectNameParts.length - 1];
237		if (functionName.charAt(0).toUpperCase() !== functionName.charAt(0)) {
238			throw new Error(['The name "', objectName, '" does not point to a',
239				'constructor which must always be upper case!'].join(''));
240		}
241
242		// Run through the namespace and identify the constructor.
243		ObjectConstructor = $;
244		for (i in objectNameParts) {
245			ObjectConstructor = ObjectConstructor[objectNameParts[i]];
246			if (ObjectConstructor === undefined) {
247				throw new Error(['Constructor for object "', objectName, '" not found!']
248						.join(''));
249			}
250		}
251
252		// Check that the constructor actually is a function.
253		if (!$.isFunction(ObjectConstructor)) {
254			throw new Error(['The name "', objectName, '" does not point to a',
255				'constructor which must always be a function!'].join());
256		}
257
258		return ObjectConstructor;
259	};
260
261
262	/**
263	 * Create a new instance of a proxy constructor.
264	 *
265	 * NB: We do this in a separate closure to avoid
266	 * memory leaks.
267	 *
268	 * @return {Function} a new proxy instance.
269	 */
270	$.pkp.classes.Helper.getObjectProxyInstance = function() {
271		// Create a new proxy constructor so that proxies
272		// do not interfere with each other.
273		/**
274		 * @constructor
275		 *
276		 * @param {string} objectName The name of the proxied
277		 *  object.
278		 * @param {Array} args The arguments to be passed to
279		 *  the constructor of the proxied object.
280		 */
281		var proxyConstructor = function(objectName, args) {
282			// Set the internal object name.
283			this.objectName_ = objectName;
284
285			// Call the constructor of the proxied object.
286			this.parent.apply(this, args);
287		};
288
289		// Declare properties/methods used in the constructor for the
290		// closure compiler. These will later be overwritten by the
291		// true implementation.
292		/**
293		 * @private
294		 * @type {string} The object name of this object.
295		 */
296		proxyConstructor.objectName_ = '';
297
298		/**
299		 * @param {*=} opt_methodName The name of the method to
300		 *  be found. Do not set when calling this method from a
301		 *  constructor!
302		 * @param {...*} var_args Arguments to be passed to the
303		 *  parent method.
304		 * @return {*} The return value of the parent method.
305		 */
306		proxyConstructor.prototype.parent = function(opt_methodName, var_args) {};
307
308		return proxyConstructor;
309	};
310
311
312	/**
313	 * Inject (mix in) an interface into an object.
314	 * @param {Function} Constructor The target object's constructor.
315	 * @param {string} mixinObjectName The object name of interface
316	 *  that can be resolved to an interface implementation by the
317	 *  object factory.
318	 */
319	$.pkp.classes.Helper.injectMixin = function(Constructor, mixinObjectName) {
320		// Retrieve an instance of the mix-in interface implementation.
321		var mixin = $.pkp.classes.Helper.objectFactory(mixinObjectName, []);
322
323		// Inject the mix-in into the target constructor.
324		$.extend(true, Constructor, mixin);
325	};
326
327
328	/**
329	 * A function currying implementation borrowed from Google Closure.
330	 * @param {Function} fn A function to partially apply.
331	 * @param {Object} context Specifies the object which |this| should
332	 *  point to when the function is run. If the value is null or undefined, it
333	 *  will default to the global object.
334	 * @param {...*} var_args Additional arguments that are partially
335	 *  applied to the function.
336	 * @return {!Function} A partially-applied form of the function bind() was
337	 *  invoked as a method of.
338	 */
339	$.pkp.classes.Helper.curry = function(fn, context, var_args) {
340		if (arguments.length > 2) {
341			var boundArgs, newArgs;
342			boundArgs = Array.prototype.slice.call(arguments, 2);
343			return function() {
344				// Prepend the bound arguments to the current arguments.
345				newArgs = Array.prototype.slice.call(arguments);
346				Array.prototype.unshift.apply(newArgs, boundArgs);
347				return fn.apply(context, newArgs);
348			};
349		} else {
350			return function() {
351				return fn.apply(context, arguments);
352			};
353		}
354	};
355
356
357	/**
358	 * A function that takes care of escaping @ character which could be interpreted
359	 * as CSS notation. This is due to the fact that jQuery uses CSS syntax for
360	 * selecting elements. These characters must be escaped by placing two
361	 * backslashes in front of them.
362	 * @param {string} elementId jQuery element selector
363	 * @return {string}
364	 */
365	$.pkp.classes.Helper.escapeJQuerySelector = function(elementId) {
366		return elementId.replace('@', '\\@');
367	};
368
369
370/** @param {jQuery} $ jQuery closure. */
371}(jQuery));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.