Created
March 22, 2011 03:19
-
-
Save ColinCampbell/880707 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/frameworks/core_foundation/tests/views/template_view/handlebars.js b/frameworks/core_foundation/tests/views/template_view/handlebars.js | |
| index 8d80c05..626d0e8 100644 | |
| --- a/frameworks/core_foundation/tests/views/template_view/handlebars.js | |
| +++ b/frameworks/core_foundation/tests/views/template_view/handlebars.js | |
| @@ -578,3 +578,25 @@ test("should be able to bind boolean element attributes using {{bindAttr}}", fun | |
| ok(view.$('input').attr('disabled'), 'attribute exists after update'); | |
| ok(!view.$('input').attr('checked'), 'attribute is not present after update'); | |
| }); | |
| + | |
| +test("should be able to add multiple classes using {{bindAttr class}}", function() { | |
| + var template = SC.Handlebars.compile('<div {{bindAttr class="content.isAwesomeSauce content.isAlsoCool"}}></div>'); | |
| + var content = SC.Object.create({ | |
| + isAwesomeSauce: true, | |
| + isAlsoCool: true | |
| + }); | |
| + | |
| + var view = SC.TemplateView.create({ | |
| + template: template, | |
| + content: content | |
| + }); | |
| + | |
| + view.createLayer(); | |
| + | |
| + ok(view.$('div').hasClass('is-awesome-sauce'), "dasherizes first property and sets classname"); | |
| + ok(view.$('div').hasClass('is-also-cool'), "dasherizes second property and sets classname"); | |
| + | |
| + content.set('isAwesomeSauce', false); | |
| + | |
| + ok(!view.$('div').hasClass('is-awesome-sauce'), "removes dasherized class when property is set to false"); | |
| +}); | |
| \ No newline at end of file | |
| diff --git a/frameworks/handlebars/extensions.js b/frameworks/handlebars/extensions.js | |
| index a38bd11..fa49630 100644 | |
| --- a/frameworks/handlebars/extensions.js | |
| +++ b/frameworks/handlebars/extensions.js | |
| @@ -42,3 +42,59 @@ SC.Handlebars.compile = function(string) { | |
| var environment = new Handlebars.Compiler().compile(ast); | |
| return new SC.Handlebars.JavaScriptCompiler().compile(environment, true); | |
| }; | |
| + | |
| + | |
| +/** | |
| + Determines the classes to add based on an array of bindings (provided as strings), | |
| + as well as adding observers to make sure the classes are up-to-date. | |
| + | |
| + @param {SC.View} view The view at add the classes to | |
| + @param {String} classBindings A string, space-separated, of class bindings to use | |
| + @param {String|Number} id Optional id to scope the observers/jQuery element to | |
| + @returns {Array} An array of class names to add | |
| +*/ | |
| +SC.Handlebars.bindClasses = function(view, classBindings, id) { | |
| + if (!view._classObservers) view._classObservers = {}; | |
| + id = id || '_default'; | |
| + var classObservers = view._classObservers[id], | |
| + ret = []; | |
| + | |
| + // Teardown any existing observers on the view. | |
| + if (classObservers) { | |
| + for (var prop in classObservers) { | |
| + if (classObservers.hasOwnProperty(prop)) { | |
| + view.removeObserver(prop, classObservers[prop]); | |
| + } | |
| + } | |
| + } | |
| + | |
| + classObservers = view._classObservers[id] = {}; | |
| + | |
| + // For each property passed, loop through and setup | |
| + // an observer. | |
| + classBindings.split(' ').forEach(function(property) { | |
| + // Normalize property path to be suitable for use | |
| + // as a class name. For exaple, content.foo.barBaz | |
| + // becomes bar-baz. | |
| + | |
| + var dasherizedProperty = property.split('.').get('lastObject').dasherize(); | |
| + | |
| + // Set up an observer on the view. If the bound property | |
| + // changes, toggle the class name | |
| + var observer = (classObservers[property] = function() { | |
| + var shouldDisplay = view.getPath(property); | |
| + var elem = id !== '_default' ? view.$("[data-handlebars-id='" + id + "']") : view.$(); | |
| + | |
| + if (elem.length === 0) { | |
| + view.removeObserver(property, observer); | |
| + } else { | |
| + elem.toggleClass(dasherizedProperty, shouldDisplay); | |
| + } | |
| + }); | |
| + | |
| + view.addObserver(property, observer); | |
| + if (view.getPath(property)) ret.push(dasherizedProperty); | |
| + }); | |
| + | |
| + return ret; | |
| +}; | |
| \ No newline at end of file | |
| diff --git a/frameworks/handlebars/extensions/bind.js b/frameworks/handlebars/extensions/bind.js | |
| index b573e85..47708ad 100644 | |
| --- a/frameworks/handlebars/extensions/bind.js | |
| +++ b/frameworks/handlebars/extensions/bind.js | |
| @@ -93,7 +93,7 @@ sc_require('extensions'); | |
| })(); | |
| Handlebars.registerHelper('bindAttr', function(options) { | |
| - var attrs = options.hash, attrKeys = SC.keys(options.hash); | |
| + var attrs = options.hash; | |
| var view = options.data.view; | |
| var ret = []; | |
| @@ -102,6 +102,16 @@ Handlebars.registerHelper('bindAttr', function(options) { | |
| // the bound property changes. | |
| var dataId = jQuery.uuid++; | |
| + // Handle classes differently, as we can bind multiple classes | |
| + var classBindings = attrs['class']; | |
| + if (classBindings != null) { | |
| + var classResults = SC.Handlebars.bindClasses(view, classBindings, dataId); | |
| + ret.push('class="'+classResults.join(' ')+'"'); | |
| + delete attrs['class']; | |
| + } | |
| + | |
| + var attrKeys = SC.keys(attrs); | |
| + | |
| // For each attribute passed, create an observer and emit the | |
| // current value of the property as an attribute. | |
| attrKeys.forEach(function(attr) { | |
| diff --git a/frameworks/handlebars/extensions/view.js b/frameworks/handlebars/extensions/view.js | |
| index 735080e..d4d205d 100644 | |
| --- a/frameworks/handlebars/extensions/view.js | |
| +++ b/frameworks/handlebars/extensions/view.js | |
| @@ -64,48 +64,10 @@ SC.Handlebars.ViewHelper = SC.Object.create({ | |
| var classBindings = options.classBinding; | |
| if (classBindings) { | |
| - this.addClassBindings(classBindings, childView, context); | |
| + SC.Handlebars.bindClasses(childView, classBindings).forEach(function(className) { | |
| + context.setClass(className, YES); | |
| + }); | |
| } | |
| - }, | |
| - | |
| - addClassBindings: function(classBindings, view, context) { | |
| - var classObservers = view._classObservers; | |
| - | |
| - // Teardown any existing observers on the view. | |
| - if (classObservers) { | |
| - for (var prop in classObservers) { | |
| - if (classObservers.hasOwnProperty(prop)) { | |
| - view.removeObserver(prop, classObservers[prop]); | |
| - } | |
| - } | |
| - } | |
| - | |
| - classObservers = view._classObservers = {}; | |
| - | |
| - // For each property passed, loop through and setup | |
| - // an observer. | |
| - classBindings.split(' ').forEach(function(property) { | |
| - // Normalize property path to be suitable for use | |
| - // as a class name. For exaple, content.foo.barBaz | |
| - // becomes bar-baz. | |
| - | |
| - var dasherizedProperty = property.split('.').get('lastObject'); | |
| - dasherizedProperty = dasherizedProperty.dasherize(); | |
| - | |
| - // Set up an observer on the view. If the bound property | |
| - // changes, toggle the class name | |
| - var observer = classObservers[property] = function() { | |
| - var shouldDisplay = view.getPath(property); | |
| - var elem = view.$(); | |
| - | |
| - elem.toggleClass(dasherizedProperty, shouldDisplay); | |
| - }; | |
| - | |
| - view.addObserver(property, observer); | |
| - | |
| - // Add the class name to the view | |
| - context.setClass(dasherizedProperty, view.getPath(property)); | |
| - }); | |
| } | |
| }); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment