@@ -214,6 +214,79 @@ function $CompileProvider($provide) {
214214 }
215215 } ;
216216
217+ var Attributes = function ( element , attr ) {
218+ this . $$element = element ;
219+ this . $$observers = { } ;
220+ this . $attr = attr || { } ;
221+ } ;
222+
223+ Attributes . prototype = {
224+ $normalize : directiveNormalize ,
225+
226+
227+ /**
228+ * Set a normalized attribute on the element in a way such that all directives
229+ * can share the attribute. This function properly handles boolean attributes.
230+ * @param {string } key Normalized key. (ie ngAttribute)
231+ * @param {string|boolean } value The value to set. If `null` attribute will be deleted.
232+ * @param {boolean= } writeAttr If false, does not write the value to DOM element attribute.
233+ * Defaults to true.
234+ * @param {string= } attrName Optional none normalized name. Defaults to key.
235+ */
236+ $set : function ( key , value , writeAttr , attrName ) {
237+ var booleanKey = isBooleanAttr ( this . $$element [ 0 ] , key . toLowerCase ( ) ) ;
238+
239+ if ( booleanKey ) {
240+ this . $$element . prop ( key , value ) ;
241+ attrName = booleanKey ;
242+ }
243+
244+ this [ key ] = value ;
245+
246+ // translate normalized key to actual key
247+ if ( attrName ) {
248+ this . $attr [ key ] = attrName ;
249+ } else {
250+ attrName = this . $attr [ key ] ;
251+ if ( ! attrName ) {
252+ this . $attr [ key ] = attrName = snake_case ( key , '-' ) ;
253+ }
254+ }
255+
256+ if ( writeAttr !== false ) {
257+ if ( value === null || value === undefined ) {
258+ this . $$element . removeAttr ( attrName ) ;
259+ } else {
260+ this . $$element . attr ( attrName , value ) ;
261+ }
262+ }
263+
264+ // fire observers
265+ forEach ( this . $$observers [ key ] , function ( fn ) {
266+ try {
267+ fn ( value ) ;
268+ } catch ( e ) {
269+ $exceptionHandler ( e ) ;
270+ }
271+ } ) ;
272+ } ,
273+
274+
275+ /**
276+ * Observe an interpolated attribute.
277+ * The observer will never be called, if given attribute is not interpolated.
278+ *
279+ * @param {string } key Normalized key. (ie ngAttribute) .
280+ * @param {function(*) } fn Function that will be called whenever the attribute value changes.
281+ */
282+ $observe : function ( key , fn ) {
283+ // keep only observers for interpolated attrs
284+ if ( this . $$observers [ key ] ) {
285+ this . $$observers [ key ] . push ( fn ) ;
286+ }
287+ }
288+ } ;
289+
217290 return compile ;
218291
219292 //================================
@@ -278,13 +351,8 @@ function $CompileProvider($provide) {
278351 directiveLinkingFn , childLinkingFn , directives , attrs , linkingFnFound ;
279352
280353 for ( var i = 0 , ii = nodeList . length ; i < ii ; i ++ ) {
281- attrs = {
282- $attr : { } ,
283- $normalize : directiveNormalize ,
284- $set : attrSetter ,
285- $observe : interpolatedAttrObserve ,
286- $observers : { }
287- } ;
354+ attrs = new Attributes ( ) ;
355+
288356 // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
289357 directives = collectDirectives ( nodeList [ i ] , [ ] , attrs , maxPriority ) ;
290358
@@ -441,7 +509,7 @@ function $CompileProvider($provide) {
441509 newIsolatedScopeDirective = null ,
442510 templateDirective = null ,
443511 delayedLinkingFn = null ,
444- element = templateAttrs . $element = jqLite ( templateNode ) ,
512+ element = templateAttrs . $$ element = jqLite ( templateNode ) ,
445513 directive ,
446514 directiveName ,
447515 template ,
@@ -485,7 +553,7 @@ function $CompileProvider($provide) {
485553 terminalPriority = directive . priority ;
486554 if ( directiveValue == 'element' ) {
487555 template = jqLite ( templateNode ) ;
488- templateNode = ( element = templateAttrs . $element = jqLite (
556+ templateNode = ( element = templateAttrs . $$ element = jqLite (
489557 '<!-- ' + directiveName + ': ' + templateAttrs [ directiveName ] + ' -->' ) ) [ 0 ] ;
490558 replaceWith ( rootElement , jqLite ( template [ 0 ] ) , templateNode ) ;
491559 childTranscludeFn = compile ( template , transcludeFn , terminalPriority ) ;
@@ -609,11 +677,9 @@ function $CompileProvider($provide) {
609677 if ( templateNode === linkNode ) {
610678 attrs = templateAttrs ;
611679 } else {
612- attrs = shallowCopy ( templateAttrs ) ;
613- attrs . $element = jqLite ( linkNode ) ;
614- attrs . $observers = { } ;
680+ attrs = shallowCopy ( templateAttrs , new Attributes ( jqLite ( linkNode ) , templateAttrs . $attr ) ) ;
615681 }
616- element = attrs . $element ;
682+ element = attrs . $$ element ;
617683
618684 if ( newScopeDirective && isObject ( newScopeDirective . scope ) ) {
619685 forEach ( newScopeDirective . scope , function ( mode , name ) {
@@ -720,7 +786,7 @@ function $CompileProvider($provide) {
720786 function mergeTemplateAttributes ( dst , src ) {
721787 var srcAttr = src . $attr ,
722788 dstAttr = dst . $attr ,
723- element = dst . $element ;
789+ element = dst . $$ element ;
724790 // reapply the old attributes to the new element
725791 forEach ( dst , function ( value , key ) {
726792 if ( key . charAt ( 0 ) != '$' ) {
@@ -873,7 +939,7 @@ function $CompileProvider($provide) {
873939
874940 // we define observers array only for interpolated attrs
875941 // and ignore observers for non interpolated attrs to save some memory
876- attr . $observers [ name ] = [ ] ;
942+ attr . $$ observers [ name ] = [ ] ;
877943 attr [ name ] = undefined ;
878944 scope . $watch ( interpolateFn , function ( value ) {
879945 attr . $set ( name , value ) ;
@@ -910,70 +976,6 @@ function $CompileProvider($provide) {
910976 }
911977 element [ 0 ] = newNode ;
912978 }
913-
914-
915- /**
916- * Set a normalized attribute on the element in a way such that all directives
917- * can share the attribute. This function properly handles boolean attributes.
918- * @param {string } key Normalized key. (ie ngAttribute)
919- * @param {string|boolean } value The value to set. If `null` attribute will be deleted.
920- * @param {boolean= } writeAttr If false, does not write the value to DOM element attribute.
921- * Defaults to true.
922- * @param {string= } attrName Optional none normalized name. Defaults to key.
923- */
924- function attrSetter ( key , value , writeAttr , attrName ) {
925- var booleanKey = isBooleanAttr ( this . $element [ 0 ] , key . toLowerCase ( ) ) ;
926-
927- if ( booleanKey ) {
928- this . $element . prop ( key , value ) ;
929- attrName = booleanKey ;
930- }
931-
932- this [ key ] = value ;
933-
934- // translate normalized key to actual key
935- if ( attrName ) {
936- this . $attr [ key ] = attrName ;
937- } else {
938- attrName = this . $attr [ key ] ;
939- if ( ! attrName ) {
940- this . $attr [ key ] = attrName = snake_case ( key , '-' ) ;
941- }
942- }
943-
944- if ( writeAttr !== false ) {
945- if ( value === null || value === undefined ) {
946- this . $element . removeAttr ( attrName ) ;
947- } else {
948- this . $element . attr ( attrName , value ) ;
949- }
950- }
951-
952-
953- // fire observers
954- forEach ( this . $observers [ key ] , function ( fn ) {
955- try {
956- fn ( value ) ;
957- } catch ( e ) {
958- $exceptionHandler ( e ) ;
959- }
960- } ) ;
961- }
962-
963-
964- /**
965- * Observe an interpolated attribute.
966- * The observer will never be called, if given attribute is not interpolated.
967- *
968- * @param {string } key Normalized key. (ie ngAttribute) .
969- * @param {function(*) } fn Function that will be called whenever the attribute value changes.
970- */
971- function interpolatedAttrObserve ( key , fn ) {
972- // keep only observers for interpolated attrs
973- if ( this . $observers [ key ] ) {
974- this . $observers [ key ] . push ( fn ) ;
975- }
976- }
977979 } ] ;
978980}
979981
0 commit comments