Skip to content

Commit c555375

Browse files
committed
mage
1 parent 1849833 commit c555375

File tree

2 files changed

+238
-0
lines changed

2 files changed

+238
-0
lines changed

mage/apply/main.js

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/**
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
6+
define([
7+
'underscore',
8+
'jquery',
9+
'./scripts'
10+
], function (_, $, processScripts) {
11+
'use strict';
12+
13+
var dataAttr = 'data-mage-init',
14+
nodeSelector = '[' + dataAttr + ']';
15+
16+
/**
17+
* Initializes components assigned to a specified element via data-* attribute.
18+
*
19+
* @param {HTMLElement} el - Element to initialize components with.
20+
* @param {Object|String} config - Initial components' config.
21+
* @param {String} component - Components' path.
22+
*/
23+
function init(el, config, component) {
24+
require([component], function (fn) {
25+
var $el;
26+
27+
if (typeof fn === 'object') {
28+
fn = fn[component].bind(fn);
29+
}
30+
31+
if (_.isFunction(fn)) {
32+
fn = fn.bind(null, config, el);
33+
} else {
34+
$el = $(el);
35+
36+
if ($el[component]) {
37+
// eslint-disable-next-line jquery-no-bind-unbind
38+
fn = $el[component].bind($el, config);
39+
}
40+
}
41+
// Init module in separate task to prevent blocking main thread.
42+
setTimeout(fn);
43+
}, function (error) {
44+
if ('console' in window && typeof window.console.error === 'function') {
45+
console.error(error);
46+
}
47+
48+
return true;
49+
});
50+
}
51+
52+
/**
53+
* Parses elements 'data-mage-init' attribute as a valid JSON data.
54+
* Note: data-mage-init attribute will be removed.
55+
*
56+
* @param {HTMLElement} el - Element whose attribute should be parsed.
57+
* @returns {Object}
58+
*/
59+
function getData(el) {
60+
var data = el.getAttribute(dataAttr);
61+
62+
el.removeAttribute(dataAttr);
63+
64+
return {
65+
el: el,
66+
data: JSON.parse(data)
67+
};
68+
}
69+
70+
return {
71+
/**
72+
* Initializes components assigned to HTML elements via [data-mage-init].
73+
*
74+
* @example Sample 'data-mage-init' declaration.
75+
* data-mage-init='{"path/to/component": {"foo": "bar"}}'
76+
*/
77+
apply: function (context) {
78+
var virtuals = processScripts(!context ? document : context),
79+
nodes = document.querySelectorAll(nodeSelector);
80+
81+
_.toArray(nodes)
82+
.map(getData)
83+
.concat(virtuals)
84+
.forEach(function (itemContainer) {
85+
var element = itemContainer.el;
86+
87+
_.each(itemContainer.data, function (obj, key) {
88+
if (obj.mixins) {
89+
require(obj.mixins, function () { //eslint-disable-line max-nested-callbacks
90+
var i, len;
91+
92+
for (i = 0, len = arguments.length; i < len; i++) {
93+
$.extend(
94+
true,
95+
itemContainer.data[key],
96+
arguments[i](itemContainer.data[key], element)
97+
);
98+
}
99+
100+
delete obj.mixins;
101+
init.call(null, element, obj, key);
102+
});
103+
} else {
104+
init.call(null, element, obj, key);
105+
}
106+
107+
}
108+
);
109+
110+
});
111+
},
112+
applyFor: init
113+
};
114+
});

mage/apply/scripts.js

+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/**
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
6+
define([
7+
'underscore',
8+
'jquery'
9+
], function (_, $) {
10+
'use strict';
11+
12+
var scriptSelector = 'script[type="text/x-magento-init"]',
13+
dataAttr = 'data-mage-init',
14+
virtuals = [];
15+
16+
/**
17+
* Adds components to the virtual list.
18+
*
19+
* @param {Object} components
20+
*/
21+
function addVirtual(components) {
22+
virtuals.push({
23+
el: false,
24+
data: components
25+
});
26+
}
27+
28+
/**
29+
* Merges provided data with a current data
30+
* of a elements' "data-mage-init" attribute.
31+
*
32+
* @param {Object} components - Object with components and theirs configuration.
33+
* @param {HTMLElement} elem - Element whose data should be modified.
34+
*/
35+
function setData(components, elem) {
36+
var data = elem.getAttribute(dataAttr);
37+
38+
data = data ? JSON.parse(data) : {};
39+
_.each(components, function (obj, key) {
40+
if (_.has(obj, 'mixins')) {
41+
data[key] = data[key] || {};
42+
data[key].mixins = data[key].mixins || [];
43+
data[key].mixins = data[key].mixins.concat(obj.mixins);
44+
delete obj.mixins;
45+
}
46+
});
47+
48+
data = $.extend(true, data, components);
49+
data = JSON.stringify(data);
50+
elem.setAttribute(dataAttr, data);
51+
}
52+
53+
/**
54+
* Search for the elements by privded selector and extends theirs data.
55+
*
56+
* @param {Object} components - Object with components and theirs configuration.
57+
* @param {String} selector - Selector for the elements.
58+
*/
59+
function processElems(components, selector) {
60+
var elems,
61+
iterator;
62+
63+
if (selector === '*') {
64+
addVirtual(components);
65+
66+
return;
67+
}
68+
69+
elems = document.querySelectorAll(selector);
70+
iterator = setData.bind(null, components);
71+
72+
_.toArray(elems).forEach(iterator);
73+
}
74+
75+
/**
76+
* Parses content of a provided script node.
77+
* Note: node will be removed from DOM.
78+
*
79+
* @param {HTMLScriptElement} node - Node to be processed.
80+
* @returns {Object}
81+
*/
82+
function getNodeData(node) {
83+
var data = node.textContent;
84+
85+
node.parentNode.removeChild(node);
86+
87+
return JSON.parse(data);
88+
}
89+
90+
/**
91+
* Parses 'script' tags with a custom type attribute and moves it's data
92+
* to a 'data-mage-init' attribute of an element found by provided selector.
93+
* Note: All found script nodes will be removed from DOM.
94+
*
95+
* @returns {Array} An array of components not assigned to the specific element.
96+
*
97+
* @example Sample declaration.
98+
* <script type="text/x-magento-init">
99+
* {
100+
* "body": {
101+
* "path/to/component": {"foo": "bar"}
102+
* }
103+
* }
104+
* </script>
105+
*
106+
* @example Providing data without selector.
107+
* {
108+
* "*": {
109+
* "path/to/component": {"bar": "baz"}
110+
* }
111+
* }
112+
*/
113+
return function () {
114+
var nodes = document.querySelectorAll(scriptSelector);
115+
116+
_.toArray(nodes)
117+
.map(getNodeData)
118+
.forEach(function (item) {
119+
_.each(item, processElems);
120+
});
121+
122+
return virtuals.splice(0, virtuals.length);
123+
};
124+
});

0 commit comments

Comments
 (0)