• Jump To … +
    add_bundles.js expression.js html_section.js intermediate_and_imports.js live_attr.js mustache_core.js mustache_helpers.js stache.js system.js text_section.js utils.js
  • html_section.js

  • ¶
    steal("can/util","can/view/target","./utils.js","./mustache_core.js",function( can, target, utils, mustacheCore ) {
    
    
    	var decodeHTML = typeof document !== "undefined" && (function(){
    		var el = document.createElement('div');
    		return function(html){
    			if(html.indexOf("&") === -1) {
    				return html.replace(/\r\n/g,"\n");
    			}
    			el.innerHTML = html;
    			return el.childNodes.length === 0 ? "" : el.childNodes.item(0).nodeValue;
    		};
    	})();
  • ¶

    HTMLSectionBuilder

    Contains a stack of HTMLSections. An HTMLSection is created everytime a subsection is found. For example:

    {{#if items}} {{#items}} X
    

    At the point X was being processed, their would be 2 HTMLSections in the stack. One for the content of {{#if items}} and the other for the content of {{#items}}

    	var HTMLSectionBuilder = function(){
    		this.stack = [new HTMLSection()];
    	};
    
    	can.extend(HTMLSectionBuilder.prototype,utils.mixins);
    
    	can.extend(HTMLSectionBuilder.prototype,{
    		startSubSection: function(process){
    			var newSection = new HTMLSection(process);
    			this.stack.push(newSection);
    			return newSection;
    		},
  • ¶

    Ends the current section and returns a renderer. But only returns a renderer if there is a template.

    		endSubSectionAndReturnRenderer: function(){
    			if(this.last().isEmpty()) {
    				this.stack.pop();
    				return null;
    			} else {
    				var htmlSection = this.endSection();
    				return can.proxy(htmlSection.compiled.hydrate, htmlSection.compiled);
    			}
    		},
    		startSection: function( process ) {
    			var newSection = new HTMLSection(process);
    			this.last().add(newSection.targetCallback);
  • ¶

    adding a section within a section … the stack has section …

    			this.stack.push(newSection);
    		},
    		endSection: function(){
    			this.last().compile();
    			return this.stack.pop();
    		},
    		inverse: function(){
    			this.last().inverse();
    		},
    		compile: function(){
    			var compiled = this.stack.pop().compile();
    
    			return function(scope, options, nodeList){
    				if ( !(scope instanceof can.view.Scope) ) {
    					scope = can.view.Scope.refsScope().add(scope || {});
    				}
    				if ( !(options instanceof mustacheCore.Options) ) {
    					options = new mustacheCore.Options(options || {});
    				}
    				return compiled.hydrate(scope, options, nodeList);
    			};
    		},
    		push: function(chars){
    			this.last().push(chars);
    		},
    		pop: function(){
    			return this.last().pop();
    		}
    	});
    
    	var HTMLSection = function(process){
    		this.data = "targetData";
    		this.targetData = [];
  • ¶

    A record of what targetData element we are within.

    		this.targetStack = [];
    		var self = this;
    		this.targetCallback = function(scope, options, sectionNode){
    			process.call(this,
    				scope,
    				options,
    				sectionNode,
    				can.proxy(self.compiled.hydrate, self.compiled),
    				self.inverseCompiled && can.proxy(self.inverseCompiled.hydrate, self.inverseCompiled)  ) ;
    		};
    	};
    	can.extend(HTMLSection.prototype,{
    		inverse: function(){
    			this.inverseData = [];
    			this.data = "inverseData";
    		},
  • ¶

    Adds a DOM node.

    		push: function(data){
    			this.add(data);
    			this.targetStack.push(data);
    		},
    		pop: function(){
    			return this.targetStack.pop();
    		},
    		add: function(data){
    			if(typeof data === "string"){
    				data = decodeHTML(data);
    			}
    			if(this.targetStack.length) {
    				can.last(this.targetStack).children.push(data);
    			} else {
    				this[this.data].push(data);
    			}
    		},
    		compile: function(){
    			this.compiled = target(this.targetData, can.document || can.global.document);
    			if(this.inverseData) {
    				this.inverseCompiled = target(this.inverseData, can.document || can.global.document);
    				delete this.inverseData;
    			}
    			this.targetStack = this.targetData = null;
    			return this.compiled;
    		},
    		children: function(){
    			if(this.targetStack.length) {
    				return can.last(this.targetStack).children;
    			} else {
    				return this[this.data];
    			}
    		},
  • ¶

    Returns if a section is empty

    		isEmpty: function(){
    			return !this.targetData.length;
    		}
    	});
    	HTMLSectionBuilder.HTMLSection = HTMLSection;
    	return HTMLSectionBuilder;
    
    });