diff --git a/src/ui/styler/NaFieldStyler.js b/src/ui/styler/NaFieldStyler.js index 0a66723..78bdbcd 100644 --- a/src/ui/styler/NaFieldStyler.js +++ b/src/ui/styler/NaFieldStyler.js @@ -59,6 +59,14 @@ module.exports = Class( 'NaFieldStyler' ) // removed once jQuery is eradicated from the framework element.style = ''; + if ( this.isSubField( element ) ) + { + // this is a child of another field; don't consider it a + // containing row, since we don't want our operations affecting + // it + return; + } + for ( var i in row ) { this.addClass( row[ i ], 'hidden' ); @@ -79,6 +87,34 @@ module.exports = Class( 'NaFieldStyler' ) 'public revokeStyle': function( field, element, row ) { this.removeClass( element, 'hidden' ); + + if ( this.isSubField( element ) ) + { + return; + } + this.removeClass( row, 'hidden' ); + }, + + + /** + * Determine whether element ELEMENT represents a sub-field + * + * A sub-field is a field within a field; the distinction is important + * because we probably don't want operations on a sub-field affecting + * its parent. + * + * @todo: move somewhere else (Field perhaps?) + * + * @param {HTMLElement} element DOM element associated with field + * + * @return {boolean} whether ELEMENT represents a sub-field + */ + 'protected isSubField': function( element ) + { + var parent = element.parentElement; + + // ES3-compatible (don't use classList) + return !!( parent && /\bwidget\b/.test( parent.className ) ); } } ); diff --git a/test/ui/styler/NaFieldStylerTest.js b/test/ui/styler/NaFieldStylerTest.js index f06767a..bbba515 100644 --- a/test/ui/styler/NaFieldStylerTest.js +++ b/test/ui/styler/NaFieldStylerTest.js @@ -68,6 +68,50 @@ describe( 'ui.styler.NaFieldStyler', function() expect( ele.style ).to.equal( '' ); } ); } ); + + + it( 'does not set class on subfield parents', function() + { + var element = { + className: '', + parentElement: { className: 'widget' } + }; + + var r1 = { className: '' }, + r2 = { className: '' }, + row = [ r1, r2 ]; + + Sut().applyStyle( {}, element, row ); + + expect( element.className ).to.match( /\bhidden\b/ ); + + [ r1, r2 ].forEach( function( ele ) + { + expect( ele.className ).to.equal( '' ); + } ); + } ); + + + it( 'does not clears style subfield parents', function() + { + var element = { + style: 'foo', + parentElement: { className: 'widget' } + }; + + var r1 = { style: 'foo' }, + r2 = { style: 'foo' }, + row = [ r1, r2 ]; + + Sut().applyStyle( {}, element, row ); + + expect( element.style ).to.equal( '' ); + + [ r1, r2 ].forEach( function( ele ) + { + expect( ele.style ).to.equal( 'foo' ); + } ); + } ); } ); @@ -104,5 +148,68 @@ describe( 'ui.styler.NaFieldStyler', function() expect( ele.style ).to.equal( 'foo' ); } ); } ); + + + it( 'does not remove hidden class on subfield parents', function() + { + var element = { + className: 'foo hidden', + parentElement: { className: 'widget' } + }; + + var r1 = { className: 'foo hidden' }, + r2 = { className: 'foo hidden' }, + row = [ r1, r2 ]; + + Sut().revokeStyle( {}, element, row ); + + expect( element.className ).to.not.match( /\bhidden\b/ ); + expect( element.className ).to.match( /foo/ ); + + [ r1, r2 ].forEach( function( ele ) + { + expect( ele.className ).to.equal( 'foo hidden' ); + } ); + } ); + } ); + + + describe( 'protected API', function() + { + describe( '#isSubField', function() + { + it( 'recognizes parent widget class as subfield', function() + { + var element = { + className: '', + parentElement: { className: 'widget' } + }; + + expect( protSut().protIsSubField( element ) ) + .to.be.true; + } ); + + + it( 'missing parent widget class is non-subfield', function() + { + var element = { + className: '', + }; + + expect( protSut().protIsSubField( element ) ) + .to.be.false; + } ); + } ); } ); } ); + + +function protSut() +{ + return Class.extend( Sut, { + protIsSubField: function( element ) + { + return this.isSubField( element ); + } + } )(); +}