159 lines
4.6 KiB
JavaScript
Executable File
159 lines
4.6 KiB
JavaScript
Executable File
/**
|
|
* Copyright © Magento, Inc. All rights reserved.
|
|
* See COPYING.txt for license details.
|
|
*/
|
|
|
|
/**
|
|
* Utility methods used to wrap and extend functions.
|
|
*
|
|
* @example Usage of a 'wrap' method with arguments delegation.
|
|
* var multiply = function (a, b) {
|
|
* return a * b;
|
|
* };
|
|
*
|
|
* multiply = module.wrap(multiply, function (orig) {
|
|
* return 'Result is: ' + orig();
|
|
* });
|
|
*
|
|
* multiply(2, 2);
|
|
* => 'Result is: 4'
|
|
*
|
|
* @example Usage of 'wrapSuper' method.
|
|
* var multiply = function (a, b) {
|
|
* return a * b;
|
|
* };
|
|
*
|
|
* var obj = {
|
|
* multiply: module.wrapSuper(multiply, function () {
|
|
* return 'Result is: ' + this._super();
|
|
* });
|
|
* };
|
|
*
|
|
* obj.multiply(2, 2);
|
|
* => 'Result is: 4'
|
|
*/
|
|
define([
|
|
'underscore'
|
|
], function (_) {
|
|
'use strict';
|
|
|
|
/**
|
|
* Checks if string has a '_super' substring.
|
|
*/
|
|
var superReg = /\b_super\b/;
|
|
|
|
return {
|
|
|
|
/**
|
|
* Wraps target function with a specified wrapper, which will receive
|
|
* reference to the original function as a first argument.
|
|
*
|
|
* @param {Function} target - Function to be wrapped.
|
|
* @param {Function} wrapper - Wrapper function.
|
|
* @returns {Function} Wrapper function.
|
|
*/
|
|
wrap: function (target, wrapper) {
|
|
if (!_.isFunction(target) || !_.isFunction(wrapper)) {
|
|
return wrapper;
|
|
}
|
|
|
|
return function () {
|
|
var args = _.toArray(arguments),
|
|
ctx = this,
|
|
_super;
|
|
|
|
/**
|
|
* Function that will be passed to the wrapper.
|
|
* If no arguments will be passed to it, then the original
|
|
* function will be called with an arguments of a wrapper function.
|
|
*/
|
|
_super = function () {
|
|
var superArgs = arguments.length ? arguments : args.slice(1);
|
|
|
|
return target.apply(ctx, superArgs);
|
|
};
|
|
|
|
args.unshift(_super);
|
|
|
|
return wrapper.apply(ctx, args);
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Wraps the incoming function to implement support of the '_super' method.
|
|
*
|
|
* @param {Function} target - Function to be wrapped.
|
|
* @param {Function} wrapper - Wrapper function.
|
|
* @returns {Function} Wrapped function.
|
|
*/
|
|
wrapSuper: function (target, wrapper) {
|
|
if (!this.hasSuper(wrapper) || !_.isFunction(target)) {
|
|
return wrapper;
|
|
}
|
|
|
|
return function () {
|
|
var _super = this._super,
|
|
args = arguments,
|
|
result;
|
|
|
|
/**
|
|
* Temporary define '_super' method which
|
|
* contains call to the original function.
|
|
*/
|
|
this._super = function () {
|
|
var superArgs = arguments.length ? arguments : args;
|
|
|
|
return target.apply(this, superArgs);
|
|
};
|
|
|
|
result = wrapper.apply(this, args);
|
|
|
|
this._super = _super;
|
|
|
|
return result;
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Checks wether the incoming method contains calls of the '_super' method.
|
|
*
|
|
* @param {Function} fn - Function to be checked.
|
|
* @returns {Boolean}
|
|
*/
|
|
hasSuper: function (fn) {
|
|
return _.isFunction(fn) && superReg.test(fn);
|
|
},
|
|
|
|
/**
|
|
* Extends target object with provided extenders.
|
|
* If property in target and extender objects is a function,
|
|
* then it will be wrapped using 'wrap' method.
|
|
*
|
|
* @param {Object} target - Object to be extended.
|
|
* @param {...Object} extenders - Multiple extenders objects.
|
|
* @returns {Object} Modified target object.
|
|
*/
|
|
extend: function (target) {
|
|
var extenders = _.toArray(arguments).slice(1),
|
|
iterator = this._extend.bind(this, target);
|
|
|
|
extenders.forEach(iterator);
|
|
|
|
return target;
|
|
},
|
|
|
|
/**
|
|
* Same as the 'extend' method, but operates only on one extender object.
|
|
*
|
|
* @private
|
|
* @param {Object} target
|
|
* @param {Object} extender
|
|
*/
|
|
_extend: function (target, extender) {
|
|
_.each(extender, function (value, key) {
|
|
target[key] = this.wrap(target[key], extender[key]);
|
|
}, this);
|
|
}
|
|
};
|
|
});
|