From ba18614c2f7bc7ad98f2025b586d0637a997aedc Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 27 Dec 2011 19:00:00 -0600 Subject: [PATCH] Bind DOM events to view methods based on element attributes. For example, if you give an element the attribute click: 'elementClicked', the template will bind a click event to that element which calls the elementClicked method on the view. --- spec/stdlib/template-spec.coffee | 21 ++++++++++++++++++--- src/stdlib/template.coffee | 19 +++++++++++++++++-- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/spec/stdlib/template-spec.coffee b/spec/stdlib/template-spec.coffee index 184fd0cae..e8d409ccb 100644 --- a/spec/stdlib/template-spec.coffee +++ b/spec/stdlib/template-spec.coffee @@ -14,13 +14,15 @@ fdescribe "Template", -> list: -> @ol => - @li outlet: 'li1', class: 'foo', "one" - @li outlet: 'li2', class: 'bar', "two" + @li outlet: 'li1', click: 'li1Clicked', class: 'foo', "one" + @li outlet: 'li2', keypress:'li2Keypressed', class: 'bar', "two" viewProperties: initialize: (attrs) -> @initializeCalledWith = attrs - foo: "bar" + foo: "bar", + li1Clicked: ->, + li2Keypressed: -> view = Foo.build(title: "Zebra") @@ -43,3 +45,16 @@ fdescribe "Template", -> expect(view.li1).toMatchSelector("li.foo:contains(one)") expect(view.li2).toMatchSelector("li.bar:contains(two)") + it "binds events for elements with event name attributes", -> + spyOn(view, 'li1Clicked') + spyOn(view, 'li2Keypressed') + view.li1.click() + expect(view.li1Clicked).toHaveBeenCalled() + expect(view.li2Keypressed).not.toHaveBeenCalled() + + view.li1Clicked.reset() + + view.li2.keypress() + expect(view.li2Keypressed).toHaveBeenCalled() + expect(view.li1Clicked).not.toHaveBeenCalled() + diff --git a/src/stdlib/template.coffee b/src/stdlib/template.coffee index cb4f7a31f..43c723cf4 100644 --- a/src/stdlib/template.coffee +++ b/src/stdlib/template.coffee @@ -4,11 +4,15 @@ Builder = require 'template/builder' module.exports = class Template + @events: 'blur change click dblclick error focus keydown + keypress keyup load mousedown mousemove mouseout mouseover + mouseup resize scroll select submit unload'.split /\s+/ + @buildTagMethod: (name) -> this.prototype[name] = (args...) -> @builder.tag(name, args...) - _.each(Builder.elements.normal, (name) => @buildTagMethod(name)) - _.each(Builder.elements.void, (name) => @buildTagMethod(name)) + @buildTagMethod(name) for name in Builder.elements.normal + @buildTagMethod(name) for name in Builder.elements.void @build: (attributes) -> (new this).build(attributes) @@ -18,6 +22,7 @@ class Template @content(attributes) view = @builder.toFragment() @wireOutlets(view) + @bindEvents(view) if @viewProperties $.extend(view, @viewProperties) view.initialize?(attributes) @@ -28,3 +33,13 @@ class Template elt = $(this) outletName = elt.attr('outlet') view[outletName] = elt + + bindEvents: (view) -> + for event in this.constructor.events + view.find("[#{event}]").each -> + elt = $(this) + methodName = elt.attr(event) + elt[event](-> view[methodName]()) + + +