Skip to content

Commit aef9537

Browse files
authored
Handle missing mixins and applying mixin attributes to mappings of primitives (#5483)
Co-authored-by: Noeri Huisman <[email protected]>
1 parent 5264e96 commit aef9537

File tree

4 files changed

+71
-20
lines changed

4 files changed

+71
-20
lines changed

src/core/a-mixin.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ var MULTIPLE_COMPONENT_DELIMITER = '__';
88
/**
99
* @member {object} componentCache - Cache of pre-parsed values. An object where the keys
1010
* are component names and the values are already parsed by the component.
11+
* @member {object} rawAttributeCache - Cache of the raw attribute values.
1112
*/
1213
class AMixin extends ANode {
1314
constructor () {
1415
super();
1516
this.componentCache = {};
17+
this.rawAttributeCache = {};
1618
this.isMixin = true;
1719
}
1820

@@ -60,10 +62,11 @@ class AMixin extends ANode {
6062
// Get component data.
6163
componentName = utils.split(attr, MULTIPLE_COMPONENT_DELIMITER)[0];
6264
component = components[componentName];
63-
if (!component) { return; }
6465
if (value === undefined) {
6566
value = window.HTMLElement.prototype.getAttribute.call(this, attr);
6667
}
68+
this.rawAttributeCache[attr] = value;
69+
if (!component) { return; }
6770
this.componentCache[attr] = component.parseAttrValueForCache(value);
6871
}
6972

src/core/a-node.js

+14-5
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ class ANode extends HTMLElement {
219219
this.computedMixinStr = '';
220220
this.mixinEls.length = 0;
221221
for (i = 0; i < newMixinIds.length; i++) {
222-
this.registerMixin(document.getElementById(newMixinIds[i]));
222+
this.registerMixin(newMixinIds[i]);
223223
}
224224

225225
// Update DOM. Keep track of `computedMixinStr` to not recurse back here after
@@ -240,21 +240,25 @@ class ANode extends HTMLElement {
240240
/**
241241
* From mixin ID, add mixin element to `mixinEls`.
242242
*
243-
* @param {Element} mixinEl
243+
* @param {string} mixinId - ID of the mixin to register.
244244
*/
245-
registerMixin (mixinEl) {
245+
registerMixin (mixinId) {
246246
var compositedMixinIds;
247247
var i;
248248
var mixin;
249+
var mixinEl = document.getElementById(mixinId);
249250

250-
if (!mixinEl) { return; }
251+
if (!mixinEl) {
252+
warn('No mixin was found with id `%s`', mixinId);
253+
return;
254+
}
251255

252256
// Register composited mixins (if mixin has mixins).
253257
mixin = mixinEl.getAttribute('mixin');
254258
if (mixin) {
255259
compositedMixinIds = utils.split(mixin.trim(), /\s+/);
256260
for (i = 0; i < compositedMixinIds.length; i++) {
257-
this.registerMixin(document.getElementById(compositedMixinIds[i]));
261+
this.registerMixin(compositedMixinIds[i]);
258262
}
259263
}
260264

@@ -268,6 +272,11 @@ class ANode extends HTMLElement {
268272
window.HTMLElement.prototype.setAttribute.call(this, attr, newValue);
269273
}
270274

275+
/**
276+
* Removes the mixin element from `mixinEls`.
277+
*
278+
* @param {string} mixinId - ID of the mixin to remove.
279+
*/
271280
unregisterMixin (mixinId) {
272281
var i;
273282
var mixinEls = this.mixinEls;

src/extras/primitives/primitives.js

+36-14
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ module.exports.registerPrimitive = function registerPrimitive (name, definition)
7070
var i;
7171
var mapping;
7272
var mixins;
73-
var path;
7473
var self = this;
7574

7675
// Gather component data from default components.
@@ -79,12 +78,25 @@ module.exports.registerPrimitive = function registerPrimitive (name, definition)
7978
// Factor in mixins to overwrite default components.
8079
mixins = this.getAttribute('mixin');
8180
if (mixins) {
82-
mixins = mixins.trim().split(' ');
81+
mixins = utils.split(mixins.trim(), /\s+/);
8382
mixins.forEach(function applyMixin (mixinId) {
84-
var mixinComponents = self.sceneEl.querySelector('#' + mixinId).componentCache;
85-
Object.keys(mixinComponents).forEach(function setComponent (name) {
86-
data[name] = extend(data[name], mixinComponents[name]);
87-
});
83+
var mixinEl = document.getElementById(mixinId);
84+
if (!mixinEl) { return; }
85+
var rawAttributeCache = mixinEl.rawAttributeCache;
86+
var mixinComponents = mixinEl.componentCache;
87+
for (var name in rawAttributeCache) {
88+
// Check if the attribute matches a mapping.
89+
mapping = self.mappings[name];
90+
if (mapping) {
91+
applyMapping(mapping, rawAttributeCache[name], data);
92+
return;
93+
}
94+
95+
// Check if the attribute belongs to a component.
96+
if (name in mixinComponents) {
97+
data[name] = extend(data[name], mixinComponents[name]);
98+
}
99+
}
88100
});
89101
}
90102

@@ -93,14 +105,7 @@ module.exports.registerPrimitive = function registerPrimitive (name, definition)
93105
attr = this.attributes[i];
94106
mapping = this.mappings[attr.name];
95107
if (mapping) {
96-
path = utils.entity.getComponentPropertyPath(mapping);
97-
if (path.constructor === Array) {
98-
data[path[0]] = data[path[0]] || {};
99-
data[path[0]][path[1]] = attr.value.trim();
100-
} else {
101-
data[path] = attr.value.trim();
102-
}
103-
continue;
108+
applyMapping(mapping, attr.value, data);
104109
}
105110
}
106111

@@ -169,6 +174,23 @@ module.exports.registerPrimitive = function registerPrimitive (name, definition)
169174
return primitiveClass;
170175
};
171176

177+
/**
178+
* Sets the relevant property based on the mapping property path.
179+
*
180+
* @param {string} mapping - The mapped property path.
181+
* @param {string} attrValue - The (raw) attribute value.
182+
* @param {object} data - The data object to apply the mapping to.
183+
*/
184+
function applyMapping (mapping, attrValue, data) {
185+
var path = utils.entity.getComponentPropertyPath(mapping);
186+
if (path.constructor === Array) {
187+
data[path[0]] = data[path[0]] || {};
188+
data[path[0]][path[1]] = attrValue.trim();
189+
} else {
190+
data[path] = attrValue.trim();
191+
}
192+
}
193+
172194
/**
173195
* Add component mappings using schema.
174196
*/

tests/extras/primitives/primitives.test.js

+17
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,23 @@ suite('registerPrimitive (using innerHTML)', function () {
226226
});
227227
});
228228

229+
test('applies mappings to mixin attributes', function (done) {
230+
AFRAME.registerComponent('test', {
231+
schema: {default: 'foo'}
232+
});
233+
primitiveFactory({
234+
defaultComponents: {
235+
material: {color: 'blue'}
236+
},
237+
mappings: {foo: 'material.color'}
238+
}, 'mixin="bar"', function postCreation (el) {
239+
assert.equal(el.getAttribute('material').color, 'purple');
240+
done();
241+
}, function preCreation (sceneEl) {
242+
helpers.mixinFactory('bar', {foo: 'purple'}, sceneEl);
243+
});
244+
});
245+
229246
test('handles mapping to a single-property component', function (done) {
230247
primitiveFactory({
231248
mappings: {

0 commit comments

Comments
 (0)