Skip to content

Instantly share code, notes, and snippets.

@ColinCampbell
Created March 22, 2011 03:19
Show Gist options
  • Select an option

  • Save ColinCampbell/880707 to your computer and use it in GitHub Desktop.

Select an option

Save ColinCampbell/880707 to your computer and use it in GitHub Desktop.
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