| Current Path : /proc/thread-self/cwd/static/adminhtml/Magento/backend/it_IT/Magento_Ui/js/core/renderer/ |
| Current File : //proc/thread-self/cwd/static/adminhtml/Magento/backend/it_IT/Magento_Ui/js/core/renderer/layout.js |
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
define([
'underscore',
'jquery',
'mageUtils',
'uiRegistry',
'./types',
'../../lib/logger/console-logger'
], function (_, $, utils, registry, types, consoleLogger) {
'use strict';
var templates = registry.create(),
layout = {},
cachedConfig = {};
/**
* Build name from parent name and node name
*
* @param {Object} parent
* @param {Object} node
* @param {String} [name]
* @returns {String}
*/
function getNodeName(parent, node, name) {
var parentName = parent && parent.name;
if (typeof name !== 'string') {
name = node.name || name;
}
return utils.fullPath(parentName, name);
}
/**
* Get node type from node or parent.
*
* @param {Object} parent
* @param {Object} node
* @returns {String}
*/
function getNodeType(parent, node) {
return node.type || parent && parent.childType;
}
/**
* Get data scope based on parent data scope and node data scope.
*
* @param {Object} parent
* @param {Object} node
* @returns {String}
*/
function getDataScope(parent, node) {
var dataScope = node.dataScope,
parentScope = parent && parent.dataScope;
return !utils.isEmpty(parentScope) ?
!utils.isEmpty(dataScope) ?
parentScope + '.' + dataScope :
parentScope :
dataScope || '';
}
/**
* Load node dependencies on other instances.
*
* @param {Object} node
* @returns {jQueryPromise}
*/
function loadDeps(node) {
var loaded = $.Deferred(),
loggerUtils = consoleLogger.utils;
if (node.deps) {
consoleLogger.utils.asyncLog(
loaded,
{
data: {
component: node.name,
deps: node.deps
},
messages: loggerUtils.createMessages(
'depsStartRequesting',
'depsFinishRequesting',
'depsLoadingFail'
)
}
);
}
registry.get(node.deps, function (deps) {
node.provider = node.extendProvider ? deps && deps.name : node.provider;
loaded.resolve(node);
});
return loaded.promise();
}
/**
* Load node component file via requirejs.
*
* @param {Object} node
* @returns {jQueryPromise}
*/
function loadSource(node) {
var loaded = $.Deferred(),
source = node.component;
consoleLogger.info('componentStartLoading', {
component: node.component
});
require([source], function (constr) {
consoleLogger.info('componentFinishLoading', {
component: node.component
});
loaded.resolve(node, constr);
}, function () {
consoleLogger.error('componentLoadingFail', {
component: node.component
});
});
return loaded.promise();
}
/**
* Create a new component instance and set it to the registry.
*
* @param {Object} node
* @param {Function} Constr
*/
function initComponent(node, Constr) {
var component = new Constr(_.omit(node, 'children'));
consoleLogger.info('componentStartInitialization', {
component: node.component,
componentName: node.name
});
registry.set(node.name, component);
}
/**
* Application entry point.
*
* @param {Object} nodes
* @param {Object} parent
* @param {Boolean} cached
* @param {Boolean} merge
* @returns {Boolean|undefined}
*/
function run(nodes, parent, cached, merge) {
if (_.isBoolean(merge) && merge) {
layout.merge(nodes);
return false;
}
if (cached) {
cachedConfig[_.keys(nodes)[0]] = JSON.parse(JSON.stringify(nodes));
}
_.each(nodes || [], layout.iterator.bind(layout, parent));
}
_.extend(layout, {
/**
* Determines if node ready to be added or process it.
*
* @param {Object} parent
* @param {Object|String} node
*/
iterator: function (parent, node) {
var action = _.isString(node) ?
this.addChild :
this.process;
action.apply(this, arguments);
},
/**
* Prepare component.
*
* @param {Object} parent
* @param {Object} node
* @param {String} name
* @returns {Object}
*/
process: function (parent, node, name) {
if (!parent && node.parent) {
return this.waitParent(node, name);
}
if (node.nodeTemplate) {
return this.waitTemplate.apply(this, arguments);
}
node = this.build.apply(this, arguments);
if (!registry.has(node.name)) {
this.addChild(parent, node)
.manipulate(node)
.initComponent(node);
}
if (node) {
run(node.children, node);
}
return this;
},
/**
* Detailed processing of component config.
*
* @param {Object} parent
* @param {Object} node
* @param {String} name
* @returns {Boolean|Object}
*/
build: function (parent, node, name) {
var defaults = parent && parent.childDefaults || {},
children = this.filterDisabledChildren(node.children),
type = getNodeType(parent, node),
dataScope = getDataScope(parent, node),
component,
extendDeps = true,
nodeName;
node.children = false;
node.extendProvider = true;
if (node.config && node.config.provider || node.provider) {
node.extendProvider = false;
}
if (node.config && node.config.deps || node.deps) {
extendDeps = false;
}
node = utils.extend({
}, types.get(type), defaults, node);
nodeName = getNodeName(parent, node, name);
if (registry.has(nodeName)) {
component = registry.get(nodeName);
component.children = children;
return component;
}
if (extendDeps && parent && parent.deps && type) {
node.deps = parent.deps;
}
_.extend(node, node.config || {}, {
index: node.name || name,
name: nodeName,
dataScope: dataScope,
parentName: utils.getPart(nodeName, -2),
parentScope: utils.getPart(dataScope, -2)
});
node.children = children;
node.componentType = node.type;
delete node.type;
delete node.config;
if (children) {
node.initChildCount = _.size(children);
}
if (node.isTemplate) {
node.isTemplate = false;
templates.set(node.name, node);
registry.get(node.parentName, function (parentComp) {
parentComp.childTemplate = node;
});
return false;
}
if (node.componentDisabled === true) {
return false;
}
return node;
},
/**
* Filter out all disabled components.
*
* @param {Object} children
* @returns {*}
*/
filterDisabledChildren: function (children) {
var cIds;
//cleanup children config.componentDisabled = true
if (children && typeof children === 'object') {
cIds = Object.keys(children);
if (cIds) {
_.each(cIds, function (cId) {
if (typeof children[cId] === 'object' &&
children[cId].hasOwnProperty('config') &&
typeof children[cId].config === 'object' &&
children[cId].config.hasOwnProperty('componentDisabled') &&
children[cId].config.componentDisabled === true) {
delete children[cId];
}
});
}
}
return children;
},
/**
* Init component.
*
* @param {Object} node
* @returns {Object}
*/
initComponent: function (node) {
if (!node.component) {
return this;
}
loadDeps(node)
.then(loadSource)
.done(initComponent);
return this;
}
});
_.extend(layout, {
/**
* Loading component marked as isTemplate.
*
* @param {Object} parent
* @param {Object} node
* @returns {Object}
*/
waitTemplate: function (parent, node) {
var args = _.toArray(arguments);
templates.get(node.nodeTemplate, function () {
this.applyTemplate.apply(this, args);
}.bind(this));
return this;
},
/**
* Waiting for parent component and process provided component.
*
* @param {Object} node
* @param {String} name
* @returns {Object}
*/
waitParent: function (node, name) {
var process = this.process.bind(this);
registry.get(node.parent, function (parent) {
process(parent, node, name);
});
return this;
},
/**
* Processing component marked as isTemplate.
*
* @param {Object} parent
* @param {Object} node
* @param {String} name
*/
applyTemplate: function (parent, node, name) {
var template = templates.get(node.nodeTemplate);
node = utils.extend({}, template, node);
delete node.nodeTemplate;
this.process(parent, node, name);
}
});
_.extend(layout, {
/**
* Determines inserting strategy.
*
* @param {Object} node
* @returns {Object}
*/
manipulate: function (node) {
var name = node.name;
if (node.appendTo) {
this.insert(name, node.appendTo, -1);
}
if (node.prependTo) {
this.insert(name, node.prependTo, 0);
}
if (node.insertTo) {
this.insertTo(name, node.insertTo);
}
return this;
},
/**
* Insert component to provide target and position.
*
* @param {Object|String} item
* @param {Object} target
* @param {Number} position
* @returns {Object}
*/
insert: function (item, target, position) {
registry.get(target, function (container) {
container.insertChild(item, position);
});
return this;
},
/**
* Insert component into multiple targets.
*
* @param {Object} item
* @param {Array} targets
* @returns {Object}
*/
insertTo: function (item, targets) {
_.each(targets, function (info, target) {
this.insert(item, target, info.position);
}, this);
return this;
},
/**
* Add provided child to parent.
*
* @param {Object} parent
* @param {Object|String} child
* @returns {Object}
*/
addChild: function (parent, child) {
var name;
if (parent && parent.component) {
name = child.name || child;
this.insert(name, parent.name, child.sortOrder);
}
return this;
},
/**
* Merge components configuration with cached configuration.
*
* @param {Array} components
*/
merge: function (components) {
var cachedKey = _.keys(components)[0],
compared = utils.compare(cachedConfig[cachedKey], components),
remove = this.filterComponents(this.getByProperty(compared.changes, 'type', 'remove'), true),
update = this.getByProperty(compared.changes, 'type', 'update'),
dataSources = this.getDataSources(components),
names, index, name, component;
_.each(dataSources, function (val, key) {
name = key.replace(/\.children|\.config/g, '');
component = registry.get(name);
component.cacheData();
component.updateConfig(
true,
this.getFullConfig(key, components),
this.getFullConfig(key, cachedConfig[cachedKey])
);
}, this);
_.each(remove, function (val) {
component = registry.get(val.path);
if (component) {
component.destroy();
}
});
update = _.compact(_.filter(update, function (val) {
return !_.isEqual(val.oldValue, val.value);
}));
_.each(update, function (val) {
names = val.path.split('.');
index = Math.max(_.lastIndexOf(names, 'config'), _.lastIndexOf(names, 'children') + 2);
name = _.without(names.splice(0, index), 'children', 'config').join('.');
component = registry.get(name);
if (val.name === 'sortOrder' && component) {
registry.get(component.parentName).insertChild(component, val.value);
} else if (component) {
component.updateConfig(
val.oldValue,
val.value,
val.path
);
}
}, this);
run(components, undefined, true);
},
/**
* Recursive dataSource assignment.
*
* @param {Object} config
* @param {String} parentPath
* @returns {Object}
*/
getDataSources: function (config, parentPath) {
var dataSources = {},
key, obj;
/* eslint-disable no-loop-func, max-depth */
for (key in config) {
if (config.hasOwnProperty(key)) {
if (
key === 'type' &&
config[key] === 'dataSource' &&
config.hasOwnProperty('config')
) {
dataSources[parentPath + '.config'] = config.config;
} else if (_.isObject(config[key])) {
obj = this.getDataSources(config[key], utils.fullPath(parentPath, key));
_.each(obj, function (value, path) {
dataSources[path] = value;
});
}
}
}
/* eslint-enable no-loop-func, max-depth */
return dataSources;
},
/**
* Configuration getter.
*
* @param {String} path
* @param {Object} config
* @returns {Boolean|Object}
*/
getFullConfig: function (path, config) {
var index;
path = path.split('.');
index = _.lastIndexOf(path, 'config');
if (!~index) {
return false;
}
path = path.splice(0, index);
_.each(path, function (val) {
config = config[val];
});
return config.config;
},
/**
* Filter data by property and value.
*
* @param {Object} data
* @param {String} prop
* @param {*} propValue
*/
getByProperty: function (data, prop, propValue) {
return _.filter(data, function (value) {
return value[prop] === propValue;
});
},
/**
* Filter components.
*
* @param {Array} data
* @param {Boolean} splitPath
* @param {Number} index
* @param {String} separator
* @param {String} keyName
* @returns {Array}
*/
filterComponents: function (data, splitPath, index, separator, keyName) {
var result = [],
names, length;
index = -2;
separator = '.' || separator;
keyName = 'children' || keyName;
_.each(data, function (val) {
names = val.path.split(separator);
length = names.length;
if (names[length + index] === keyName) {
val.path = splitPath ? _.without(names, keyName).join(separator) : val.path;
result.push(val);
}
});
return result;
}
});
return run;
});