@@ -3,9 +3,10 @@ var registerElement = require('./a-register-element').registerElement;
33var isNode = require ( './a-register-element' ) . isNode ;
44var utils = require ( '../utils/' ) ;
55
6- var bind = utils . bind ;
76var warn = utils . debug ( 'core:a-node:warn' ) ;
87
8+ var MIXIN_OBSERVER_CONFIG = { attributes : true } ;
9+
910/**
1011 * Base class for A-Frame that manages loading of objects.
1112 *
@@ -16,6 +17,7 @@ module.exports = registerElement('a-node', {
1617 prototype : Object . create ( window . HTMLElement . prototype , {
1718 createdCallback : {
1819 value : function ( ) {
20+ this . computedMixinStr = '' ;
1921 this . hasLoaded = false ;
2022 this . isNode = true ;
2123 this . mixinEls = [ ] ;
@@ -37,15 +39,25 @@ module.exports = registerElement('a-node', {
3739 this . hasLoaded = false ;
3840 this . emit ( 'nodeready' , undefined , false ) ;
3941
40- mixins = this . getAttribute ( 'mixin' ) ;
41- if ( mixins ) { this . updateMixins ( mixins ) ; }
42+ if ( ! this . isMixin ) {
43+ mixins = this . getAttribute ( 'mixin' ) ;
44+ if ( mixins ) { this . updateMixins ( mixins ) ; }
45+ }
4246 } ,
4347 writable : window . debug
4448 } ,
4549
50+ /**
51+ * Handle mixin.
52+ */
4653 attributeChangedCallback : {
4754 value : function ( attr , oldVal , newVal ) {
48- if ( attr === 'mixin' ) { this . updateMixins ( newVal , oldVal ) ; }
55+ // Ignore if `<a-node>` code is just updating computed mixin in the DOM.
56+ if ( newVal === this . computedMixinStr ) { return ; }
57+
58+ if ( attr === 'mixin' && ! this . isMixin ) {
59+ this . updateMixins ( newVal , oldVal ) ;
60+ }
4961 }
5062 } ,
5163
@@ -128,32 +140,76 @@ module.exports = registerElement('a-node', {
128140 } ,
129141
130142 /**
131- * Remove old mixins and mixin listeners.
132- * Add new mixins and mixin listeners.
143+ * Unregister old mixins and listeners.
144+ * Register new mixins and listeners.
145+ * Registering means to update `this.mixinEls` with listeners.
133146 */
134147 updateMixins : {
135- value : function ( newMixins , oldMixins ) {
136- var newMixinIds = newMixins ? newMixins . trim ( ) . split ( / \s + / ) : [ ] ;
137- var oldMixinIds = oldMixins ? oldMixins . trim ( ) . split ( / \s + / ) : [ ] ;
148+ value : ( function ( ) {
149+ var newMixinIdArray = [ ] ;
150+ var oldMixinIdArray = [ ] ;
138151
139- // Unregister old mixins.
140- oldMixinIds . filter ( function ( i ) {
141- return newMixinIds . indexOf ( i ) < 0 ;
142- } ) . forEach ( bind ( this . unregisterMixin , this ) ) ;
152+ return function ( newMixins , oldMixins ) {
153+ var i ;
154+ var newMixinIds ;
155+ var oldMixinIds ;
143156
144- // Register new mixins.
145- this . mixinEls = [ ] ;
146- newMixinIds . forEach ( bind ( this . registerMixin , this ) ) ;
147- }
157+ newMixinIdArray . length = 0 ;
158+ oldMixinIdArray . length = 0 ;
159+ newMixinIds = newMixins ? utils . split ( newMixins . trim ( ) , / \s + / ) : newMixinIdArray ;
160+ oldMixinIds = oldMixins ? utils . split ( oldMixins . trim ( ) , / \s + / ) : oldMixinIdArray ;
161+
162+ // Unregister old mixins.
163+ for ( i = 0 ; i < oldMixinIds . length ; i ++ ) {
164+ if ( newMixinIds . indexOf ( oldMixinIds [ i ] ) === - 1 ) {
165+ this . unregisterMixin ( oldMixinIds [ i ] ) ;
166+ }
167+ }
168+
169+ // Register new mixins.
170+ this . computedMixinStr = '' ;
171+ this . mixinEls . length = 0 ;
172+ for ( i = 0 ; i < newMixinIds . length ; i ++ ) {
173+ this . registerMixin ( document . getElementById ( newMixinIds [ i ] ) ) ;
174+ }
175+
176+ // Update DOM. Keep track of `computedMixinStr` to not recurse back here after
177+ // update.
178+ if ( this . computedMixinStr ) {
179+ this . computedMixinStr = this . computedMixinStr . trim ( ) ;
180+ window . HTMLElement . prototype . setAttribute . call ( this , 'mixin' ,
181+ this . computedMixinStr ) ;
182+ }
183+ } ;
184+ } ) ( )
148185 } ,
149186
187+ /**
188+ * From mixin ID, add mixin element to `mixinEls`.
189+ *
190+ * @param {Element } mixinEl
191+ */
150192 registerMixin : {
151- value : function ( mixinId ) {
152- if ( ! this . sceneEl ) { return ; }
153- var mixinEl = this . sceneEl . querySelector ( 'a-mixin#' + mixinId ) ;
193+ value : function ( mixinEl ) {
194+ var compositedMixinIds ;
195+ var i ;
196+ var mixin ;
197+
154198 if ( ! mixinEl ) { return ; }
155- this . attachMixinListener ( mixinEl ) ;
199+
200+ // Register composited mixins (if mixin has mixins).
201+ mixin = mixinEl . getAttribute ( 'mixin' ) ;
202+ if ( mixin ) {
203+ compositedMixinIds = utils . split ( mixin . trim ( ) , / \s + / ) ;
204+ for ( i = 0 ; i < compositedMixinIds . length ; i ++ ) {
205+ this . registerMixin ( document . getElementById ( compositedMixinIds [ i ] ) ) ;
206+ }
207+ }
208+
209+ // Register mixin.
210+ this . computedMixinStr = this . computedMixinStr + ' ' + mixinEl . id ;
156211 this . mixinEls . push ( mixinEl ) ;
212+ this . attachMixinListener ( mixinEl ) ;
157213 }
158214 } ,
159215
@@ -166,9 +222,9 @@ module.exports = registerElement('a-node', {
166222
167223 unregisterMixin : {
168224 value : function ( mixinId ) {
225+ var i ;
169226 var mixinEls = this . mixinEls ;
170227 var mixinEl ;
171- var i ;
172228 for ( i = 0 ; i < mixinEls . length ; ++ i ) {
173229 mixinEl = mixinEls [ i ] ;
174230 if ( mixinId === mixinEl . id ) {
@@ -189,19 +245,27 @@ module.exports = registerElement('a-node', {
189245 }
190246 } ,
191247
248+ /**
249+ * Add mutation observer from entity to mixin.
250+ */
192251 attachMixinListener : {
193252 value : function ( mixinEl ) {
253+ var currentObserver ;
254+ var mixinId ;
255+ var observer ;
194256 var self = this ;
195- var mixinId = mixinEl . id ;
196- var currentObserver = this . mixinObservers [ mixinId ] ;
257+
197258 if ( ! mixinEl ) { return ; }
259+
260+ mixinId = mixinEl . id ;
261+ currentObserver = this . mixinObservers [ mixinId ] ;
198262 if ( currentObserver ) { return ; }
199- var observer = new MutationObserver ( function ( mutations ) {
200- var attr = mutations [ 0 ] . attributeName ;
201- self . handleMixinUpdate ( attr ) ;
263+
264+ // Add observer.
265+ observer = new MutationObserver ( function ( mutations ) {
266+ self . handleMixinUpdate ( mutations [ 0 ] . attributeName ) ;
202267 } ) ;
203- var config = { attributes : true } ;
204- observer . observe ( mixinEl , config ) ;
268+ observer . observe ( mixinEl , MIXIN_OBSERVER_CONFIG ) ;
205269 this . mixinObservers [ mixinId ] = observer ;
206270 }
207271 } ,
0 commit comments