155 lines
4.4 KiB
JavaScript
155 lines
4.4 KiB
JavaScript
/**
|
|
* @file js/classes/ObjectProxy.js
|
|
*
|
|
* Copyright (c) 2014-2021 Simon Fraser University
|
|
* Copyright (c) 2000-2021 John Willinsky
|
|
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
|
*
|
|
* @class ObjectProxy
|
|
* @ingroup js_classes
|
|
*
|
|
* @brief Proxy that will be added to every object before
|
|
* instantiation.
|
|
*
|
|
* This proxy allows us to use a generic object factory. It'll
|
|
* also be a good place to intercept objects and implement
|
|
* cross-cutting concerns if required.
|
|
*/
|
|
(function($) {
|
|
|
|
|
|
/**
|
|
* @constructor
|
|
* The constructor must remain empty because it will
|
|
* be replaced on instantiation of the proxy.
|
|
*/
|
|
$.pkp.classes.ObjectProxy = function() {};
|
|
|
|
|
|
//
|
|
// Private instance variables
|
|
//
|
|
/**
|
|
* @private
|
|
* @type {string} The object name of this object.
|
|
*/
|
|
$.pkp.classes.ObjectProxy.prototype.objectName_ = '';
|
|
|
|
|
|
//
|
|
// Protected methods
|
|
//
|
|
/**
|
|
* Find a static property in the constructor hierarchy.
|
|
*
|
|
* NB: If the property is a function then it will be executed
|
|
* in the current context with the additional arguments given.
|
|
* If it is any other type then the property will be returned.
|
|
*
|
|
* @param {string} propertyName The name of the static
|
|
* property to be found.
|
|
* @param {...*} var_args Arguments to be passed to the
|
|
* static method (if any).
|
|
* @return {*} The property or undefined if the property
|
|
* was not found.
|
|
*/
|
|
$.pkp.classes.ObjectProxy.prototype.self =
|
|
function(propertyName, var_args) {
|
|
var ctor, foundProperty, args;
|
|
|
|
// Loop through the inheritance hierarchy to find the property.
|
|
for (ctor = this.constructor; ctor;
|
|
ctor = ctor.parent_ && ctor.parent_.constructor) {
|
|
|
|
// Try to find the property in the current constructor.
|
|
if (ctor.hasOwnProperty(propertyName)) {
|
|
foundProperty = ctor[propertyName];
|
|
if ($.isFunction(foundProperty)) {
|
|
// If the property is a function then call it.
|
|
args = Array.prototype.slice.call(arguments, 1);
|
|
return foundProperty.apply(this, args);
|
|
} else {
|
|
// Return the property itself.
|
|
return foundProperty;
|
|
}
|
|
}
|
|
}
|
|
|
|
// The property was not found on any of the functions
|
|
// in the constructor hierarchy.
|
|
throw new Error(['Static property "', propertyName, '" not found!'].join(''));
|
|
};
|
|
|
|
|
|
/**
|
|
* Find the parent constructor or method in the prototype
|
|
* hierarchy.
|
|
*
|
|
* NB: If the method is found then it will be executed in the
|
|
* context of the me parameter with the given arguments.
|
|
*
|
|
* @param {*=} opt_methodName The name of the method to
|
|
* be found. Do not set when calling this method from a
|
|
* constructor!
|
|
* @param {...*} var_args Arguments to be passed to the
|
|
* parent method.
|
|
* @return {*} The return value of the parent method.
|
|
*/
|
|
$.pkp.classes.ObjectProxy.prototype.parent =
|
|
function(opt_methodName, var_args) {
|
|
var caller, args, foundCaller, ctor;
|
|
|
|
// Retrieve a reference to the function that called us.
|
|
caller = $.pkp.classes.ObjectProxy.prototype.parent.caller;
|
|
|
|
// 1) Check whether the caller is a constructor.
|
|
if (caller.parent_) {
|
|
// We were called from within a constructor and
|
|
// therefore the methodName parameter is not set.
|
|
args = Array.prototype.slice.call(arguments);
|
|
|
|
// Call the constructor.
|
|
return caller.parent_.constructor.apply(this, args);
|
|
}
|
|
|
|
// Assume that we were called from within a method and that
|
|
// therefore the methodName parameter is set.
|
|
args = Array.prototype.slice.call(arguments, 1);
|
|
|
|
// 2) Look for the caller in the top-level instance methods.
|
|
if (this.hasOwnProperty(opt_methodName) && this[opt_methodName] === caller) {
|
|
return this.constructor.parent_[opt_methodName].apply(this, args);
|
|
}
|
|
|
|
// 3) Look for the caller in the prototype chain.
|
|
foundCaller = false;
|
|
for (ctor = this.constructor; ctor;
|
|
ctor = ctor.parent_ && ctor.parent_.constructor) {
|
|
if (ctor.prototype.hasOwnProperty(opt_methodName) &&
|
|
ctor.prototype[opt_methodName] === caller) {
|
|
foundCaller = true;
|
|
} else if (foundCaller) {
|
|
return ctor.prototype[opt_methodName].apply(this, args);
|
|
}
|
|
}
|
|
|
|
// 4) This method was not called by the right caller.
|
|
throw new Error(['Trying to call parent from a method of one name ',
|
|
'to a method of a different name'].join(''));
|
|
};
|
|
|
|
|
|
//
|
|
// Public methods
|
|
//
|
|
/**
|
|
* Return the object name of this object
|
|
* @return {string} The object name of this object.
|
|
*/
|
|
$.pkp.classes.ObjectProxy.prototype.getObjectName = function() {
|
|
return this.objectName_;
|
|
};
|
|
|
|
|
|
}(jQuery));
|