Created
May 3, 2012 19:35
-
-
Save anonymous/2588583 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/packages/ember-handlebars/lib/helpers/binding.js b/packages/ember-handlebars/lib/helpers/binding.js | |
index dd4fc0f..c0d28a7 100644 | |
--- a/packages/ember-handlebars/lib/helpers/binding.js | |
+++ b/packages/ember-handlebars/lib/helpers/binding.js | |
@@ -13,141 +13,139 @@ var forEach = Ember.ArrayUtils.forEach; | |
var EmberHandlebars = Ember.Handlebars, helpers = EmberHandlebars.helpers; | |
-(function() { | |
- // Binds a property into the DOM. This will create a hook in DOM that the | |
- // KVO system will look for and update if the property changes. | |
- var bind = function(property, options, preserveContext, shouldDisplay, valueNormalizer) { | |
- var data = options.data, | |
- fn = options.fn, | |
- inverse = options.inverse, | |
- view = data.view, | |
- ctx = this, | |
- normalized; | |
- | |
- normalized = Ember.Handlebars.normalizePath(ctx, property, data); | |
- | |
- ctx = normalized.root; | |
- property = normalized.path; | |
- | |
- // Set up observers for observable objects | |
- if ('object' === typeof this) { | |
- // Create the view that will wrap the output of this template/property | |
- // and add it to the nearest view's childViews array. | |
- // See the documentation of Ember._HandlebarsBoundView for more. | |
- var bindView = view.createChildView(Ember._HandlebarsBoundView, { | |
- preserveContext: preserveContext, | |
- shouldDisplayFunc: shouldDisplay, | |
- valueNormalizerFunc: valueNormalizer, | |
- displayTemplate: fn, | |
- inverseTemplate: inverse, | |
- property: property, | |
- previousContext: ctx, | |
- isEscaped: options.hash.escaped, | |
- templateData: options.data | |
- }); | |
- | |
- view.appendChild(bindView); | |
- | |
- /** @private */ | |
- var observer = function() { | |
- Ember.run.once(bindView, 'rerenderIfNeeded'); | |
- }; | |
- | |
- // Observes the given property on the context and | |
- // tells the Ember._BindableSpan to re-render. If property | |
- // is an empty string, we are printing the current context | |
- // object ({{this}}) so updating it is not our responsibility. | |
- if (property !== '') { | |
- Ember.addObserver(ctx, property, observer); | |
- } | |
- } else { | |
- // The object is not observable, so just render it out and | |
- // be done with it. | |
- data.buffer.push(getPath(this, property, options)); | |
- } | |
- }; | |
+// Binds a property into the DOM. This will create a hook in DOM that the | |
+// KVO system will look for and update if the property changes. | |
+var bind = function(property, options, preserveContext, shouldDisplay, valueNormalizer) { | |
+ var data = options.data, | |
+ fn = options.fn, | |
+ inverse = options.inverse, | |
+ view = data.view, | |
+ ctx = this, | |
+ normalized; | |
+ | |
+ normalized = Ember.Handlebars.normalizePath(ctx, property, data); | |
+ | |
+ ctx = normalized.root; | |
+ property = normalized.path; | |
+ | |
+ // Set up observers for observable objects | |
+ if ('object' === typeof this) { | |
+ // Create the view that will wrap the output of this template/property | |
+ // and add it to the nearest view's childViews array. | |
+ // See the documentation of Ember._HandlebarsBoundView for more. | |
+ var bindView = view.createChildView(Ember._HandlebarsBoundView, { | |
+ preserveContext: preserveContext, | |
+ shouldDisplayFunc: shouldDisplay, | |
+ valueNormalizerFunc: valueNormalizer, | |
+ displayTemplate: fn, | |
+ inverseTemplate: inverse, | |
+ property: property, | |
+ previousContext: ctx, | |
+ isEscaped: options.hash.escaped, | |
+ templateData: options.data | |
+ }); | |
- /** | |
- '_triageMustache' is used internally select between a binding and helper for | |
- the given context. Until this point, it would be hard to determine if the | |
- mustache is a property reference or a regular helper reference. This triage | |
- helper resolves that. | |
- | |
- This would not be typically invoked by directly. | |
- | |
- @private | |
- @name Handlebars.helpers._triageMustache | |
- @param {String} property Property/helperID to triage | |
- @param {Function} fn Context to provide for rendering | |
- @returns {String} HTML string | |
- */ | |
- EmberHandlebars.registerHelper('_triageMustache', function(property, fn) { | |
- Ember.assert("You cannot pass more than one argument to the _triageMustache helper", arguments.length <= 2); | |
- if (helpers[property]) { | |
- return helpers[property].call(this, fn); | |
- } | |
- else { | |
- return helpers.bind.apply(this, arguments); | |
+ view.appendChild(bindView); | |
+ | |
+ /** @private */ | |
+ var observer = function() { | |
+ Ember.run.once(bindView, 'rerenderIfNeeded'); | |
+ }; | |
+ | |
+ // Observes the given property on the context and | |
+ // tells the Ember._BindableSpan to re-render. If property | |
+ // is an empty string, we are printing the current context | |
+ // object ({{this}}) so updating it is not our responsibility. | |
+ if (property !== '') { | |
+ Ember.addObserver(ctx, property, observer); | |
} | |
- }); | |
+ } else { | |
+ // The object is not observable, so just render it out and | |
+ // be done with it. | |
+ data.buffer.push(getPath(this, property, options)); | |
+ } | |
+}; | |
- /** | |
- `bind` can be used to display a value, then update that value if it | |
- changes. For example, if you wanted to print the `title` property of | |
- `content`: | |
+/** | |
+ '_triageMustache' is used internally select between a binding and helper for | |
+ the given context. Until this point, it would be hard to determine if the | |
+ mustache is a property reference or a regular helper reference. This triage | |
+ helper resolves that. | |
- {{bind "content.title"}} | |
+ This would not be typically invoked by directly. | |
- This will return the `title` property as a string, then create a new | |
- observer at the specified path. If it changes, it will update the value in | |
- DOM. Note that if you need to support IE7 and IE8 you must modify the | |
- model objects properties using Ember.get() and Ember.set() for this to work as | |
- it relies on Ember's KVO system. For all other browsers this will be handled | |
- for you automatically. | |
+ @private | |
+ @name Handlebars.helpers._triageMustache | |
+ @param {String} property Property/helperID to triage | |
+ @param {Function} fn Context to provide for rendering | |
+ @returns {String} HTML string | |
+*/ | |
+EmberHandlebars.registerHelper('_triageMustache', function(property, fn) { | |
+ Ember.assert("You cannot pass more than one argument to the _triageMustache helper", arguments.length <= 2); | |
+ if (helpers[property]) { | |
+ return helpers[property].call(this, fn); | |
+ } | |
+ else { | |
+ return helpers.bind.apply(this, arguments); | |
+ } | |
+}); | |
- @private | |
- @name Handlebars.helpers.bind | |
- @param {String} property Property to bind | |
- @param {Function} fn Context to provide for rendering | |
- @returns {String} HTML string | |
- */ | |
- EmberHandlebars.registerHelper('bind', function(property, fn) { | |
- Ember.assert("You cannot pass more than one argument to the bind helper", arguments.length <= 2); | |
+/** | |
+ `bind` can be used to display a value, then update that value if it | |
+ changes. For example, if you wanted to print the `title` property of | |
+ `content`: | |
+ | |
+ {{bind "content.title"}} | |
+ | |
+ This will return the `title` property as a string, then create a new | |
+ observer at the specified path. If it changes, it will update the value in | |
+ DOM. Note that if you need to support IE7 and IE8 you must modify the | |
+ model objects properties using Ember.get() and Ember.set() for this to work as | |
+ it relies on Ember's KVO system. For all other browsers this will be handled | |
+ for you automatically. | |
+ | |
+ @private | |
+ @name Handlebars.helpers.bind | |
+ @param {String} property Property to bind | |
+ @param {Function} fn Context to provide for rendering | |
+ @returns {String} HTML string | |
+*/ | |
+EmberHandlebars.registerHelper('bind', function(property, fn) { | |
+ Ember.assert("You cannot pass more than one argument to the bind helper", arguments.length <= 2); | |
- var context = (fn.contexts && fn.contexts[0]) || this; | |
+ var context = (fn.contexts && fn.contexts[0]) || this; | |
- return bind.call(context, property, fn, false, function(result) { | |
- return !Ember.none(result); | |
- }); | |
+ return bind.call(context, property, fn, false, function(result) { | |
+ return !Ember.none(result); | |
}); | |
+}); | |
- /** | |
- Use the `boundIf` helper to create a conditional that re-evaluates | |
- whenever the bound value changes. | |
- | |
- {{#boundIf "content.shouldDisplayTitle"}} | |
- {{content.title}} | |
- {{/boundIf}} | |
- | |
- @private | |
- @name Handlebars.helpers.boundIf | |
- @param {String} property Property to bind | |
- @param {Function} fn Context to provide for rendering | |
- @returns {String} HTML string | |
- */ | |
- EmberHandlebars.registerHelper('boundIf', function(property, fn) { | |
- var context = (fn.contexts && fn.contexts[0]) || this; | |
- var func = function(result) { | |
- if (Ember.typeOf(result) === 'array') { | |
- return get(result, 'length') !== 0; | |
- } else { | |
- return !!result; | |
- } | |
- }; | |
+/** | |
+ Use the `boundIf` helper to create a conditional that re-evaluates | |
+ whenever the bound value changes. | |
- return bind.call(context, property, fn, true, func, func); | |
- }); | |
-})(); | |
+ {{#boundIf "content.shouldDisplayTitle"}} | |
+ {{content.title}} | |
+ {{/boundIf}} | |
+ | |
+ @private | |
+ @name Handlebars.helpers.boundIf | |
+ @param {String} property Property to bind | |
+ @param {Function} fn Context to provide for rendering | |
+ @returns {String} HTML string | |
+*/ | |
+EmberHandlebars.registerHelper('boundIf', function(property, fn) { | |
+ var context = (fn.contexts && fn.contexts[0]) || this; | |
+ var func = function(result) { | |
+ if (Ember.typeOf(result) === 'array') { | |
+ return get(result, 'length') !== 0; | |
+ } else { | |
+ return !!result; | |
+ } | |
+ }; | |
+ | |
+ return bind.call(context, property, fn, true, func, func); | |
+}); | |
/** | |
@name Handlebars.helpers.with | |
@@ -156,10 +154,27 @@ var EmberHandlebars = Ember.Handlebars, helpers = EmberHandlebars.helpers; | |
@returns {String} HTML string | |
*/ | |
EmberHandlebars.registerHelper('with', function(context, options) { | |
- Ember.assert("You must pass exactly one argument to the with helper", arguments.length === 2); | |
- Ember.assert("You must pass a block to the with helper", options.fn && options.fn !== Handlebars.VM.noop); | |
+ if (arguments.length === 4) { | |
+ var keywordName, path; | |
+ | |
+ Ember.assert("If you pass more than one argument to the with helper, it must be in the form #with foo as bar", arguments[1] === "as"); | |
+ options = arguments[3]; | |
+ preserveContext = true; | |
+ keywordName = arguments[2]; | |
+ path = arguments[0]; | |
- return helpers.bind.call(options.contexts[0], context, options); | |
+ Ember.assert("You must pass a block to the with helper", options.fn && options.fn !== Handlebars.VM.noop); | |
+ | |
+ options.data.keywords[keywordName] = getPath(this, path); | |
+ | |
+ return bind.call(this, path, options.fn, true, function(result) { | |
+ return !Ember.none(result); | |
+ }); | |
+ } else { | |
+ Ember.assert("You must pass exactly one argument to the with helper", arguments.length === 2); | |
+ Ember.assert("You must pass a block to the with helper", options.fn && options.fn !== Handlebars.VM.noop); | |
+ return helpers.bind.call(options.contexts[0], context, options); | |
+ } | |
}); | |
diff --git a/packages/ember-handlebars/tests/helpers/with_test.js b/packages/ember-handlebars/tests/helpers/with_test.js | |
new file mode 100644 | |
index 0000000..cdf98f9 | |
--- /dev/null | |
+++ b/packages/ember-handlebars/tests/helpers/with_test.js | |
@@ -0,0 +1,17 @@ | |
+var appendView = function(view) { | |
+ Ember.run(function() { view.appendTo('#qunit-fixture'); }); | |
+}; | |
+ | |
+module("Handlebars {{#with}} helper"); | |
+ | |
+test("it should support #with foo as bar", function() { | |
+ var view = Ember.View.create({ | |
+ template: Ember.Handlebars.compile("{{#with person as tom}}{{title}}: {{tom.name}}{{/with}}"), | |
+ title: "Señor Engineer", | |
+ person: { name: "Tom Dale" } | |
+ }); | |
+ | |
+ appendView(view); | |
+ | |
+ equal(view.$().text(), "Señor Engineer: Tom Dale", "should be properly scoped"); | |
+}); | |
diff --git a/packages/ember-views/lib/views/view.js b/packages/ember-views/lib/views/view.js | |
index 63ce13c..43b1b76 100644 | |
--- a/packages/ember-views/lib/views/view.js | |
+++ b/packages/ember-views/lib/views/view.js | |
@@ -743,20 +743,23 @@ Ember.View = Ember.Object.extend(Ember.Evented, | |
templateData = this.get('templateData'), | |
controller = this.get('controller'); | |
+ var keywords = templateData ? Ember.copy(templateData.keywords) : {}; | |
+ keywords.view = get(this, 'concreteView'); | |
+ | |
+ // If the view has a controller specified, make it available to the | |
+ // template. If not, pass along the parent template's controller, | |
+ // if it exists. | |
+ if (controller) { | |
+ keywords.controller = controller; | |
+ } | |
+ | |
var data = { | |
view: this, | |
buffer: buffer, | |
isRenderData: true, | |
- keywords: { | |
- view: get(this, 'concreteView') | |
- } | |
+ keywords: keywords | |
}; | |
- // If the view has a controller specified, make it available to the | |
- // template. If not, pass along the parent template's controller, | |
- // if it exists. | |
- data.keywords.controller = controller || (templateData && templateData.keywords.controller); | |
- | |
// Invoke the template with the provided template context, which | |
// is the view by default. A hash of data is also passed that provides | |
// the template with access to the view and render buffer. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment