| Current Path : /proc/thread-self/cwd/static/frontend/Magento/luma/it_IT/Magento_Ui/js/lib/registry/ |
| Current File : //proc/thread-self/cwd/static/frontend/Magento/luma/it_IT/Magento_Ui/js/lib/registry/registry.js |
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
/**
* @api
*/
define([
'jquery',
'underscore'
], function ($, _) {
'use strict';
var privateData = new WeakMap();
/**
* Extracts private item storage associated
* with a provided registry instance.
*
* @param {Object} container
* @returns {Object}
*/
function getItems(container) {
return privateData.get(container).items;
}
/**
* Extracts private requests array associated
* with a provided registry instance.
*
* @param {Object} container
* @returns {Array}
*/
function getRequests(container) {
return privateData.get(container).requests;
}
/**
* Wrapper function used for convenient access to the elements.
* See 'async' method for examples of usage and comparison
* with a regular 'get' method.
*
* @param {(String|Object|Function)} name - Key of the requested element.
* @param {Registry} registry - Instance of a registry
* where to search for the element.
* @param {(Function|String)} [method] - Optional callback function
* or a name of the elements' method which
* will be invoked when element is available in registry.
* @returns {*}
*/
function async(name, registry, method) {
var args = _.toArray(arguments).slice(3);
if (_.isString(method)) {
registry.get(name, function (component) {
component[method].apply(component, args);
});
} else if (_.isFunction(method)) {
registry.get(name, method);
} else if (!args.length) {
return registry.get(name);
}
}
/**
* Checks that every property of the query object
* is present and equal to the corresponding
* property in target object.
* Note that non-strict comparison is used.
*
* @param {Object} query - Query object.
* @param {Object} target - Target object.
* @returns {Boolean}
*/
function compare(query, target) {
var matches = true,
index,
keys,
key;
if (!_.isObject(query) || !_.isObject(target)) {
return false;
}
keys = Object.getOwnPropertyNames(query);
index = keys.length;
while (matches && index--) {
key = keys[index];
/* eslint-disable eqeqeq */
if (target[key] != query[key]) {
matches = false;
}
/* eslint-enable eqeqeq */
}
return matches;
}
/**
* Explodes incoming string into object if
* string is defined as a set of key = value pairs.
*
* @param {(String|*)} query - String to be processed.
* @returns {Object|*} Either created object or an unmodified incoming
* value if conversion was not possible.
* @example Sample conversions.
* 'key = value, key2 = value2'
* => {key: 'value', key2: 'value2'}
*/
function explode(query) {
var result = {},
index,
data;
if (typeof query !== 'string' || !~query.indexOf('=')) {
return query;
}
query = query.split(',');
index = query.length;
while (index--) {
data = query[index].split('=');
result[data[0].trim()] = data[1].trim();
}
return result;
}
/**
* Extracts items from the provided data object
* which matches specified search criteria.
*
* @param {Object} data - Data object where to perform a lookup.
* @param {(String|Object|Function)} query - Search criteria.
* @param {Boolean} findAll - Flag that defines whether to
* search for all applicable items or to stop on a first found entry.
* @returns {Array|Object|*}
*/
function find(data, query, findAll) {
var iterator,
item;
query = explode(query);
if (typeof query === 'string') {
item = data[query];
if (findAll) {
return item ? [item] : [];
}
return item;
}
iterator = !_.isFunction(query) ?
compare.bind(null, query) :
query;
return findAll ?
_.filter(data, iterator) :
_.find(data, iterator);
}
/**
* @constructor
*/
function Registry() {
var data = {
items: {},
requests: []
};
this._updateRequests = _.debounce(this._updateRequests.bind(this), 10);
privateData.set(this, data);
}
Registry.prototype = {
constructor: Registry,
/**
* Retrieves item from registry which matches specified search criteria.
*
* @param {(Object|String|Function|Array)} query - Search condition (see examples).
* @param {Function} [callback] - Callback that will be invoked when
* all of the requested items are available.
* @returns {*}
*
* @example Requesting item by it's name.
* var obj = {index: 'test', sample: true};
*
* registry.set('first', obj);
* registry.get('first') === obj;
* => true
*
* @example Requesting item with a specific properties.
* registry.get('sample = 1, index = test') === obj;
* => true
* registry.get('sample = 0, index = foo') === obj;
* => false
*
* @example Declaring search criteria as an object.
* registry.get({sample: true}) === obj;
* => true;
*
* @example Providing custom search handler.
* registry.get(function (item) { return item.sample === true; }) === obj;
* => true
*
* @example Sample asynchronous request declaration.
* registry.get('index = test', function (item) {});
*
* @example Requesting multiple elements.
* registry.set('second', {index: 'test2'});
* registry.get(['first', 'second'], function (first, second) {});
*/
get: function (query, callback) {
if (typeof callback !== 'function') {
return find(getItems(this), query);
}
this._addRequest(query, callback);
},
/**
* Sets provided item to the registry.
*
* @param {String} id - Item's identifier.
* @param {*} item - Item's data.
* returns {Registry} Chainable.
*/
set: function (id, item) {
getItems(this)[id] = item;
this._updateRequests();
return this;
},
/**
* Removes specified item from registry.
* Note that search query is not applicable.
*
* @param {String} id - Item's identifier.
* @returns {Registry} Chainable.
*/
remove: function (id) {
delete getItems(this)[id];
return this;
},
/**
* Retrieves a collection of elements that match
* provided search criteria.
*
* @param {(Object|String|Function)} query - Search query.
* See 'get' method for the syntax examples.
* @returns {Array} Found elements.
*/
filter: function (query) {
return find(getItems(this), query, true);
},
/**
* Checks that at least one element in collection
* matches provided search criteria.
*
* @param {(Object|String|Function)} query - Search query.
* See 'get' method for the syntax examples.
* @returns {Boolean}
*/
has: function (query) {
return !!this.get(query);
},
/**
* Checks that registry contains a provided item.
*
* @param {*} item - Item to be checked.
* @returns {Boolean}
*/
contains: function (item) {
return _.contains(getItems(this), item);
},
/**
* Extracts identifier of an item if it's present in registry.
*
* @param {*} item - Item whose identifier will be extracted.
* @returns {String|Undefined}
*/
indexOf: function (item) {
return _.findKey(getItems(this), function (elem) {
return item === elem;
});
},
/**
* Same as a 'get' method except that it returns
* a promise object instead of invoking provided callback.
*
* @param {(String|Function|Object|Array)} query - Search query.
* See 'get' method for the syntax examples.
* @returns {jQueryPromise}
*/
promise: function (query) {
var defer = $.Deferred(),
callback = defer.resolve.bind(defer);
this.get(query, callback);
return defer.promise();
},
/**
* Creates a wrapper function over the provided search query
* in order to provide somehow more convenient access to the
* registry's items.
*
* @param {(String|Object|Function)} query - Search criteria.
* See 'get' method for the syntax examples.
* @returns {Function}
*
* @example Comparison with a 'get' method on retrieving items.
* var module = registry.async('name');
*
* module();
* => registry.get('name');
*
* @example Asynchronous request.
* module(function (component) {});
* => registry.get('name', function (component) {});
*
* @example Requesting item and invoking it's method with specified parameters.
* module('trigger', true);
* => registry.get('name', function (component) {
* component.trigger(true);
* });
*/
async: function (query) {
return async.bind(null, query, this);
},
/**
* Creates new instance of a Registry.
*
* @returns {Registry} New instance.
*/
create: function () {
return new Registry;
},
/**
* Adds new request to the queue or resolves it immediately
* if all of the required items are available.
*
* @private
* @param {(Object|String|Function|Array)} queries - Search criteria.
* See 'get' method for the syntax examples.
* @param {Function} callback - Callback that will be invoked when
* all of the requested items are available.
* @returns {Registry}
*/
_addRequest: function (queries, callback) {
var request;
if (!Array.isArray(queries)) {
queries = queries ? [queries] : [];
}
request = {
queries: queries.map(explode),
callback: callback
};
this._canResolve(request) ?
this._resolveRequest(request) :
getRequests(this).push(request);
return this;
},
/**
* Updates requests list resolving applicable items.
*
* @private
* @returns {Registry} Chainable.
*/
_updateRequests: function () {
getRequests(this)
.filter(this._canResolve, this)
.forEach(this._resolveRequest, this);
return this;
},
/**
* Resolves provided request invoking it's callback
* with items specified in query parameters.
*
* @private
* @param {Object} request - Request object.
* @returns {Registry} Chainable.
*/
_resolveRequest: function (request) {
var requests = getRequests(this),
items = request.queries.map(this.get, this),
index = requests.indexOf(request);
request.callback.apply(null, items);
if (~index) {
requests.splice(index, 1);
}
return this;
},
/**
* Checks if provided request can be resolved.
*
* @private
* @param {Object} request - Request object.
* @returns {Boolean}
*/
_canResolve: function (request) {
var queries = request.queries;
return queries.every(this.has, this);
}
};
return new Registry;
});