1 sc_require("handlebars");
  2 sc_require("ext/handlebars");
  3 sc_require("ext/handlebars/bind");
  4 sc_require("ext/handlebars/collection");
  5 sc_require("ext/handlebars/localization");
  6 sc_require("ext/handlebars/view");
  7 
  8 // Global hash of shared templates. This will automatically be populated
  9 // by the build tools so that you can store your Handlebars templates in
 10 // separate files that get loaded into JavaScript at buildtime.
 11 SC.TEMPLATES = SC.Object.create();
 12 
 13 /** @class
 14 
 15   SC.TemplateView allows you to create a view that uses the Handlebars templating
 16   engine to generate its HTML representation.
 17 
 18   To use it, create a file in your project called +mytemplate.handlebars+. Then,
 19   set the +templateName+ property of your SC.TemplateView to +mytemplate+.
 20 
 21   Alternatively, you can set the +template+ property to any function that
 22   returns a string. It is recommended that you use +SC.Handlebars.compile()+ to
 23   generate a function from a string containing Handlebars markup.
 24 
 25   @extends SC.CoreView
 26   @since SproutCore 1.5
 27 */
 28 SC.TemplateView = SC.CoreView.extend(
 29 /** @scope SC.TemplateView.prototype */ {
 30 
 31   // This makes it easier to build custom views on top of TemplateView without
 32   // gotchas, but may have tab navigation repercussions. The tab navigation
 33   // system should be revisited.
 34   acceptsFirstResponder: YES,
 35 
 36   /**
 37     The name of the template to lookup if no template is provided.
 38 
 39     SC.TemplateView will look for a template with this name in the global
 40     +SC.TEMPLATES+ hash. Usually this hash will be populated for you
 41     automatically when you include +.handlebars+ files in your project.
 42 
 43     @type String
 44   */
 45   templateName: null,
 46 
 47   /**
 48     The hash in which to look for +templateName+. Defaults to SC.TEMPLATES.
 49 
 50     @type Object
 51   */
 52   templates: SC.TEMPLATES,
 53 
 54   /**
 55     The template used to render the view. This should be a function that
 56     accepts an optional context parameter and returns a string of HTML that
 57     will be inserted into the DOM relative to its parent view.
 58 
 59     In general, you should set the +templateName+ property instead of setting
 60     the template yourself.
 61 
 62     @type Function
 63   */
 64   template: function(key, value) {
 65     if (value !== undefined) {
 66       return value;
 67     }
 68 
 69     var templateName = this.get('templateName'),
 70         template = this.get('templates').get(templateName);
 71 
 72     if (!template) {
 73       //@if(debug)
 74       if (templateName) {
 75         SC.Logger.warn('%@ - Unable to find template "%@".'.fmt(this, templateName));
 76       }
 77       //@endif
 78 
 79       return function() { return ''; };
 80     }
 81 
 82     return template;
 83   }.property('templateName').cacheable(),
 84 
 85   /**
 86     The object from which templates should access properties.
 87 
 88     This object will be passed to the template function each time the render
 89     method is called, but it is up to the individual function to decide what
 90     to do with it.
 91 
 92     By default, this will be the view itself.
 93 
 94     @type Object
 95   */
 96   context: function(key, value) {
 97     if (value !== undefined) {
 98       return value;
 99     }
100 
101     return this;
102   }.property().cacheable(),
103 
104   /**
105     When the view is asked to render, we look for the appropriate template
106     function and invoke it, then push its result onto the passed
107     SC.RenderContext instance.
108 
109     @param {SC.RenderContext} context the render context
110   */
111   render: function(context) {
112     var data,
113         output,
114         template = this.get('template'),
115         templateContext = this.get('context');
116 
117     this._didRenderChildViews = YES;
118 
119     data = { view: this, isRenderData: true };
120     output = template(templateContext, { data: data });
121 
122     context.push(output);
123   },
124 
125   // in TemplateView, updating is handled by observers created by helpers in the
126   // template. As a result, we create an empty update method so that the old
127   // (pre-1.5) behavior which would force a full re-render does not get activated.
128   update: function() { },
129 
130   /**
131     Since mouseUp events will not fire unless we return YES to mouseDown, the
132     default mouseDown implementation returns YES if a mouseDown method exists.
133   */
134   mouseDown: function() {
135     if (this.mouseUp) { return YES; }
136     return NO;
137   }
138 });
139