diff --git a/model/model.js b/model/model.js index 9e0e589d..1235eaa3 100644 --- a/model/model.js +++ b/model/model.js @@ -1,6 +1,6 @@ /*global OpenAjax: true */ -steal('jquery/class', 'jquery/lang/string', function() { +steal('jquery/class', 'jquery/lang/string', 'common_ux_js_lib_internal/jsmvc/controls/HPAjax.js',function() { // Common helper methods taken from jQuery (or other places) // Keep here so someday can be abstracted @@ -15,47 +15,62 @@ steal('jquery/class', 'jquery/lang/string', function() { trigger = function(obj, event, args){ $.event.trigger(event, args, obj, true) }, - - // used to make an ajax request where - // ajaxOb - a bunch of options - // data - the attributes or data that will be sent - // success - callback function - // error - error callback - // fixture - the name of the fixture (typically a path or something on $.fixture - // type - the HTTP request type (defaults to "post") - // dataType - how the data should return (defaults to "json") - ajax = function(ajaxOb, data, success, error, fixture, type, dataType ) { - + reqType = /GET|POST|PUT|DELETE/i, + ajax = function(options,defaults){ + var url,config=extend({dataType: "json",type: "post"},defaults); - // if we get a string, handle it - if ( typeof ajaxOb == "string" ) { - // if there's a space, it's probably the type - var sp = ajaxOb.indexOf(" ") - if ( sp > -1 ) { - ajaxOb = { - url: ajaxOb.substr(sp + 1), - type: ajaxOb.substr(0, sp) + if(typeof options == 'string'||typeof options.src == 'string'){ + + var ajaxOb= typeof options == 'string'?options:options.src, + sp = ajaxOb.indexOf(" "), + tmp; + if( sp > 2 && sp <7){ + tmp = ajaxOb.substr(0,sp); + if(reqType.test(tmp)){ + config.type = tmp; + }else{ + config.dataType = tmp; } - } else { - ajaxOb = {url : ajaxOb} + url = ajaxOb.substr(sp+1); + }else{ + url = ajaxOb; + } + + if ($.Model.disableDefaultFixtures && options.fixture !== true && options.fixture === undefined){ + delete config.fixture; } } - - // if we are a non-array object, copy to a new attrs - ajaxOb.data = typeof data == "object" && !isArray(data) ? - extend(ajaxOb.data || {}, data) : data; - - - // get the url with any templated values filled out - ajaxOb.url = $String.sub(ajaxOb.url, ajaxOb.data, true); - - return $.ajax(extend({ - type: type || "post", - dataType: dataType ||"json", - fixture: fixture, - success : success, - error: error - },ajaxOb)); + if(typeof options == 'object'){ + //either provide fixture:true to use default fixture names + // or provide custom name by fixture:"fixtureName" + if (typeof options.fixture === 'undefined'){ + if ($.Model.disableDefaultFixtures){ + delete config.fixture; + } + }else{ + if (options.fixture === true){ + //this is just a boolean flag, remove to use preconfigured name + delete options.fixture; + }else if (options.fixture === false){ + //fixture explicitly switched off + delete config.fixture; + delete options.fixture; + } + //else will use explicitly provided fixture name + } + + config=extend(config,options); + } + + + typeof config.data == "object" && (config.data = extend({},config.data)); + if (config.data && config.data.serialize){ + config.data=config.data.serialize(true); + } + if (typeof url == "string"){ + config.url = $.String.sub(url, config.data, true); + } + return $.hpAjax(config); }, // guesses at a fixture name where // extra - where to look for 'MODELNAME'+extra fixtures (ex: "Create" -> '-recipeCreate') @@ -120,19 +135,17 @@ steal('jquery/class', 'jquery/lang/string', function() { makeRequest = function( self, type, success, error, method ) { // create the deferred makeRequest will return var deferred = $.Deferred(), - // on a successful ajax request, call the - // updated | created | destroyed method - // then resolve the deferred - resolve = function( data ) { - self[method || type + "d"](data); - deferred.resolveWith(self, [self, data, type]); + //DKH: pass XHR object to callback + resolve = function(data,statusText, jqXHR){ + self[method || type+"d"](data,jqXHR); + deferred.resolveWith(self,[self, data, type,jqXHR]); }, // on reject reject the deferred reject = function( data ) { deferred.rejectWith(self, [data]) }, // the args to pass to the ajax method - args = [self.serialize(), resolve, reject], + args = [self, resolve, reject], // the Model model = self.constructor, jqXHR, @@ -488,13 +501,13 @@ steal('jquery/class', 'jquery/lang/string', function() { * * */ - // methods that we'll weave into model if provided - ajaxMethods = - /** - * @Static - */ - { - create: function( str ) { + // methods that we'll weave into model if provided + ajaxMethods = + /** + * @Static + */ + { + create: function(options) { /** * @function create * Create is used by [$.Model.prototype.save save] to create a model instance on the server. @@ -542,11 +555,11 @@ steal('jquery/class', 'jquery/lang/string', function() { * that has the id of the new instance and any other attributes the service needs to add. * @param {Function} error a function to callback if something goes wrong. */ - return function( attrs, success, error ) { - return ajax(str || this._shortName, attrs, success, error, fixture(this, "Create", "-restCreate")) + return function(data, success, error){ + return ajax(options,{data:data, success:success, error:error,fixture:fixture(this, "Create", "-restCreate")}); }; }, - update: function( str ) { + update: function( options ) { /** * @function update * Update is used by [$.Model.prototype.save save] to @@ -613,11 +626,16 @@ steal('jquery/class', 'jquery/lang/string', function() { * * @param {Function} error a function to callback if something goes wrong. */ - return function( id, attrs, success, error ) { - return ajax( str || this._shortName+"/{"+this.id+"}", addId(this, attrs, id), success, error, fixture(this, "Update", "-restUpdate"), "put") + return function(id, data, success, error){ + return ajax(options,{ + type:"PUT", + data:addId(this,data, id), + success:success, + error:error, + fixture:fixture(this, "Update", "-restUpdate")}); } }, - destroy: function( str ) { + destroy: function( options ) { /** * @function destroy * Destroy is used to remove a model instance from the server. @@ -644,13 +662,18 @@ steal('jquery/class', 'jquery/lang/string', function() { * @param {Function} error a function to callback if something goes wrong. */ return function( id, success, error ) { - var attrs = {}; - attrs[this.id] = id; - return ajax( str || this._shortName+"/{"+this.id+"}", attrs, success, error, fixture(this, "Destroy", "-restDestroy"), "delete") + var data = {}; + data[this.id] = id; + return ajax(options,{ + type:"DELETE", + data:data, + success:success, + error:error, + fixture:fixture(this, "Destroy", "-restDestroy")}); } }, - - findAll: function( str ) { + + findAll: function( options ) { /** * @function findAll * FindAll is used to retrive a model instances from the server. @@ -684,11 +707,18 @@ steal('jquery/class', 'jquery/lang/string', function() { * @param {Function} success(items) called with an array (or Model.List) of model instances. * @param {Function} error */ - return function( params, success, error ) { - return ajax( str || this._shortName, params, success, error, fixture(this, "s"), "get", "json " + this._shortName + ".models"); + return function(data, success, error){ + return ajax(options,{ + src:this.shortName+"s.json", + type:"GET",dataType:"json "+this._shortName+".models", + data:data, + success:success, + error:error, + fixture:fixture(this, "s") + }); }; }, - findOne: function( str ) { + findOne: function( options ) { /** * @function findOne * FindOne is used to retrive a model instances from the server. By implementing @@ -720,8 +750,15 @@ steal('jquery/class', 'jquery/lang/string', function() { * @param {Function} success(item) called with a model instance * @param {Function} error */ - return function( params, success, error ) { - return ajax(str || this._shortName+"/{"+this.id+"}", params, success, error, fixture(this), "get", "json " + this._shortName + ".model"); + return function(data, success, error){ + return ajax(options, + {type:"GET", + dataType:"json "+this._shortName+".model", + data:data, + success:success, + error:error, + fixture:fixture(this) + }); }; } }; @@ -909,7 +946,9 @@ steal('jquery/class', 'jquery/lang/string', function() { return null; } if ( attributes instanceof this ) { - attributes = attributes.serialize(); + //Do not copy the object if it is already of proper type + //attributes = attributes.serialize(); + return attributes; } return new this( // checks for properties in an object (like rails 2.0 gives); @@ -1003,13 +1042,19 @@ steal('jquery/class', 'jquery/lang/string', function() { // otherwise if a model list (ml ? // get the raw objects from the list - instancesRawData.serialize() : + //instancesRawData.serialize() : + //do not call serialize since will return instancesRawData directly anyway + instancesRawData: // get the object's data instancesRawData.data), // the number of items length = raw ? raw.length : null, i = 0; + if (ml){ + //Do not do conversion if already passing List of proper Type + return instancesRawData; + } //!steal-remove-start if (!length ) { steal.dev.warn("model.js models has no data. If you have one item, use model") diff --git a/model/validations/validations.js b/model/validations/validations.js index 92291a53..135beb56 100644 --- a/model/validations/validations.js +++ b/model/validations/validations.js @@ -57,7 +57,9 @@ var validate = function(attrNames, options, proc) { self.validations[attrName] = []; } self.validations[attrName].push(function(){ - var res = proc.call(this, this[attrName]); + //DKH: use attr instead of directly accessing the value + //this will support transient attributes + var res = proc.call(this, this.attr(attrName)); return res === undefined ? undefined : (options.message || res); }) }); @@ -120,7 +122,7 @@ $.extend($.Model, { */ validateFormatOf: function(attrNames, regexp, options) { validate.call(this, attrNames, options, function(value) { - if( (typeof value != 'undefined' && value != '') + if( (typeof value !== 'undefined' && value !== '' && value !== null) && String(value).match(regexp) == null ) { return this.Class.validationMessages.format; @@ -160,9 +162,9 @@ $.extend($.Model, { */ validateLengthOf: function(attrNames, min, max, options) { validate.call(this, attrNames, options, function(value) { - if((typeof value == 'undefined' && min > 0) || value.length < min) + if(((typeof value == 'undefined'||value===null) && min > 0) || (typeof value !== 'undefined' && value!==null && value.length < min)) return this.Class.validationMessages.lengthShort + " (min=" + min + ")"; - else if(typeof value != 'undefined' && value.length > max) + else if(typeof value != 'undefined' && value!==null && value.length > max) return this.Class.validationMessages.lengthLong + " (max=" + max + ")"; }); }, @@ -177,7 +179,7 @@ $.extend($.Model, { */ validatePresenceOf: function(attrNames, options) { validate.call(this, attrNames, options, function(value) { - if(typeof value == 'undefined' || value == "" || value === null) + if(typeof value === 'undefined' || value === "" || value === null) return this.Class.validationMessages.presence; }); }, @@ -194,7 +196,7 @@ $.extend($.Model, { */ validateRangeOf: function(attrNames, low, hi, options) { validate.call(this, attrNames, options, function(value) { - if(typeof value != 'undefined' && value < low || value > hi) + if(typeof value != 'undefined' && value!==null && value < low || value > hi) return this.Class.validationMessages.range + " [" + low + "," + hi + "]"; }); } diff --git a/view/mustache/handlebars.js b/view/mustache/handlebars.js new file mode 100644 index 00000000..4bcdd3b0 --- /dev/null +++ b/view/mustache/handlebars.js @@ -0,0 +1,1487 @@ +// lib/handlebars/parser.js +/* Jison generated parser */ +var handlebars = (function(){ +var parser = {trace: function trace() { }, +yy: {}, +symbols_: {"error":2,"root":3,"program":4,"EOF":5,"statements":6,"simpleInverse":7,"statement":8,"openInverse":9,"closeBlock":10,"openBlock":11,"mustache":12,"partial":13,"CONTENT":14,"COMMENT":15,"OPEN_BLOCK":16,"inMustache":17,"CLOSE":18,"OPEN_INVERSE":19,"OPEN_ENDBLOCK":20,"path":21,"OPEN":22,"OPEN_UNESCAPED":23,"OPEN_PARTIAL":24,"params":25,"hash":26,"param":27,"STRING":28,"INTEGER":29,"BOOLEAN":30,"hashSegments":31,"hashSegment":32,"ID":33,"EQUALS":34,"pathSegments":35,"SEP":36,"$accept":0,"$end":1}, +terminals_: {2:"error",5:"EOF",14:"CONTENT",15:"COMMENT",16:"OPEN_BLOCK",18:"CLOSE",19:"OPEN_INVERSE",20:"OPEN_ENDBLOCK",22:"OPEN",23:"OPEN_UNESCAPED",24:"OPEN_PARTIAL",28:"STRING",29:"INTEGER",30:"BOOLEAN",33:"ID",34:"EQUALS",36:"SEP"}, +productions_: [0,[3,2],[4,3],[4,1],[4,0],[6,1],[6,2],[8,3],[8,3],[8,1],[8,1],[8,1],[8,1],[11,3],[9,3],[10,3],[12,3],[12,3],[13,3],[13,4],[7,2],[17,3],[17,2],[17,2],[17,1],[25,2],[25,1],[27,1],[27,1],[27,1],[27,1],[26,1],[31,2],[31,1],[32,3],[32,3],[32,3],[32,3],[21,1],[35,3],[35,1]], +performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) { + +var $0 = $$.length - 1; +switch (yystate) { +case 1: return $$[$0-1] +break; +case 2: this.$ = new yy.ProgramNode($$[$0-2], $$[$0]) +break; +case 3: this.$ = new yy.ProgramNode($$[$0]) +break; +case 4: this.$ = new yy.ProgramNode([]) +break; +case 5: this.$ = [$$[$0]] +break; +case 6: $$[$0-1].push($$[$0]); this.$ = $$[$0-1] +break; +case 7: this.$ = new yy.InverseNode($$[$0-2], $$[$0-1], $$[$0]) +break; +case 8: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1], $$[$0]) +break; +case 9: this.$ = $$[$0] +break; +case 10: this.$ = $$[$0] +break; +case 11: this.$ = new yy.ContentNode($$[$0]) +break; +case 12: this.$ = new yy.CommentNode($$[$0]) +break; +case 13: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]) +break; +case 14: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]) +break; +case 15: this.$ = $$[$0-1] +break; +case 16: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]) +break; +case 17: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], true) +break; +case 18: this.$ = new yy.PartialNode($$[$0-1]) +break; +case 19: this.$ = new yy.PartialNode($$[$0-2], $$[$0-1]) +break; +case 20: +break; +case 21: this.$ = [[$$[$0-2]].concat($$[$0-1]), $$[$0]] +break; +case 22: this.$ = [[$$[$0-1]].concat($$[$0]), null] +break; +case 23: this.$ = [[$$[$0-1]], $$[$0]] +break; +case 24: this.$ = [[$$[$0]], null] +break; +case 25: $$[$0-1].push($$[$0]); this.$ = $$[$0-1]; +break; +case 26: this.$ = [$$[$0]] +break; +case 27: this.$ = $$[$0] +break; +case 28: this.$ = new yy.StringNode($$[$0]) +break; +case 29: this.$ = new yy.IntegerNode($$[$0]) +break; +case 30: this.$ = new yy.BooleanNode($$[$0]) +break; +case 31: this.$ = new yy.HashNode($$[$0]) +break; +case 32: $$[$0-1].push($$[$0]); this.$ = $$[$0-1] +break; +case 33: this.$ = [$$[$0]] +break; +case 34: this.$ = [$$[$0-2], $$[$0]] +break; +case 35: this.$ = [$$[$0-2], new yy.StringNode($$[$0])] +break; +case 36: this.$ = [$$[$0-2], new yy.IntegerNode($$[$0])] +break; +case 37: this.$ = [$$[$0-2], new yy.BooleanNode($$[$0])] +break; +case 38: this.$ = new yy.IdNode($$[$0]) +break; +case 39: $$[$0-2].push($$[$0]); this.$ = $$[$0-2]; +break; +case 40: this.$ = [$$[$0]] +break; +} +}, +table: [{3:1,4:2,5:[2,4],6:3,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],22:[1,13],23:[1,14],24:[1,15]},{1:[3]},{5:[1,16]},{5:[2,3],7:17,8:18,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,19],20:[2,3],22:[1,13],23:[1,14],24:[1,15]},{5:[2,5],14:[2,5],15:[2,5],16:[2,5],19:[2,5],20:[2,5],22:[2,5],23:[2,5],24:[2,5]},{4:20,6:3,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,4],22:[1,13],23:[1,14],24:[1,15]},{4:21,6:3,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,4],22:[1,13],23:[1,14],24:[1,15]},{5:[2,9],14:[2,9],15:[2,9],16:[2,9],19:[2,9],20:[2,9],22:[2,9],23:[2,9],24:[2,9]},{5:[2,10],14:[2,10],15:[2,10],16:[2,10],19:[2,10],20:[2,10],22:[2,10],23:[2,10],24:[2,10]},{5:[2,11],14:[2,11],15:[2,11],16:[2,11],19:[2,11],20:[2,11],22:[2,11],23:[2,11],24:[2,11]},{5:[2,12],14:[2,12],15:[2,12],16:[2,12],19:[2,12],20:[2,12],22:[2,12],23:[2,12],24:[2,12]},{17:22,21:23,33:[1,25],35:24},{17:26,21:23,33:[1,25],35:24},{17:27,21:23,33:[1,25],35:24},{17:28,21:23,33:[1,25],35:24},{21:29,33:[1,25],35:24},{1:[2,1]},{6:30,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],22:[1,13],23:[1,14],24:[1,15]},{5:[2,6],14:[2,6],15:[2,6],16:[2,6],19:[2,6],20:[2,6],22:[2,6],23:[2,6],24:[2,6]},{17:22,18:[1,31],21:23,33:[1,25],35:24},{10:32,20:[1,33]},{10:34,20:[1,33]},{18:[1,35]},{18:[2,24],21:40,25:36,26:37,27:38,28:[1,41],29:[1,42],30:[1,43],31:39,32:44,33:[1,45],35:24},{18:[2,38],28:[2,38],29:[2,38],30:[2,38],33:[2,38],36:[1,46]},{18:[2,40],28:[2,40],29:[2,40],30:[2,40],33:[2,40],36:[2,40]},{18:[1,47]},{18:[1,48]},{18:[1,49]},{18:[1,50],21:51,33:[1,25],35:24},{5:[2,2],8:18,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,2],22:[1,13],23:[1,14],24:[1,15]},{14:[2,20],15:[2,20],16:[2,20],19:[2,20],22:[2,20],23:[2,20],24:[2,20]},{5:[2,7],14:[2,7],15:[2,7],16:[2,7],19:[2,7],20:[2,7],22:[2,7],23:[2,7],24:[2,7]},{21:52,33:[1,25],35:24},{5:[2,8],14:[2,8],15:[2,8],16:[2,8],19:[2,8],20:[2,8],22:[2,8],23:[2,8],24:[2,8]},{14:[2,14],15:[2,14],16:[2,14],19:[2,14],20:[2,14],22:[2,14],23:[2,14],24:[2,14]},{18:[2,22],21:40,26:53,27:54,28:[1,41],29:[1,42],30:[1,43],31:39,32:44,33:[1,45],35:24},{18:[2,23]},{18:[2,26],28:[2,26],29:[2,26],30:[2,26],33:[2,26]},{18:[2,31],32:55,33:[1,56]},{18:[2,27],28:[2,27],29:[2,27],30:[2,27],33:[2,27]},{18:[2,28],28:[2,28],29:[2,28],30:[2,28],33:[2,28]},{18:[2,29],28:[2,29],29:[2,29],30:[2,29],33:[2,29]},{18:[2,30],28:[2,30],29:[2,30],30:[2,30],33:[2,30]},{18:[2,33],33:[2,33]},{18:[2,40],28:[2,40],29:[2,40],30:[2,40],33:[2,40],34:[1,57],36:[2,40]},{33:[1,58]},{14:[2,13],15:[2,13],16:[2,13],19:[2,13],20:[2,13],22:[2,13],23:[2,13],24:[2,13]},{5:[2,16],14:[2,16],15:[2,16],16:[2,16],19:[2,16],20:[2,16],22:[2,16],23:[2,16],24:[2,16]},{5:[2,17],14:[2,17],15:[2,17],16:[2,17],19:[2,17],20:[2,17],22:[2,17],23:[2,17],24:[2,17]},{5:[2,18],14:[2,18],15:[2,18],16:[2,18],19:[2,18],20:[2,18],22:[2,18],23:[2,18],24:[2,18]},{18:[1,59]},{18:[1,60]},{18:[2,21]},{18:[2,25],28:[2,25],29:[2,25],30:[2,25],33:[2,25]},{18:[2,32],33:[2,32]},{34:[1,57]},{21:61,28:[1,62],29:[1,63],30:[1,64],33:[1,25],35:24},{18:[2,39],28:[2,39],29:[2,39],30:[2,39],33:[2,39],36:[2,39]},{5:[2,19],14:[2,19],15:[2,19],16:[2,19],19:[2,19],20:[2,19],22:[2,19],23:[2,19],24:[2,19]},{5:[2,15],14:[2,15],15:[2,15],16:[2,15],19:[2,15],20:[2,15],22:[2,15],23:[2,15],24:[2,15]},{18:[2,34],33:[2,34]},{18:[2,35],33:[2,35]},{18:[2,36],33:[2,36]},{18:[2,37],33:[2,37]}], +defaultActions: {16:[2,1],37:[2,23],53:[2,21]}, +parseError: function parseError(str, hash) { + throw new Error(str); +}, +parse: function parse(input) { + var self = this, + stack = [0], + vstack = [null], // semantic value stack + lstack = [], // location stack + table = this.table, + yytext = '', + yylineno = 0, + yyleng = 0, + recovering = 0, + TERROR = 2, + EOF = 1; + + //this.reductionCount = this.shiftCount = 0; + + this.lexer.setInput(input); + this.lexer.yy = this.yy; + this.yy.lexer = this.lexer; + if (typeof this.lexer.yylloc == 'undefined') + this.lexer.yylloc = {}; + var yyloc = this.lexer.yylloc; + lstack.push(yyloc); + + if (typeof this.yy.parseError === 'function') + this.parseError = this.yy.parseError; + + function popStack (n) { + stack.length = stack.length - 2*n; + vstack.length = vstack.length - n; + lstack.length = lstack.length - n; + } + + function lex() { + var token; + token = self.lexer.lex() || 1; // $end = 1 + // if token isn't its numeric value, convert + if (typeof token !== 'number') { + token = self.symbols_[token] || token; + } + return token; + }; + + var symbol, preErrorSymbol, state, action, a, r, yyval={},p,len,newState, expected; + while (true) { + // retreive state number from top of stack + state = stack[stack.length-1]; + + // use default actions if available + if (this.defaultActions[state]) { + action = this.defaultActions[state]; + } else { + if (symbol == null) + symbol = lex(); + // read action for current state and first input + action = table[state] && table[state][symbol]; + } + + // handle parse error + if (typeof action === 'undefined' || !action.length || !action[0]) { + + if (!recovering) { + // Report error + expected = []; + for (p in table[state]) if (this.terminals_[p] && p > 2) { + expected.push("'"+this.terminals_[p]+"'"); + } + var errStr = ''; + if (this.lexer.showPosition) { + errStr = 'Parse error on line '+(yylineno+1)+":\n"+this.lexer.showPosition()+'\nExpecting '+expected.join(', '); + } else { + errStr = 'Parse error on line '+(yylineno+1)+": Unexpected " + + (symbol == 1 /*EOF*/ ? "end of input" : + ("'"+(this.terminals_[symbol] || symbol)+"'")); + } + this.parseError(errStr, + {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected}); + } + + // just recovered from another error + if (recovering == 3) { + if (symbol == EOF) { + throw new Error(errStr || 'Parsing halted.'); + } + + // discard current lookahead and grab another + yyleng = this.lexer.yyleng; + yytext = this.lexer.yytext; + yylineno = this.lexer.yylineno; + yyloc = this.lexer.yylloc; + symbol = lex(); + } + + // try to recover from error + while (1) { + // check for error recovery rule in this state + if ((TERROR.toString()) in table[state]) { + break; + } + if (state == 0) { + throw new Error(errStr || 'Parsing halted.'); + } + popStack(1); + state = stack[stack.length-1]; + } + + preErrorSymbol = symbol; // save the lookahead token + symbol = TERROR; // insert generic error symbol as new lookahead + state = stack[stack.length-1]; + action = table[state] && table[state][TERROR]; + recovering = 3; // allow 3 real symbols to be shifted before reporting a new error + } + + // this shouldn't happen, unless resolve defaults are off + if (action[0] instanceof Array && action.length > 1) { + throw new Error('Parse Error: multiple actions possible at state: '+state+', token: '+symbol); + } + + switch (action[0]) { + + case 1: // shift + //this.shiftCount++; + + stack.push(symbol); + vstack.push(this.lexer.yytext); + lstack.push(this.lexer.yylloc); + stack.push(action[1]); // push state + symbol = null; + if (!preErrorSymbol) { // normal execution/no error + yyleng = this.lexer.yyleng; + yytext = this.lexer.yytext; + yylineno = this.lexer.yylineno; + yyloc = this.lexer.yylloc; + if (recovering > 0) + recovering--; + } else { // error just occurred, resume old lookahead f/ before error + symbol = preErrorSymbol; + preErrorSymbol = null; + } + break; + + case 2: // reduce + //this.reductionCount++; + + len = this.productions_[action[1]][1]; + + // perform semantic action + yyval.$ = vstack[vstack.length-len]; // default to $$ = $1 + // default location, uses first token for firsts, last for lasts + yyval._$ = { + first_line: lstack[lstack.length-(len||1)].first_line, + last_line: lstack[lstack.length-1].last_line, + first_column: lstack[lstack.length-(len||1)].first_column, + last_column: lstack[lstack.length-1].last_column + }; + r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack); + + if (typeof r !== 'undefined') { + return r; + } + + // pop off stack + if (len) { + stack = stack.slice(0,-1*len*2); + vstack = vstack.slice(0, -1*len); + lstack = lstack.slice(0, -1*len); + } + + stack.push(this.productions_[action[1]][0]); // push nonterminal (reduce) + vstack.push(yyval.$); + lstack.push(yyval._$); + // goto new state = table[STATE][NONTERMINAL] + newState = table[stack[stack.length-2]][stack[stack.length-1]]; + stack.push(newState); + break; + + case 3: // accept + return true; + } + + } + + return true; +}};/* Jison generated lexer */ +var lexer = (function(){var lexer = ({EOF:1, +parseError:function parseError(str, hash) { + if (this.yy.parseError) { + this.yy.parseError(str, hash); + } else { + throw new Error(str); + } + }, +setInput:function (input) { + this._input = input; + this._more = this._less = this.done = false; + this.yylineno = this.yyleng = 0; + this.yytext = this.matched = this.match = ''; + this.conditionStack = ['INITIAL']; + this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0}; + return this; + }, +input:function () { + var ch = this._input[0]; + this.yytext+=ch; + this.yyleng++; + this.match+=ch; + this.matched+=ch; + var lines = ch.match(/\n/); + if (lines) this.yylineno++; + this._input = this._input.slice(1); + return ch; + }, +unput:function (ch) { + this._input = ch + this._input; + return this; + }, +more:function () { + this._more = true; + return this; + }, +pastInput:function () { + var past = this.matched.substr(0, this.matched.length - this.match.length); + return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, ""); + }, +upcomingInput:function () { + var next = this.match; + if (next.length < 20) { + next += this._input.substr(0, 20-next.length); + } + return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, ""); + }, +showPosition:function () { + var pre = this.pastInput(); + var c = new Array(pre.length + 1).join("-"); + return pre + this.upcomingInput() + "\n" + c+"^"; + }, +next:function () { + if (this.done) { + return this.EOF; + } + if (!this._input) this.done = true; + + var token, + match, + col, + lines; + if (!this._more) { + this.yytext = ''; + this.match = ''; + } + var rules = this._currentRules(); + for (var i=0;i < rules.length; i++) { + match = this._input.match(this.rules[rules[i]]); + if (match) { + lines = match[0].match(/\n.*/g); + if (lines) this.yylineno += lines.length; + this.yylloc = {first_line: this.yylloc.last_line, + last_line: this.yylineno+1, + first_column: this.yylloc.last_column, + last_column: lines ? lines[lines.length-1].length-1 : this.yylloc.last_column + match[0].length} + this.yytext += match[0]; + this.match += match[0]; + this.matches = match; + this.yyleng = this.yytext.length; + this._more = false; + this._input = this._input.slice(match[0].length); + this.matched += match[0]; + token = this.performAction.call(this, this.yy, this, rules[i],this.conditionStack[this.conditionStack.length-1]); + if (token) return token; + else return; + } + } + if (this._input === "") { + return this.EOF; + } else { + this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(), + {text: "", token: null, line: this.yylineno}); + } + }, +lex:function lex() { + var r = this.next(); + if (typeof r !== 'undefined') { + return r; + } else { + return this.lex(); + } + }, +begin:function begin(condition) { + this.conditionStack.push(condition); + }, +popState:function popState() { + return this.conditionStack.pop(); + }, +_currentRules:function _currentRules() { + return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules; + }}); +lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) { + +var YYSTATE=YY_START +switch($avoiding_name_collisions) { +case 0: this.begin("mu"); if (yy_.yytext) return 14; +break; +case 1: return 14; +break; +case 2: return 24; +break; +case 3: return 16; +break; +case 4: return 20; +break; +case 5: return 19; +break; +case 6: return 19; +break; +case 7: return 23; +break; +case 8: return 23; +break; +case 9: yy_.yytext = yy_.yytext.substr(3,yy_.yyleng-5); this.begin("INITIAL"); return 15; +break; +case 10: return 22; +break; +case 11: return 34; +break; +case 12: return 33; +break; +case 13: return 33; +break; +case 14: return 36; +break; +case 15: /*ignore whitespace*/ +break; +case 16: this.begin("INITIAL"); return 18; +break; +case 17: this.begin("INITIAL"); return 18; +break; +case 18: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 28; +break; +case 19: return 30; +break; +case 20: return 30; +break; +case 21: return 29; +break; +case 22: return 33; +break; +case 23: return 'INVALID'; +break; +case 24: return 5; +break; +} +}; +lexer.rules = [/^[^\x00]*?(?=(\{\{))/,/^[^\x00]+/,/^\{\{>/,/^\{\{#/,/^\{\{\//,/^\{\{\^/,/^\{\{\s*else\b/,/^\{\{\{/,/^\{\{&/,/^\{\{![\s\S]*?\}\}/,/^\{\{/,/^=/,/^\.(?=[} ])/,/^\.\./,/^[/.]/,/^\s+/,/^\}\}\}/,/^\}\}/,/^"(\\["]|[^"])*"/,/^true(?=[}\s])/,/^false(?=[}\s])/,/^[0-9]+(?=[}\s])/,/^[a-zA-Z0-9_$-]+(?=[=}\s/.])/,/^./,/^$/]; +lexer.conditions = {"mu":{"rules":[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24],"inclusive":false},"INITIAL":{"rules":[0,1,24],"inclusive":true}};return lexer;})() +parser.lexer = lexer; +return parser; +})(); +if (typeof require !== 'undefined' && typeof exports !== 'undefined') { +exports.parser = handlebars; +exports.parse = function () { return handlebars.parse.apply(handlebars, arguments); } +exports.main = function commonjsMain(args) { + if (!args[1]) + throw new Error('Usage: '+args[0]+' FILE'); + if (typeof process !== 'undefined') { + var source = require('fs').readFileSync(require('path').join(process.cwd(), args[1]), "utf8"); + } else { + var cwd = require("file").path(require("file").cwd()); + var source = cwd.join(args[1]).read({charset: "utf-8"}); + } + return exports.parser.parse(source); +} +if (typeof module !== 'undefined' && require.main === module) { + exports.main(typeof process !== 'undefined' ? process.argv.slice(1) : require("system").args); +} +}; +; +// lib/handlebars/base.js +var Handlebars = {}; + +Handlebars.VERSION = "1.0.beta.2"; + +Handlebars.Parser = handlebars; + +Handlebars.parse = function(string) { + Handlebars.Parser.yy = Handlebars.AST; + return Handlebars.Parser.parse(string); +}; + +Handlebars.print = function(ast) { + return new Handlebars.PrintVisitor().accept(ast); +}; + +Handlebars.helpers = {}; +Handlebars.partials = {}; + +Handlebars.registerHelper = function(name, fn, inverse) { + if(inverse) { fn.not = inverse; } + this.helpers[name] = fn; +}; + +Handlebars.registerPartial = function(name, str) { + this.partials[name] = str; +}; + +Handlebars.registerHelper('helperMissing', function(arg) { + if(arguments.length === 2) { + return undefined; + } else { + throw new Error("Could not find property '" + arg + "'"); + } +}); + +Handlebars.registerHelper('blockHelperMissing', function(context, options) { + var inverse = options.inverse || function() {}, fn = options.fn; + + + var ret = ""; + var type = Object.prototype.toString.call(context); + + if(type === "[object Function]") { + context = context(); + } + + if(context === true) { + return fn(this); + } else if(context === false || context == null) { + return inverse(this); + } else if(type === "[object Array]") { + if(context.length > 0) { + for(var i=0, j=context.length; i 0) { + for(var i=0, j=context.length; i": ">", + '"': """, + "'": "'", + "`": "`" + }; + + var badChars = /&(?!\w+;)|[<>"'`]/g; + var possible = /[&<>"'`]/; + + var escapeChar = function(chr) { + return escape[chr] || "&"; + }; + + Handlebars.Utils = { + escapeExpression: function(string) { + // don't escape SafeStrings, since they're already safe + if (string instanceof Handlebars.SafeString) { + return string.toString(); + } else if (string == null || string === false) { + return ""; + } + + if(!possible.test(string)) { return string; } + return string.replace(badChars, escapeChar); + }, + + isEmpty: function(value) { + if (typeof value === "undefined") { + return true; + } else if (value === null) { + return true; + } else if (value === false) { + return true; + } else if(Object.prototype.toString.call(value) === "[object Array]" && value.length === 0) { + return true; + } else { + return false; + } + } + }; +})();; +// lib/handlebars/compiler.js +Handlebars.Compiler = function() {}; +Handlebars.JavaScriptCompiler = function() {}; + +(function(Compiler, JavaScriptCompiler) { + Compiler.OPCODE_MAP = { + appendContent: 1, + getContext: 2, + lookupWithHelpers: 3, + lookup: 4, + append: 5, + invokeMustache: 6, + appendEscaped: 7, + pushString: 8, + truthyOrFallback: 9, + functionOrFallback: 10, + invokeProgram: 11, + invokePartial: 12, + push: 13, + assignToHash: 15, + pushStringParam: 16 + }; + + Compiler.MULTI_PARAM_OPCODES = { + appendContent: 1, + getContext: 1, + lookupWithHelpers: 1, + lookup: 1, + invokeMustache: 2, + pushString: 1, + truthyOrFallback: 1, + functionOrFallback: 1, + invokeProgram: 2, + invokePartial: 1, + push: 1, + assignToHash: 1, + pushStringParam: 1 + }; + + Compiler.DISASSEMBLE_MAP = {}; + + for(var prop in Compiler.OPCODE_MAP) { + var value = Compiler.OPCODE_MAP[prop]; + Compiler.DISASSEMBLE_MAP[value] = prop; + } + + Compiler.multiParamSize = function(code) { + return Compiler.MULTI_PARAM_OPCODES[Compiler.DISASSEMBLE_MAP[code]]; + }; + + Compiler.prototype = { + compiler: Compiler, + + disassemble: function() { + var opcodes = this.opcodes, opcode, nextCode; + var out = [], str, name, value; + + for(var i=0, l=opcodes.length; i 0) { + this.source[0] = this.source[0] + ", " + locals.join(", "); + } + + this.source[0] = this.source[0] + ";"; + + this.source.push("return buffer;"); + + var params = ["Handlebars", "context", "helpers", "partials"]; + + if(this.options.data) { params.push("data"); } + + for(var i=0, l=this.environment.depths.list.length; i this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); } + return "stack" + this.stackSlot; + }, + + popStack: function() { + return "stack" + this.stackSlot--; + }, + + topStack: function() { + return "stack" + this.stackSlot; + }, + + quotedString: function(str) { + return '"' + str + .replace(/\\/g, '\\\\') + .replace(/"/g, '\\"') + .replace(/\n/g, '\\n') + .replace(/\r/g, '\\r') + '"'; + } + }; + + var reservedWords = ("break case catch continue default delete do else finally " + + "for function if in instanceof new return switch this throw " + + "try typeof var void while with null true false").split(" "); + + compilerWords = JavaScriptCompiler.RESERVED_WORDS = {}; + + for(var i=0, l=reservedWords.length; i