diff --git a/ajax/libs/clientside-haml-js /5.1/haml.js b/ajax/libs/clientside-haml-js /5.1/haml.js new file mode 100644 index 000000000..a51889c51 --- /dev/null +++ b/ajax/libs/clientside-haml-js /5.1/haml.js @@ -0,0 +1,2058 @@ +// Generated by CoffeeScript 1.3.3 + +/* + clientside HAML compiler for Javascript and Coffeescript (Version 5) + + Copyright 2011-12, Ronald Holshausen (https://github.com/uglyog) + Released under the MIT License (http://www.opensource.org/licenses/MIT) +*/ + + +(function() { + var Buffer, CodeGenerator, CoffeeCodeGenerator, HamlRuntime, JsCodeGenerator, ProductionJsCodeGenerator, Tokeniser, filters, root, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + + root = this; + + /* + Haml runtime functions. These are used both by the compiler and the generated template functions + */ + + + HamlRuntime = { + /* + Taken from underscore.string.js escapeHTML, and replace the apos entity with character 39 so that it renders + correctly in IE7 + */ + + escapeHTML: function(str) { + return String(str || '').replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, "'"); + }, + /* + Provides the implementation to preserve the whitespace as per the HAML reference + */ + + perserveWhitespace: function(str) { + var i, out, re, result; + re = /<[a-zA-Z]+>[^<]*<\/[a-zA-Z]+>/g; + out = ''; + i = 0; + result = re.exec(str); + if (result) { + while (result) { + out += str.substring(i, result.index); + out += result[0].replace(/\n/g, ' '); + i = result.index + result[0].length; + result = re.exec(str); + } + out += str.substring(i); + } else { + out = str; + } + return out; + }, + /* + Generates a error message including the current line in the source where the error occurred + */ + + templateError: function(lineNumber, characterNumber, currentLine, error) { + var i, message; + message = error + " at line " + lineNumber + " and character " + characterNumber + ":\n" + currentLine + '\n'; + i = 0; + while (i < characterNumber - 1) { + message += '-'; + i++; + } + message += '^'; + return message; + }, + /* + Generates the attributes for the element by combining all the various sources together + */ + + generateElementAttributes: function(context, id, classes, objRefFn, attrList, attrFunction, lineNumber, characterNumber, currentLine) { + var attr, attributes, className, dataAttr, dataAttributes, hash, html, object, objectId; + attributes = {}; + attributes = this.combineAttributes(attributes, 'id', id); + if (classes.length > 0 && classes[0].length > 0) { + attributes = this.combineAttributes(attributes, 'class', classes); + } + if (attrList) { + for (attr in attrList) { + if (!__hasProp.call(attrList, attr)) continue; + attributes = this.combineAttributes(attributes, attr, attrList[attr]); + } + } + if (objRefFn) { + try { + object = objRefFn.call(context, context); + if (object) { + objectId = null; + if (object.id) { + objectId = object.id; + } else if (object.get) { + objectId = object.get('id'); + } + attributes = this.combineAttributes(attributes, 'id', objectId); + className = null; + if (object['class']) { + className = object['class']; + } else if (object.get) { + className = object.get('class'); + } + attributes = this.combineAttributes(attributes, 'class', className); + } + } catch (e) { + throw haml.HamlRuntime.templateError(lineNumber, characterNumber, currentLine, "Error evaluating object reference - " + e); + } + } + if (attrFunction) { + try { + hash = attrFunction.call(context, context); + if (hash) { + for (attr in hash) { + if (!__hasProp.call(hash, attr)) continue; + if (attr === 'data') { + dataAttributes = hash[attr]; + for (dataAttr in dataAttributes) { + if (!__hasProp.call(dataAttributes, dataAttr)) continue; + attributes = this.combineAttributes(attributes, 'data-' + dataAttr, dataAttributes[dataAttr]); + } + } else { + attributes = this.combineAttributes(attributes, attr, hash[attr]); + } + } + } + } catch (ex) { + throw haml.HamlRuntime.templateError(lineNumber, characterNumber, currentLine, "Error evaluating attribute hash - " + ex); + } + } + html = ''; + if (attributes) { + for (attr in attributes) { + if (!__hasProp.call(attributes, attr)) continue; + if (haml.hasValue(attributes[attr])) { + if ((attr === 'id' || attr === 'for') && attributes[attr] instanceof Array) { + html += ' ' + attr + '="' + _(attributes[attr]).flatten().join('-') + '"'; + } else if (attr === 'class' && attributes[attr] instanceof Array) { + html += ' ' + attr + '="' + _(attributes[attr]).flatten().join(' ') + '"'; + } else { + html += ' ' + attr + '="' + haml.attrValue(attr, attributes[attr]) + '"'; + } + } + } + } + return html; + }, + /* + Returns a white space string with a length of indent * 2 + */ + + indentText: function(indent) { + var i, text; + text = ''; + i = 0; + while (i < indent) { + text += ' '; + i++; + } + return text; + }, + /* + Combines the attributes in the attributres hash with the given attribute and value + ID, FOR and CLASS attributes will expand to arrays when multiple values are provided + */ + + combineAttributes: function(attributes, attrName, attrValue) { + var classes; + if (haml.hasValue(attrValue)) { + if (attrName === 'id' && attrValue.toString().length > 0) { + if (attributes && attributes.id instanceof Array) { + attributes.id.unshift(attrValue); + } else if (attributes && attributes.id) { + attributes.id = [attributes.id, attrValue]; + } else if (attributes) { + attributes.id = attrValue; + } else { + attributes = { + id: attrValue + }; + } + } else if (attrName === 'for' && attrValue.toString().length > 0) { + if (attributes && attributes['for'] instanceof Array) { + attributes['for'].unshift(attrValue); + } else if (attributes && attributes['for']) { + attributes['for'] = [attributes['for'], attrValue]; + } else if (attributes) { + attributes['for'] = attrValue; + } else { + attributes = { + 'for': attrValue + }; + } + } else if (attrName === 'class') { + classes = []; + if (attrValue instanceof Array) { + classes = classes.concat(attrValue); + } else { + classes.push(attrValue); + } + if (attributes && attributes['class']) { + attributes['class'] = attributes['class'].concat(classes); + } else if (attributes) { + attributes['class'] = classes; + } else { + attributes = { + 'class': classes + }; + } + } else if (attrName !== 'id') { + attributes || (attributes = {}); + attributes[attrName] = attrValue; + } + } + return attributes; + } + }; + + /* + HAML Tokiniser: This class is responsible for parsing the haml source into tokens + */ + + + Tokeniser = (function() { + + Tokeniser.prototype.currentLineMatcher = /[^\n]*/g; + + Tokeniser.prototype.tokenMatchers = { + whitespace: /[ \t]+/g, + element: /%[a-zA-Z][a-zA-Z0-9]*/g, + idSelector: /#[a-zA-Z_\-][a-zA-Z0-9_\-]*/g, + classSelector: /\.[a-zA-Z0-9_\-]+/g, + identifier: /[a-zA-Z][a-zA-Z0-9\-]*/g, + quotedString: /[\'][^\'\n]*[\']/g, + quotedString2: /[\"][^\"\n]*[\"]/g, + comment: /\-#/g, + escapeHtml: /\&=/g, + unescapeHtml: /\!=/g, + objectReference: /\[[a-zA-Z_@][a-zA-Z0-9_]*\]/g, + doctype: /!!!/g, + continueLine: /\|\s*\n/g, + filter: /:\w+/g + }; + + function Tokeniser(options) { + var errorFn, successFn, template, + _this = this; + this.buffer = null; + this.bufferIndex = null; + this.prevToken = null; + this.token = null; + if (options.templateId != null) { + template = document.getElementById(options.templateId); + if (template) { + this.buffer = template.text; + this.bufferIndex = 0; + } else { + throw "Did not find a template with ID '" + options.templateId + "'"; + } + } else if (options.template != null) { + this.buffer = options.template; + this.bufferIndex = 0; + } else if (options.templateUrl != null) { + errorFn = function(jqXHR, textStatus, errorThrown) { + throw "Failed to fetch haml template at URL " + options.templateUrl + ": " + textStatus + " " + errorThrown; + }; + successFn = function(data) { + _this.buffer = data; + return _this.bufferIndex = 0; + }; + jQuery.ajax({ + url: options.templateUrl, + success: successFn, + error: errorFn, + dataType: 'text', + async: false, + beforeSend: function(xhr) { + return xhr.withCredentials = true; + } + }); + } + } + + /* + Try to match a token with the given regexp + */ + + + Tokeniser.prototype.matchToken = function(matcher) { + var result; + matcher.lastIndex = this.bufferIndex; + result = matcher.exec(this.buffer); + if ((result != null ? result.index : void 0) === this.bufferIndex) { + return result[0]; + } + }; + + /* + Match a multi-character token + */ + + + Tokeniser.prototype.matchMultiCharToken = function(matcher, token, tokenStr) { + var matched, _ref; + if (!this.token) { + matched = this.matchToken(matcher); + if (matched) { + this.token = token; + this.token.tokenString = (_ref = typeof tokenStr === "function" ? tokenStr(matched) : void 0) != null ? _ref : matched; + this.token.matched = matched; + return this.advanceCharsInBuffer(matched.length); + } + } + }; + + /* + Match a single character token + */ + + + Tokeniser.prototype.matchSingleCharToken = function(ch, token) { + if (!this.token && this.buffer.charAt(this.bufferIndex) === ch) { + this.token = token; + this.token.tokenString = ch; + this.token.matched = ch; + return this.advanceCharsInBuffer(1); + } + }; + + /* + Match and return the next token in the input buffer + */ + + + Tokeniser.prototype.getNextToken = function() { + var braceCount, ch, ch1, characterNumberStart, i, lineNumberStart, str; + if (isNaN(this.bufferIndex)) { + throw haml.HamlRuntime.templateError(this.lineNumber, this.characterNumber, this.currentLine, "An internal parser error has occurred in the HAML parser"); + } + this.prevToken = this.token; + this.token = null; + if (this.buffer === null || this.buffer.length === this.bufferIndex) { + this.token = { + eof: true, + token: 'EOF' + }; + } else { + this.initLine(); + if (!this.token) { + ch = this.buffer.charCodeAt(this.bufferIndex); + ch1 = this.buffer.charCodeAt(this.bufferIndex + 1); + if (ch === 10 || (ch === 13 && ch1 === 10)) { + this.token = { + eol: true, + token: 'EOL' + }; + if (ch === 13 && ch1 === 10) { + this.advanceCharsInBuffer(2); + this.token.matched = String.fromCharCode(ch) + String.fromCharCode(ch1); + } else { + this.advanceCharsInBuffer(1); + this.token.matched = String.fromCharCode(ch); + } + this.characterNumber = 0; + this.currentLine = this.getCurrentLine(); + } + } + this.matchMultiCharToken(this.tokenMatchers.whitespace, { + ws: true, + token: 'WS' + }); + this.matchMultiCharToken(this.tokenMatchers.continueLine, { + continueLine: true, + token: 'CONTINUELINE' + }); + this.matchMultiCharToken(this.tokenMatchers.element, { + element: true, + token: 'ELEMENT' + }, function(matched) { + return matched.substring(1); + }); + this.matchMultiCharToken(this.tokenMatchers.idSelector, { + idSelector: true, + token: 'ID' + }, function(matched) { + return matched.substring(1); + }); + this.matchMultiCharToken(this.tokenMatchers.classSelector, { + classSelector: true, + token: 'CLASS' + }, function(matched) { + return matched.substring(1); + }); + this.matchMultiCharToken(this.tokenMatchers.identifier, { + identifier: true, + token: 'IDENTIFIER' + }); + this.matchMultiCharToken(this.tokenMatchers.doctype, { + doctype: true, + token: 'DOCTYPE' + }); + this.matchMultiCharToken(this.tokenMatchers.filter, { + filter: true, + token: 'FILTER' + }, function(matched) { + return matched.substring(1); + }); + if (!this.token) { + str = this.matchToken(this.tokenMatchers.quotedString); + if (!str) { + str = this.matchToken(this.tokenMatchers.quotedString2); + } + if (str) { + this.token = { + string: true, + token: 'STRING', + tokenString: str.substring(1, str.length - 1), + matched: str + }; + this.advanceCharsInBuffer(str.length); + } + } + this.matchMultiCharToken(this.tokenMatchers.comment, { + comment: true, + token: 'COMMENT' + }); + this.matchMultiCharToken(this.tokenMatchers.escapeHtml, { + escapeHtml: true, + token: 'ESCAPEHTML' + }); + this.matchMultiCharToken(this.tokenMatchers.unescapeHtml, { + unescapeHtml: true, + token: 'UNESCAPEHTML' + }); + this.matchMultiCharToken(this.tokenMatchers.objectReference, { + objectReference: true, + token: 'OBJECTREFERENCE' + }, function(matched) { + return matched.substring(1, matched.length - 1); + }); + if (!this.token) { + if (this.buffer && this.buffer.charAt(this.bufferIndex) === '{') { + i = this.bufferIndex + 1; + characterNumberStart = this.characterNumber; + lineNumberStart = this.lineNumber; + braceCount = 1; + while (i < this.buffer.length && (braceCount > 1 || this.buffer.charAt(i) !== '}')) { + if (this.buffer.charAt(i) === '{') { + braceCount++; + } else if (this.buffer.charAt(i) === '}') { + braceCount--; + } + i++; + } + if (i === this.buffer.length) { + this.characterNumber = characterNumberStart + 1; + this.lineNumber = lineNumberStart; + throw this.parseError('Error parsing attribute hash - Did not find a terminating "}"'); + } else { + this.token = { + attributeHash: true, + token: 'ATTRHASH', + tokenString: this.buffer.substring(this.bufferIndex, i + 1), + matched: this.buffer.substring(this.bufferIndex, i + 1) + }; + this.advanceCharsInBuffer(i - this.bufferIndex + 1); + } + } + } + this.matchSingleCharToken('(', { + openBracket: true, + token: 'OPENBRACKET' + }); + this.matchSingleCharToken(')', { + closeBracket: true, + token: 'CLOSEBRACKET' + }); + this.matchSingleCharToken('=', { + equal: true, + token: 'EQUAL' + }); + this.matchSingleCharToken('/', { + slash: true, + token: 'SLASH' + }); + this.matchSingleCharToken('!', { + exclamation: true, + token: 'EXCLAMATION' + }); + this.matchSingleCharToken('-', { + minus: true, + token: 'MINUS' + }); + this.matchSingleCharToken('&', { + amp: true, + token: 'AMP' + }); + this.matchSingleCharToken('<', { + lt: true, + token: 'LT' + }); + this.matchSingleCharToken('>', { + gt: true, + token: 'GT' + }); + this.matchSingleCharToken('~', { + tilde: true, + token: 'TILDE' + }); + if (this.token === null) { + this.token = { + unknown: true, + token: 'UNKNOWN' + }; + } + } + return this.token; + }; + + /* + Look ahead a number of tokens and return the token found + */ + + + Tokeniser.prototype.lookAhead = function(numberOfTokens) { + var bufferIndex, characterNumber, currentLine, currentToken, i, lineNumber, prevToken, token; + token = null; + if (numberOfTokens > 0) { + currentToken = this.token; + prevToken = this.prevToken; + currentLine = this.currentLine; + lineNumber = this.lineNumber; + characterNumber = this.characterNumber; + bufferIndex = this.bufferIndex; + i = 0; + while (i++ < numberOfTokens) { + token = this.getNextToken(); + } + this.token = currentToken; + this.prevToken = prevToken; + this.currentLine = currentLine; + this.lineNumber = lineNumber; + this.characterNumber = characterNumber; + this.bufferIndex = bufferIndex; + } + return token; + }; + + /* + Initilise the line and character counters + */ + + + Tokeniser.prototype.initLine = function() { + if (!this.currentLine && this.currentLine !== "") { + this.currentLine = this.getCurrentLine(); + this.lineNumber = 1; + return this.characterNumber = 0; + } + }; + + /* + Returns the current line in the input buffer + */ + + + Tokeniser.prototype.getCurrentLine = function(index) { + var line; + this.currentLineMatcher.lastIndex = this.bufferIndex + (index != null ? index : 0); + line = this.currentLineMatcher.exec(this.buffer); + if (line) { + return line[0]; + } else { + return ''; + } + }; + + /* + Returns an error string filled out with the line and character counters + */ + + + Tokeniser.prototype.parseError = function(error) { + return haml.HamlRuntime.templateError(this.lineNumber, this.characterNumber, this.currentLine, error); + }; + + /* + Skips to the end of the line and returns the string that was skipped + */ + + + Tokeniser.prototype.skipToEOLorEOF = function() { + var contents, line, text; + text = ''; + if (!(this.token.eof || this.token.eol)) { + if (!this.token.unknown) { + text += this.token.matched; + } + this.currentLineMatcher.lastIndex = this.bufferIndex; + line = this.currentLineMatcher.exec(this.buffer); + if (line && line.index === this.bufferIndex) { + contents = (_.str || _).rtrim(line[0]); + if ((_.str || _).endsWith(contents, '|')) { + text += contents.substring(0, contents.length - 1); + this.advanceCharsInBuffer(contents.length - 1); + this.getNextToken(); + text += this.parseMultiLine(); + } else { + text += line[0]; + this.advanceCharsInBuffer(line[0].length); + this.getNextToken(); + } + } + } + return text; + }; + + /* + Parses a multiline code block and returns the parsed text + */ + + + Tokeniser.prototype.parseMultiLine = function() { + var contents, line, text; + text = ''; + while (this.token.continueLine) { + this.currentLineMatcher.lastIndex = this.bufferIndex; + line = this.currentLineMatcher.exec(this.buffer); + if (line && line.index === this.bufferIndex) { + contents = (_.str || _).rtrim(line[0]); + if ((_.str || _).endsWith(contents, '|')) { + text += contents.substring(0, contents.length - 1); + this.advanceCharsInBuffer(contents.length - 1); + } + this.getNextToken(); + } + } + return text; + }; + + /* + Advances the input buffer pointer by a number of characters, updating the line and character counters + */ + + + Tokeniser.prototype.advanceCharsInBuffer = function(numChars) { + var ch, ch1, i; + i = 0; + while (i < numChars) { + ch = this.buffer.charCodeAt(this.bufferIndex + i); + ch1 = this.buffer.charCodeAt(this.bufferIndex + i + 1); + if (ch === 13 && ch1 === 10) { + this.lineNumber++; + this.characterNumber = 0; + this.currentLine = this.getCurrentLine(i); + i++; + } else if (ch === 10) { + this.lineNumber++; + this.characterNumber = 0; + this.currentLine = this.getCurrentLine(i); + } else { + this.characterNumber++; + } + i++; + } + return this.bufferIndex += numChars; + }; + + /* + Returns the current line and character counters + */ + + + Tokeniser.prototype.currentParsePoint = function() { + return { + lineNumber: this.lineNumber, + characterNumber: this.characterNumber, + currentLine: this.currentLine + }; + }; + + /* + Pushes back the current token onto the front of the input buffer + */ + + + Tokeniser.prototype.pushBackToken = function() { + if (!this.token.unknown && !this.token.eof) { + this.bufferIndex -= this.token.matched.length; + return this.token = this.prevToken; + } + }; + + /* + Is the current token an end of line or end of input buffer + */ + + + Tokeniser.prototype.isEolOrEof = function() { + return this.token.eol || this.token.eof; + }; + + return Tokeniser; + + })(); + + /* + Provides buffering between the generated javascript and html contents + */ + + + Buffer = (function() { + + function Buffer(generator) { + this.generator = generator; + this.buffer = ''; + this.outputBuffer = ''; + } + + Buffer.prototype.append = function(str) { + if (this.buffer.length === 0) { + this.generator.mark(); + } + if (str && str.length > 0) { + return this.buffer += str; + } + }; + + Buffer.prototype.appendToOutputBuffer = function(str) { + if (str && str.length > 0) { + this.flush(); + return this.outputBuffer += str; + } + }; + + Buffer.prototype.flush = function() { + if (this.buffer && this.buffer.length > 0) { + this.outputBuffer += this.generator.generateFlush(this.buffer); + } + return this.buffer = ''; + }; + + Buffer.prototype.output = function() { + return this.outputBuffer; + }; + + Buffer.prototype.trimWhitespace = function() { + var ch, i; + if (this.buffer.length > 0) { + i = this.buffer.length - 1; + while (i > 0) { + ch = this.buffer.charAt(i); + if (ch === ' ' || ch === '\t' || ch === '\n') { + i--; + } else if (i > 1 && (ch === 'n' || ch === 't') && (this.buffer.charAt(i - 1) === '\\')) { + i -= 2; + } else { + break; + } + } + if (i > 0 && i < this.buffer.length - 1) { + return this.buffer = this.buffer.substring(0, i + 1); + } else if (i === 0) { + return this.buffer = ''; + } + } + }; + + return Buffer; + + })(); + + /* + Common code shared across all code generators + */ + + + CodeGenerator = (function() { + + function CodeGenerator() {} + + CodeGenerator.prototype.embeddedCodeBlockMatcher = /#{([^}]*)}/g; + + return CodeGenerator; + + })(); + + /* + Code generator that generates a Javascript function body + */ + + + JsCodeGenerator = (function(_super) { + + __extends(JsCodeGenerator, _super); + + function JsCodeGenerator() { + this.outputBuffer = new haml.Buffer(this); + } + + /* + Append a line with embedded javascript code + */ + + + JsCodeGenerator.prototype.appendEmbeddedCode = function(indentText, expression, escapeContents, perserveWhitespace, currentParsePoint) { + this.outputBuffer.flush(); + this.outputBuffer.appendToOutputBuffer(indentText + 'try {\n'); + this.outputBuffer.appendToOutputBuffer(indentText + ' var value = eval("' + (_.str || _).trim(expression).replace(/"/g, '\\"').replace(/\\n/g, '\\\\n') + '");\n'); + this.outputBuffer.appendToOutputBuffer(indentText + ' value = value === null ? "" : value;'); + if (escapeContents) { + this.outputBuffer.appendToOutputBuffer(indentText + ' html.push(haml.HamlRuntime.escapeHTML(String(value)));\n'); + } else if (perserveWhitespace) { + this.outputBuffer.appendToOutputBuffer(indentText + ' html.push(haml.HamlRuntime.perserveWhitespace(String(value)));\n'); + } else { + this.outputBuffer.appendToOutputBuffer(indentText + ' html.push(String(value));\n'); + } + this.outputBuffer.appendToOutputBuffer(indentText + '} catch (e) {\n'); + this.outputBuffer.appendToOutputBuffer(indentText + ' throw new Error(haml.HamlRuntime.templateError(' + currentParsePoint.lineNumber + ', ' + currentParsePoint.characterNumber + ', "' + this.escapeCode(currentParsePoint.currentLine) + '",\n'); + this.outputBuffer.appendToOutputBuffer(indentText + ' "Error evaluating expression - " + e));\n'); + return this.outputBuffer.appendToOutputBuffer(indentText + '}\n'); + }; + + /* + Initilising the output buffer with any variables or code + */ + + + JsCodeGenerator.prototype.initOutput = function() { + return this.outputBuffer.appendToOutputBuffer(' var html = [];\n' + ' var hashFunction = null, hashObject = null, objRef = null, objRefFn = null;\n with (context || {}) {\n'); + }; + + /* + Flush and close the output buffer and return the contents + */ + + + JsCodeGenerator.prototype.closeAndReturnOutput = function() { + this.outputBuffer.flush(); + return this.outputBuffer.output() + ' }\n return html.join("");\n'; + }; + + /* + Append a line of code to the output buffer + */ + + + JsCodeGenerator.prototype.appendCodeLine = function(line, eol) { + this.outputBuffer.flush(); + this.outputBuffer.appendToOutputBuffer(HamlRuntime.indentText(this.indent)); + this.outputBuffer.appendToOutputBuffer(line); + return this.outputBuffer.appendToOutputBuffer(eol); + }; + + /* + Does the current line end with a function declaration? + */ + + + JsCodeGenerator.prototype.lineMatchesStartFunctionBlock = function(line) { + return line.match(/function\s*\((,?\s*\w+)*\)\s*\{\s*$/); + }; + + /* + Does the current line end with a starting code block + */ + + + JsCodeGenerator.prototype.lineMatchesStartBlock = function(line) { + return line.match(/\{\s*$/); + }; + + /* + Generate the code to close off a code block + */ + + + JsCodeGenerator.prototype.closeOffCodeBlock = function(tokeniser) { + if (!(tokeniser.token.minus && tokeniser.matchToken(/\s*\}/g))) { + this.outputBuffer.flush(); + return this.outputBuffer.appendToOutputBuffer(HamlRuntime.indentText(this.indent) + '}\n'); + } + }; + + /* + Generate the code to close off a function parameter + */ + + + JsCodeGenerator.prototype.closeOffFunctionBlock = function(tokeniser) { + if (!(tokeniser.token.minus && tokeniser.matchToken(/\s*\}/g))) { + this.outputBuffer.flush(); + return this.outputBuffer.appendToOutputBuffer(HamlRuntime.indentText(this.indent) + '});\n'); + } + }; + + /* + Generate the code for dynamic attributes ({} form) + */ + + + JsCodeGenerator.prototype.generateCodeForDynamicAttributes = function(id, classes, attributeList, attributeHash, objectRef, currentParsePoint) { + this.outputBuffer.flush(); + if (attributeHash.length > 0) { + attributeHash = this.replaceReservedWordsInHash(attributeHash); + this.outputBuffer.appendToOutputBuffer(' hashFunction = function () { return eval("hashObject = ' + attributeHash.replace(/"/g, '\\"').replace(/\n/g, '\\n') + '"); };\n'); + } + if (objectRef.length > 0) { + this.outputBuffer.appendToOutputBuffer(' objRefFn = function () { return eval("objRef = ' + objectRef.replace(/"/g, '\\"') + '"); };\n'); + } + return this.outputBuffer.appendToOutputBuffer(' html.push(haml.HamlRuntime.generateElementAttributes(context, "' + id + '", ["' + classes.join('","') + '"], objRefFn, ' + JSON.stringify(attributeList) + ', hashFunction, ' + currentParsePoint.lineNumber + ', ' + currentParsePoint.characterNumber + ', "' + this.escapeCode(currentParsePoint.currentLine) + '"));\n'); + }; + + /* + Clean any reserved words in the given hash + */ + + + JsCodeGenerator.prototype.replaceReservedWordsInHash = function(hash) { + var reservedWord, resultHash, _i, _len, _ref; + resultHash = hash; + _ref = ['class', 'for']; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + reservedWord = _ref[_i]; + resultHash = resultHash.replace(reservedWord + ':', '"' + reservedWord + '":'); + } + return resultHash; + }; + + /* + Escape the line so it is safe to put into a javascript string + */ + + + JsCodeGenerator.prototype.escapeCode = function(jsStr) { + return jsStr.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r'); + }; + + /* + Generate a function from the function body + */ + + + JsCodeGenerator.prototype.generateJsFunction = function(functionBody) { + try { + return new Function('context', functionBody); + } catch (e) { + throw "Incorrect embedded code has resulted in an invalid Haml function - " + e + "\nGenerated Function:\n" + functionBody; + } + }; + + /* + Generate the code required to support a buffer flush + */ + + + JsCodeGenerator.prototype.generateFlush = function(bufferStr) { + return ' html.push("' + this.escapeCode(bufferStr) + '");\n'; + }; + + /* + Set the current indent level + */ + + + JsCodeGenerator.prototype.setIndent = function(indent) { + return this.indent = indent; + }; + + /* + Save the current indent level if required + */ + + + JsCodeGenerator.prototype.mark = function() {}; + + /* + Append the text contents to the buffer, expanding any embedded code + */ + + + JsCodeGenerator.prototype.appendTextContents = function(text, shouldInterpolate, currentParsePoint, options) { + if (options == null) { + options = {}; + } + if (shouldInterpolate && text.match(/#{[^}]*}/)) { + return this.interpolateString(text, currentParsePoint, options); + } else { + return this.outputBuffer.append(this.processText(text, options)); + } + }; + + /* + Interpolate any embedded code in the text + */ + + + JsCodeGenerator.prototype.interpolateString = function(text, currentParsePoint, options) { + var index, precheedingChar, precheedingChar2, result; + index = 0; + result = this.embeddedCodeBlockMatcher.exec(text); + while (result) { + if (result.index > 0) { + precheedingChar = text.charAt(result.index - 1); + } + if (result.index > 1) { + precheedingChar2 = text.charAt(result.index - 2); + } + if (precheedingChar === '\\' && precheedingChar2 !== '\\') { + if (result.index !== 0) { + this.outputBuffer.append(this.processText(text.substring(index, result.index - 1), options)); + } + this.outputBuffer.append(this.processText(result[0]), options); + } else { + this.outputBuffer.append(this.processText(text.substring(index, result.index)), options); + this.appendEmbeddedCode(HamlRuntime.indentText(this.indent + 1), result[1], options.escapeHTML, options.perserveWhitespace, currentParsePoint); + } + index = this.embeddedCodeBlockMatcher.lastIndex; + result = this.embeddedCodeBlockMatcher.exec(text); + } + if (index < text.length) { + return this.outputBuffer.append(this.processText(text.substring(index), options)); + } + }; + + /* + process text based on escape and preserve flags + */ + + + JsCodeGenerator.prototype.processText = function(text, options) { + if (options != null ? options.escapeHTML : void 0) { + return haml.HamlRuntime.escapeHTML(text); + } else if (options != null ? options.perserveWhitespace : void 0) { + return haml.HamlRuntime.perserveWhitespace(text); + } else { + return text; + } + }; + + return JsCodeGenerator; + + })(CodeGenerator); + + /* + Code generator that generates javascript code without runtime evaluation + */ + + + ProductionJsCodeGenerator = (function(_super) { + + __extends(ProductionJsCodeGenerator, _super); + + function ProductionJsCodeGenerator() { + return ProductionJsCodeGenerator.__super__.constructor.apply(this, arguments); + } + + /* + Append a line with embedded javascript code + */ + + + ProductionJsCodeGenerator.prototype.appendEmbeddedCode = function(indentText, expression, escapeContents, perserveWhitespace, currentParsePoint) { + this.outputBuffer.flush(); + this.outputBuffer.appendToOutputBuffer(indentText + ' value = ' + (_.str || _).trim(expression) + ';\n'); + this.outputBuffer.appendToOutputBuffer(indentText + ' value = value === null ? "" : value;'); + if (escapeContents) { + return this.outputBuffer.appendToOutputBuffer(indentText + ' html.push(haml.HamlRuntime.escapeHTML(String(value)));\n'); + } else if (perserveWhitespace) { + return this.outputBuffer.appendToOutputBuffer(indentText + ' html.push(haml.HamlRuntime.perserveWhitespace(String(value)));\n'); + } else { + return this.outputBuffer.appendToOutputBuffer(indentText + ' html.push(String(value));\n'); + } + }; + + /* + Generate the code for dynamic attributes ({} form) + */ + + + ProductionJsCodeGenerator.prototype.generateCodeForDynamicAttributes = function(id, classes, attributeList, attributeHash, objectRef, currentParsePoint) { + this.outputBuffer.flush(); + if (attributeHash.length > 0) { + attributeHash = this.replaceReservedWordsInHash(attributeHash); + this.outputBuffer.appendToOutputBuffer(' hashFunction = function () { return ' + attributeHash + '; };\n'); + } + if (objectRef.length > 0) { + this.outputBuffer.appendToOutputBuffer(' objRefFn = function () { return ' + objectRef + '; };\n'); + } + return this.outputBuffer.appendToOutputBuffer(' html.push(haml.HamlRuntime.generateElementAttributes(context, "' + id + '", ["' + classes.join('","') + '"], objRefFn, ' + JSON.stringify(attributeList) + ', hashFunction, ' + currentParsePoint.lineNumber + ', ' + currentParsePoint.characterNumber + ', "' + this.escapeCode(currentParsePoint.currentLine) + '"));\n'); + }; + + /* + Initilising the output buffer with any variables or code + */ + + + ProductionJsCodeGenerator.prototype.initOutput = function() { + return this.outputBuffer.appendToOutputBuffer(' var html = [];\n' + ' var hashFunction = null, hashObject = null, objRef = null, objRefFn = null, value= null;\n with (context || {}) {\n'); + }; + + return ProductionJsCodeGenerator; + + })(JsCodeGenerator); + + /* + Code generator that generates a coffeescript function body + */ + + + CoffeeCodeGenerator = (function(_super) { + + __extends(CoffeeCodeGenerator, _super); + + function CoffeeCodeGenerator() { + this.outputBuffer = new haml.Buffer(this); + } + + CoffeeCodeGenerator.prototype.appendEmbeddedCode = function(indentText, expression, escapeContents, perserveWhitespace, currentParsePoint) { + var indent; + this.outputBuffer.flush(); + indent = this.calcCodeIndent(); + this.outputBuffer.appendToOutputBuffer(indent + "try\n"); + this.outputBuffer.appendToOutputBuffer(indent + " exp = CoffeeScript.compile('" + expression.replace(/'/g, "\\'").replace(/\\n/g, '\\\\n') + "', bare: true)\n"); + this.outputBuffer.appendToOutputBuffer(indent + " value = eval(exp)\n"); + this.outputBuffer.appendToOutputBuffer(indent + " value ?= ''\n"); + if (escapeContents) { + this.outputBuffer.appendToOutputBuffer(indent + " html.push(haml.HamlRuntime.escapeHTML(String(value)))\n"); + } else if (perserveWhitespace) { + this.outputBuffer.appendToOutputBuffer(indent + " html.push(haml.HamlRuntime.perserveWhitespace(String(value)))\n"); + } else { + this.outputBuffer.appendToOutputBuffer(indent + " html.push(String(value))\n"); + } + this.outputBuffer.appendToOutputBuffer(indent + "catch e \n"); + this.outputBuffer.appendToOutputBuffer(indent + " throw new Error(haml.HamlRuntime.templateError(" + currentParsePoint.lineNumber + ", " + currentParsePoint.characterNumber + ", '" + this.escapeCode(currentParsePoint.currentLine) + "',\n"); + return this.outputBuffer.appendToOutputBuffer(indent + " 'Error evaluating expression - ' + e))\n"); + }; + + CoffeeCodeGenerator.prototype.initOutput = function() { + return this.outputBuffer.appendToOutputBuffer('html = []\n'); + }; + + CoffeeCodeGenerator.prototype.closeAndReturnOutput = function() { + this.outputBuffer.flush(); + return this.outputBuffer.output() + 'return html.join("")\n'; + }; + + CoffeeCodeGenerator.prototype.appendCodeLine = function(line, eol) { + this.outputBuffer.flush(); + this.outputBuffer.appendToOutputBuffer(this.calcCodeIndent()); + this.outputBuffer.appendToOutputBuffer((_.str || _).trim(line)); + this.outputBuffer.appendToOutputBuffer(eol); + return this.prevCodeIndent = this.indent; + }; + + CoffeeCodeGenerator.prototype.lineMatchesStartFunctionBlock = function(line) { + return line.match(/\) [\-=]>\s*$/); + }; + + CoffeeCodeGenerator.prototype.lineMatchesStartBlock = function(line) { + return true; + }; + + CoffeeCodeGenerator.prototype.closeOffCodeBlock = function(tokeniser) { + return this.outputBuffer.flush(); + }; + + CoffeeCodeGenerator.prototype.closeOffFunctionBlock = function(tokeniser) { + return this.outputBuffer.flush(); + }; + + CoffeeCodeGenerator.prototype.generateCodeForDynamicAttributes = function(id, classes, attributeList, attributeHash, objectRef, currentParsePoint) { + var indent; + this.outputBuffer.flush(); + indent = this.calcCodeIndent(); + if (attributeHash.length > 0) { + attributeHash = this.replaceReservedWordsInHash(attributeHash); + this.outputBuffer.appendToOutputBuffer(indent + "hashFunction = () -> s = CoffeeScript.compile('" + attributeHash.replace(/'/g, "\\'").replace(/\n/g, '\\n') + "', bare: true); eval 'hashObject = ' + s\n"); + } + if (objectRef.length > 0) { + this.outputBuffer.appendToOutputBuffer(indent + "objRefFn = () -> s = CoffeeScript.compile('" + objectRef.replace(/'/g, "\\'") + "', bare: true); eval 'objRef = ' + s\n"); + } + return this.outputBuffer.appendToOutputBuffer(indent + "html.push(haml.HamlRuntime.generateElementAttributes(this, '" + id + "', ['" + classes.join("','") + "'], objRefFn ? null, " + JSON.stringify(attributeList) + ", hashFunction ? null, " + currentParsePoint.lineNumber + ", " + currentParsePoint.characterNumber + ", '" + this.escapeCode(currentParsePoint.currentLine) + "'))\n"); + }; + + CoffeeCodeGenerator.prototype.replaceReservedWordsInHash = function(hash) { + var reservedWord, resultHash, _i, _len, _ref; + resultHash = hash; + _ref = ['class', 'for']; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + reservedWord = _ref[_i]; + resultHash = resultHash.replace(reservedWord + ':', "'" + reservedWord + "':"); + } + return resultHash; + }; + + /* + Escapes the string for insertion into the generated code. Embedded code blocks in strings must not be escaped + */ + + + CoffeeCodeGenerator.prototype.escapeCode = function(str) { + var index, outString, precheedingChar, precheedingChar2, result; + outString = ''; + index = 0; + result = this.embeddedCodeBlockMatcher.exec(str); + while (result) { + if (result.index > 0) { + precheedingChar = str.charAt(result.index - 1); + } + if (result.index > 1) { + precheedingChar2 = str.charAt(result.index - 2); + } + if (precheedingChar === '\\' && precheedingChar2 !== '\\') { + if (result.index !== 0) { + outString += this._escapeText(str.substring(index, result.index - 1)); + } + outString += this._escapeText('\\' + result[0]); + } else { + outString += this._escapeText(str.substring(index, result.index)); + outString += result[0]; + } + index = this.embeddedCodeBlockMatcher.lastIndex; + result = this.embeddedCodeBlockMatcher.exec(str); + } + if (index < str.length) { + outString += this._escapeText(str.substring(index)); + } + return outString; + }; + + CoffeeCodeGenerator.prototype._escapeText = function(text) { + return text.replace(/\\/g, '\\\\').replace(/'/g, '\\\'').replace(/"/g, '\\\"').replace(/\n/g, '\\n').replace(/(^|[^\\]{2})\\\\#{/g, '$1\\#{'); + }; + + /* + Generates the javascript function by compiling the given code with coffeescript compiler + */ + + + CoffeeCodeGenerator.prototype.generateJsFunction = function(functionBody) { + var fn; + try { + fn = CoffeeScript.compile(functionBody, { + bare: true + }); + return new Function(fn); + } catch (e) { + throw "Incorrect embedded code has resulted in an invalid Haml function - " + e + "\nGenerated Function:\n" + fn; + } + }; + + CoffeeCodeGenerator.prototype.generateFlush = function(bufferStr) { + return this.calcCodeIndent() + "html.push('" + this.escapeCode(bufferStr) + "')\n"; + }; + + CoffeeCodeGenerator.prototype.setIndent = function(indent) { + return this.indent = indent; + }; + + CoffeeCodeGenerator.prototype.mark = function() { + return this.prevIndent = this.indent; + }; + + CoffeeCodeGenerator.prototype.calcCodeIndent = function() { + var codeIndent, i, _i, _ref, _ref1, _ref2; + codeIndent = 0; + for (i = _i = 0, _ref = this.indent; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) { + if (((_ref1 = this.elementStack[i]) != null ? _ref1.block : void 0) || ((_ref2 = this.elementStack[i]) != null ? _ref2.fnBlock : void 0)) { + codeIndent += 1; + } + } + return HamlRuntime.indentText(codeIndent); + }; + + /* + Append the text contents to the buffer (interpolating embedded code not required for coffeescript) + */ + + + CoffeeCodeGenerator.prototype.appendTextContents = function(text, shouldInterpolate, currentParsePoint, options) { + var prefix, suffix; + if (shouldInterpolate && text.match(/#{[^}]*}/)) { + this.outputBuffer.flush(); + prefix = suffix = ''; + if (options != null ? options.escapeHTML : void 0) { + prefix = 'haml.HamlRuntime.escapeHTML('; + suffix = ')'; + } else if (options != null ? options.perserveWhitespace : void 0) { + prefix = 'haml.HamlRuntime.perserveWhitespace('; + suffix = ')'; + } + return this.outputBuffer.appendToOutputBuffer(this.calcCodeIndent() + 'html.push(' + prefix + '"' + this.escapeCode(text) + '"' + suffix + ')\n'); + } else { + if (options != null ? options.escapeHTML : void 0) { + text = haml.HamlRuntime.escapeHTML(text); + } + if (options != null ? options.perserveWhitespace : void 0) { + text = haml.HamlRuntime.perserveWhitespace(text); + } + return this.outputBuffer.append(text); + } + }; + + return CoffeeCodeGenerator; + + })(CodeGenerator); + + /* + HAML filters are functions that take 3 parameters + contents: The contents block for the filter an array of lines of text + generator: The current generator for the compiled function + indentText: A whitespace string specifying the current indent level + currentParsePoint: line and character counters for the current parse point in the input buffer + */ + + + filters = { + /* + Plain filter, just renders the text in the block + */ + + plain: function(contents, generator, indentText, currentParsePoint) { + var line, _i, _len; + for (_i = 0, _len = contents.length; _i < _len; _i++) { + line = contents[_i]; + generator.appendTextContents(indentText + line + '\n', true, currentParsePoint); + } + return true; + }, + /* + Wraps the filter block in a javascript tag + */ + + javascript: function(contents, generator, indentText, currentParsePoint) { + var line, _i, _len; + generator.outputBuffer.append(indentText + "\n"); + }, + /* + Wraps the filter block in a style tag + */ + + css: function(contents, generator, indentText, currentParsePoint) { + var line, _i, _len; + generator.outputBuffer.append(indentText + "\n"); + }, + /* + Wraps the filter block in a CDATA tag + */ + + cdata: function(contents, generator, indentText, currentParsePoint) { + var line, _i, _len; + generator.outputBuffer.append(indentText + "\n"); + }, + /* + Preserve filter, preserved blocks of text aren't indented, and newlines are replaced with the HTML escape code for newlines + */ + + preserve: function(contents, generator, indentText, currentParsePoint) { + return generator.appendTextContents(contents.join('\n') + '\n', true, currentParsePoint, { + perserveWhitespace: true + }); + }, + /* + Escape filter, renders the text in the block with html escaped + */ + + escape: function(contents, generator, indentText, currentParsePoint) { + var line, _i, _len; + for (_i = 0, _len = contents.length; _i < _len; _i++) { + line = contents[_i]; + generator.appendTextContents(indentText + line + '\n', true, currentParsePoint, { + escapeHTML: true + }); + } + return true; + } + }; + + /* + Main haml compiler implemtation + */ + + + root.haml = { + /* + Compiles the haml provided in the parameters to a Javascipt function + + Parameter: + String: Looks for a haml template in dom with this ID + Option Hash: The following options determines how haml sources and compiles the template + source - This contains the template in string form + sourceId - This contains the element ID in the dom which contains the haml source + sourceUrl - This contains the URL where the template can be fetched from + outputFormat - This determines what is returned, and has the following values: + string - The javascript source code + function - A javascript function (default) + generator - Which code generator to use + javascript (default) + coffeescript + productionjavascript + + Returns a javascript function + */ + + compileHaml: function(options) { + var codeGenerator, result, tokinser; + if (typeof options === 'string') { + return this._compileHamlTemplate(options, new haml.JsCodeGenerator()); + } else { + codeGenerator = (function() { + switch (options.generator) { + case 'coffeescript': + return new haml.CoffeeCodeGenerator(); + case 'productionjavascript': + return new haml.ProductionJsCodeGenerator(); + default: + return new haml.JsCodeGenerator(); + } + })(); + if (options.source != null) { + tokinser = new haml.Tokeniser({ + template: options.source + }); + } else if (options.sourceId != null) { + tokinser = new haml.Tokeniser({ + templateId: options.sourceId + }); + } else if (options.sourceUrl != null) { + tokinser = new haml.Tokeniser({ + templateUrl: options.sourceUrl + }); + } else { + throw "No template source specified for compileHaml. You need to provide a source, sourceId or sourceUrl option"; + } + result = this._compileHamlToJs(tokinser, codeGenerator); + if (options.outputFormat !== 'string') { + return codeGenerator.generateJsFunction(result); + } else { + return "function (context) {\n" + result + "}\n"; + } + } + }, + /* + Compiles the haml in the script block with ID templateId using the coffeescript generator + Returns a javascript function + */ + + compileCoffeeHaml: function(templateId) { + return this._compileHamlTemplate(templateId, new haml.CoffeeCodeGenerator()); + }, + /* + Compiles the haml in the passed in string + Returns a javascript function + */ + + compileStringToJs: function(string) { + var codeGenerator, result; + codeGenerator = new haml.JsCodeGenerator(); + result = this._compileHamlToJs(new haml.Tokeniser({ + template: string + }), codeGenerator); + return codeGenerator.generateJsFunction(result); + }, + /* + Compiles the haml in the passed in string using the coffeescript generator + Returns a javascript function + */ + + compileCoffeeHamlFromString: function(string) { + var codeGenerator, result; + codeGenerator = new haml.CoffeeCodeGenerator(); + result = this._compileHamlToJs(new haml.Tokeniser({ + template: string + }), codeGenerator); + return codeGenerator.generateJsFunction(result); + }, + /* + Compiles the haml in the passed in string + Returns the javascript function source + + This is mainly used for precompiling the haml templates so they can be packaged. + */ + + compileHamlToJsString: function(string) { + var result; + result = 'function (context) {\n'; + result += this._compileHamlToJs(new haml.Tokeniser({ + template: string + }), new haml.JsCodeGenerator()); + return result += '}\n'; + }, + _compileHamlTemplate: function(templateId, codeGenerator) { + var fn, result; + haml.cache || (haml.cache = {}); + if (haml.cache[templateId]) { + return haml.cache[templateId]; + } + result = this._compileHamlToJs(new haml.Tokeniser({ + templateId: templateId + }), codeGenerator); + fn = codeGenerator.generateJsFunction(result); + haml.cache[templateId] = fn; + return fn; + }, + _compileHamlToJs: function(tokeniser, generator) { + var indent; + generator.elementStack = []; + generator.initOutput(); + tokeniser.getNextToken(); + while (!tokeniser.token.eof) { + if (!tokeniser.token.eol) { + indent = this._whitespace(tokeniser); + generator.setIndent(indent); + if (tokeniser.token.eol) { + generator.outputBuffer.append(HamlRuntime.indentText(indent) + tokeniser.token.matched); + tokeniser.getNextToken(); + } else if (tokeniser.token.doctype) { + this._doctype(tokeniser, indent, generator); + } else if (tokeniser.token.exclamation) { + this._ignoredLine(tokeniser, indent, generator.elementStack, generator); + } else if (tokeniser.token.equal || tokeniser.token.escapeHtml || tokeniser.token.unescapeHtml || tokeniser.token.tilde) { + this._embeddedJs(tokeniser, indent, generator.elementStack, { + innerWhitespace: true + }, generator); + } else if (tokeniser.token.minus) { + this._jsLine(tokeniser, indent, generator.elementStack, generator); + } else if (tokeniser.token.comment || tokeniser.token.slash) { + this._commentLine(tokeniser, indent, generator.elementStack, generator); + } else if (tokeniser.token.amp) { + this._escapedLine(tokeniser, indent, generator.elementStack, generator); + } else if (tokeniser.token.filter) { + this._filter(tokeniser, indent, generator); + } else { + this._templateLine(tokeniser, generator.elementStack, indent, generator); + } + } else { + generator.outputBuffer.append(tokeniser.token.matched); + tokeniser.getNextToken(); + } + } + this._closeElements(0, generator.elementStack, tokeniser, generator); + return generator.closeAndReturnOutput(); + }, + _doctype: function(tokeniser, indent, generator) { + var contents, params; + if (tokeniser.token.doctype) { + generator.outputBuffer.append(HamlRuntime.indentText(indent)); + tokeniser.getNextToken(); + if (tokeniser.token.ws) { + tokeniser.getNextToken(); + } + contents = tokeniser.skipToEOLorEOF(); + if (contents && contents.length > 0) { + params = contents.split(/\s+/); + switch (params[0]) { + case 'XML': + if (params.length > 1) { + generator.outputBuffer.append(""); + } else { + generator.outputBuffer.append(""); + } + break; + case 'Strict': + generator.outputBuffer.append(''); + break; + case 'Frameset': + generator.outputBuffer.append(''); + break; + case '5': + generator.outputBuffer.append(''); + break; + case '1.1': + generator.outputBuffer.append(''); + break; + case 'Basic': + generator.outputBuffer.append(''); + break; + case 'Mobile': + generator.outputBuffer.append(''); + break; + case 'RDFa': + generator.outputBuffer.append(''); + } + } else { + generator.outputBuffer.append(''); + } + generator.outputBuffer.append(this._newline(tokeniser)); + return tokeniser.getNextToken(); + } + }, + _filter: function(tokeniser, indent, generator) { + var filter, filterBlock, i, line; + if (tokeniser.token.filter) { + filter = tokeniser.token.tokenString; + if (!haml.filters[filter]) { + throw tokeniser.parseError("Filter '" + filter + "' not registered. Filter functions need to be added to 'haml.filters'."); + } + tokeniser.skipToEOLorEOF(); + tokeniser.getNextToken(); + i = haml._whitespace(tokeniser); + filterBlock = []; + while (!tokeniser.token.eof && i > indent) { + line = tokeniser.skipToEOLorEOF(); + filterBlock.push(haml.HamlRuntime.indentText(i - indent - 1) + line); + tokeniser.getNextToken(); + i = haml._whitespace(tokeniser); + } + haml.filters[filter](filterBlock, generator, haml.HamlRuntime.indentText(indent), tokeniser.currentParsePoint()); + return tokeniser.pushBackToken(); + } + }, + _commentLine: function(tokeniser, indent, elementStack, generator) { + var contents, i; + if (tokeniser.token.comment) { + tokeniser.skipToEOLorEOF(); + tokeniser.getNextToken(); + i = this._whitespace(tokeniser); + while (!tokeniser.token.eof && i > indent) { + tokeniser.skipToEOLorEOF(); + tokeniser.getNextToken(); + i = this._whitespace(tokeniser); + } + if (i > 0) { + return tokeniser.pushBackToken(); + } + } else if (tokeniser.token.slash) { + haml._closeElements(indent, elementStack, tokeniser, generator); + generator.outputBuffer.append(HamlRuntime.indentText(indent)); + generator.outputBuffer.append("' + elementStack[indent].eol); + } else if (elementStack[indent].htmlConditionalComment) { + generator.outputBuffer.append(HamlRuntime.indentText(indent) + '' + elementStack[indent].eol); + } else if (elementStack[indent].block) { + generator.closeOffCodeBlock(tokeniser); + } else if (elementStack[indent].fnBlock) { + generator.closeOffFunctionBlock(tokeniser); + } else { + innerWhitespace = !elementStack[indent].tagOptions || elementStack[indent].tagOptions.innerWhitespace; + if (innerWhitespace) { + generator.outputBuffer.append(HamlRuntime.indentText(indent)); + } else { + generator.outputBuffer.trimWhitespace(); + } + generator.outputBuffer.append(''); + outerWhitespace = !elementStack[indent].tagOptions || elementStack[indent].tagOptions.outerWhitespace; + if (haml._parentInnerWhitespace(elementStack, indent) && outerWhitespace) { + generator.outputBuffer.append('\n'); + } + } + elementStack[indent] = null; + return generator.mark(); + } + }, + _closeElements: function(indent, elementStack, tokeniser, generator) { + var i, _results; + i = elementStack.length - 1; + _results = []; + while (i >= indent) { + _results.push(this._closeElement(i--, elementStack, tokeniser, generator)); + } + return _results; + }, + _openElement: function(currentParsePoint, indent, identifier, id, classes, objectRef, attributeList, attributeHash, elementStack, tagOptions, generator) { + var element, parentInnerWhitespace, tagOuterWhitespace; + element = identifier.length === 0 ? "div" : identifier; + parentInnerWhitespace = this._parentInnerWhitespace(elementStack, indent); + tagOuterWhitespace = !tagOptions || tagOptions.outerWhitespace; + if (!tagOuterWhitespace) { + generator.outputBuffer.trimWhitespace(); + } + if (indent > 0 && parentInnerWhitespace && tagOuterWhitespace) { + generator.outputBuffer.append(HamlRuntime.indentText(indent)); + } + generator.outputBuffer.append('<' + element); + if (attributeHash.length > 0 || objectRef.length > 0) { + generator.generateCodeForDynamicAttributes(id, classes, attributeList, attributeHash, objectRef, currentParsePoint); + } else { + generator.outputBuffer.append(HamlRuntime.generateElementAttributes(null, id, classes, null, attributeList, null, currentParsePoint.lineNumber, currentParsePoint.characterNumber, currentParsePoint.currentLine)); + } + if (tagOptions.selfClosingTag) { + generator.outputBuffer.append("/>"); + if (tagOptions.outerWhitespace) { + return generator.outputBuffer.append("\n"); + } + } else { + generator.outputBuffer.append(">"); + elementStack[indent] = { + tag: element, + tagOptions: tagOptions + }; + if (tagOptions.innerWhitespace) { + return generator.outputBuffer.append("\n"); + } + } + }, + _isSelfClosingTag: function(tag) { + return tag === 'meta' || tag === 'img' || tag === 'link' || tag === 'script' || tag === 'br' || tag === 'hr'; + }, + _tagHasContents: function(indent, tokeniser) { + var nextToken; + if (!tokeniser.isEolOrEof()) { + return true; + } else { + nextToken = tokeniser.lookAhead(1); + return nextToken.ws && nextToken.tokenString.length / 2 > indent; + } + }, + _parentInnerWhitespace: function(elementStack, indent) { + return indent === 0 || (!elementStack[indent - 1] || !elementStack[indent - 1].tagOptions || elementStack[indent - 1].tagOptions.innerWhitespace); + }, + _lineHasElement: function(identifier, id, classes) { + return identifier.length > 0 || id.length > 0 || classes.length > 0; + }, + hasValue: function(value) { + return (value != null) && value !== false; + }, + attrValue: function(attr, value) { + if (attr === 'selected' || attr === 'checked' || attr === 'disabled') { + return attr; + } else { + return value; + } + }, + _whitespace: function(tokeniser) { + var i, indent, whitespace; + indent = 0; + if (tokeniser.token.ws) { + i = 0; + whitespace = tokeniser.token.tokenString; + while (i < whitespace.length) { + if (whitespace.charCodeAt(i) === 9 && i % 2 === 0) { + indent += 2; + } else { + indent++; + } + i++; + } + indent = Math.floor((indent + 1) / 2); + tokeniser.getNextToken(); + } + return indent; + }, + _element: function(tokeniser) { + var identifier; + identifier = ''; + if (tokeniser.token.element) { + identifier = tokeniser.token.tokenString; + tokeniser.getNextToken(); + } + return identifier; + }, + _eolOrEof: function(tokeniser) { + if (tokeniser.token.eol || tokeniser.token.continueLine) { + return tokeniser.getNextToken(); + } else if (!tokeniser.token.eof) { + throw tokeniser.parseError("Expected EOL or EOF"); + } + }, + _idSelector: function(tokeniser) { + var id; + id = ''; + if (tokeniser.token.idSelector) { + id = tokeniser.token.tokenString; + tokeniser.getNextToken(); + } + return id; + }, + _classSelector: function(tokeniser) { + var classes; + classes = []; + while (tokeniser.token.classSelector) { + classes.push(tokeniser.token.tokenString); + tokeniser.getNextToken(); + } + return classes; + }, + _newline: function(tokeniser) { + if (tokeniser.token.eol) { + return tokeniser.token.matched; + } else if (tokeniser.token.continueLine) { + return tokeniser.token.matched.substring(1); + } else { + return "\n"; + } + } + }; + + root.haml.Tokeniser = Tokeniser; + + root.haml.Buffer = Buffer; + + root.haml.JsCodeGenerator = JsCodeGenerator; + + root.haml.ProductionJsCodeGenerator = ProductionJsCodeGenerator; + + root.haml.CoffeeCodeGenerator = CoffeeCodeGenerator; + + root.haml.HamlRuntime = HamlRuntime; + + root.haml.filters = filters; + +}).call(this); diff --git a/ajax/libs/clientside-haml-js /5.1/haml.min.js b/ajax/libs/clientside-haml-js /5.1/haml.min.js new file mode 100644 index 000000000..72cc72daf --- /dev/null +++ b/ajax/libs/clientside-haml-js /5.1/haml.min.js @@ -0,0 +1,8 @@ +// Generated by CoffeeScript 1.3.3 +/* + clientside HAML compiler for Javascript and Coffeescript (Version 5) + + Copyright 2011-12, Ronald Holshausen (https://github.com/uglyog) + Released under the MIT License (http://www.opensource.org/licenses/MIT) +*/(function(){var e,t,n,r,i,s,o,u,a,f={}.hasOwnProperty,l=function(e,t){function r(){this.constructor=e}for(var n in t)f.call(t,n)&&(e[n]=t[n]);return r.prototype=t.prototype,e.prototype=new r,e.__super__=t.prototype,e};a=this,r={escapeHTML:function(e){return String(e||"").replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")},perserveWhitespace:function(e){var t,n,r,i;r=/<[a-zA-Z]+>[^<]*<\/[a-zA-Z]+>/g,n="",t=0,i=r.exec(e);if(i){while(i)n+=e.substring(t,i.index),n+=i[0].replace(/\n/g," "),t=i.index+i[0].length,i=r.exec(e);n+=e.substring(t)}else n=e;return n},templateError:function(e,t,n,r){var i,s;s=r+" at line "+e+" and character "+t+":\n"+n+"\n",i=0;while(i0&&n[0].length>0&&(c=this.combineAttributes(c,"class",n));if(i)for(l in i){if(!f.call(i,l))continue;c=this.combineAttributes(c,l,i[l])}if(r)try{g=r.call(e,e),g&&(y=null,g.id?y=g.id:g.get&&(y=g.get("id")),c=this.combineAttributes(c,"id",y),h=null,g["class"]?h=g["class"]:g.get&&(h=g.get("class")),c=this.combineAttributes(c,"class",h))}catch(b){throw haml.HamlRuntime.templateError(o,u,a,"Error evaluating object reference - "+b)}if(s)try{v=s.call(e,e);if(v)for(l in v){if(!f.call(v,l))continue;if(l==="data"){d=v[l];for(p in d){if(!f.call(d,p))continue;c=this.combineAttributes(c,"data-"+p,d[p])}}else c=this.combineAttributes(c,l,v[l])}}catch(w){throw haml.HamlRuntime.templateError(o,u,a,"Error evaluating attribute hash - "+w)}m="";if(c)for(l in c){if(!f.call(c,l))continue;haml.hasValue(c[l])&&((l==="id"||l==="for")&&c[l]instanceof Array?m+=" "+l+'="'+_(c[l]).flatten().join("-")+'"':l==="class"&&c[l]instanceof Array?m+=" "+l+'="'+_(c[l]).flatten().join(" ")+'"':m+=" "+l+'="'+haml.attrValue(l,c[l])+'"')}return m},indentText:function(e){var t,n;n="",t=0;while(t0?e&&e.id instanceof Array?e.id.unshift(n):e&&e.id?e.id=[e.id,n]:e?e.id=n:e={id:n}:t==="for"&&n.toString().length>0?e&&e["for"]instanceof Array?e["for"].unshift(n):e&&e["for"]?e["for"]=[e["for"],n]:e?e["for"]=n:e={"for":n}:t==="class"?(r=[],n instanceof Array?r=r.concat(n):r.push(n),e&&e["class"]?e["class"]=e["class"].concat(r):e?e["class"]=r:e={"class":r}):t!=="id"&&(e||(e={}),e[t]=n)),e}},o=function(){function e(e){var t,n,r,i=this;this.buffer=null,this.bufferIndex=null,this.prevToken=null,this.token=null;if(e.templateId!=null){r=document.getElementById(e.templateId);if(!r)throw"Did not find a template with ID '"+e.templateId+"'";this.buffer=r.text,this.bufferIndex=0}else e.template!=null?(this.buffer=e.template,this.bufferIndex=0):e.templateUrl!=null&&(t=function(t,n,r){throw"Failed to fetch haml template at URL "+e.templateUrl+": "+n+" "+r},n=function(e){return i.buffer=e,i.bufferIndex=0},jQuery.ajax({url:e.templateUrl,success:n,error:t,dataType:"text",async:!1,beforeSend:function(e){return e.withCredentials=!0}}))}return e.prototype.currentLineMatcher=/[^\n]*/g,e.prototype.tokenMatchers={whitespace:/[ \t]+/g,element:/%[a-zA-Z][a-zA-Z0-9]*/g,idSelector:/#[a-zA-Z_\-][a-zA-Z0-9_\-]*/g,classSelector:/\.[a-zA-Z0-9_\-]+/g,identifier:/[a-zA-Z][a-zA-Z0-9\-]*/g,quotedString:/[\'][^\'\n]*[\']/g,quotedString2:/[\"][^\"\n]*[\"]/g,comment:/\-#/g,escapeHtml:/\&=/g,unescapeHtml:/\!=/g,objectReference:/\[[a-zA-Z_@][a-zA-Z0-9_]*\]/g,doctype:/!!!/g,continueLine:/\|\s*\n/g,filter:/:\w+/g},e.prototype.matchToken=function(e){var t;e.lastIndex=this.bufferIndex,t=e.exec(this.buffer);if((t!=null?t.index:void 0)===this.bufferIndex)return t[0]},e.prototype.matchMultiCharToken=function(e,t,n){var r,i;if(!this.token){r=this.matchToken(e);if(r)return this.token=t,this.token.tokenString=(i=typeof n==="function"?n(r):void 0)!=null?i:r,this.token.matched=r,this.advanceCharsInBuffer(r.length)}},e.prototype.matchSingleCharToken=function(e,t){if(!this.token&&this.buffer.charAt(this.bufferIndex)===e)return this.token=t,this.token.tokenString=e,this.token.matched=e,this.advanceCharsInBuffer(1)},e.prototype.getNextToken=function(){var e,t,n,r,i,s,o;if(isNaN(this.bufferIndex))throw haml.HamlRuntime.templateError(this.lineNumber,this.characterNumber,this.currentLine,"An internal parser error has occurred in the HAML parser");this.prevToken=this.token,this.token=null;if(this.buffer===null||this.buffer.length===this.bufferIndex)this.token={eof:!0,token:"EOF"};else{this.initLine();if(!this.token){t=this.buffer.charCodeAt(this.bufferIndex),n=this.buffer.charCodeAt(this.bufferIndex+1);if(t===10||t===13&&n===10)this.token={eol:!0,token:"EOL"},t===13&&n===10?(this.advanceCharsInBuffer(2),this.token.matched=String.fromCharCode(t)+String.fromCharCode(n)):(this.advanceCharsInBuffer(1),this.token.matched=String.fromCharCode(t)),this.characterNumber=0,this.currentLine=this.getCurrentLine()}this.matchMultiCharToken(this.tokenMatchers.whitespace,{ws:!0,token:"WS"}),this.matchMultiCharToken(this.tokenMatchers.continueLine,{continueLine:!0,token:"CONTINUELINE"}),this.matchMultiCharToken(this.tokenMatchers.element,{element:!0,token:"ELEMENT"},function(e){return e.substring(1)}),this.matchMultiCharToken(this.tokenMatchers.idSelector,{idSelector:!0,token:"ID"},function(e){return e.substring(1)}),this.matchMultiCharToken(this.tokenMatchers.classSelector,{classSelector:!0,token:"CLASS"},function(e){return e.substring(1)}),this.matchMultiCharToken(this.tokenMatchers.identifier,{identifier:!0,token:"IDENTIFIER"}),this.matchMultiCharToken(this.tokenMatchers.doctype,{doctype:!0,token:"DOCTYPE"}),this.matchMultiCharToken(this.tokenMatchers.filter,{filter:!0,token:"FILTER"},function(e){return e.substring(1)}),this.token||(o=this.matchToken(this.tokenMatchers.quotedString),o||(o=this.matchToken(this.tokenMatchers.quotedString2)),o&&(this.token={string:!0,token:"STRING",tokenString:o.substring(1,o.length-1),matched:o},this.advanceCharsInBuffer(o.length))),this.matchMultiCharToken(this.tokenMatchers.comment,{comment:!0,token:"COMMENT"}),this.matchMultiCharToken(this.tokenMatchers.escapeHtml,{escapeHtml:!0,token:"ESCAPEHTML"}),this.matchMultiCharToken(this.tokenMatchers.unescapeHtml,{unescapeHtml:!0,token:"UNESCAPEHTML"}),this.matchMultiCharToken(this.tokenMatchers.objectReference,{objectReference:!0,token:"OBJECTREFERENCE"},function(e){return e.substring(1,e.length-1)});if(!this.token&&this.buffer&&this.buffer.charAt(this.bufferIndex)==="{"){i=this.bufferIndex+1,r=this.characterNumber,s=this.lineNumber,e=1;while(i1||this.buffer.charAt(i)!=="}"))this.buffer.charAt(i)==="{"?e++:this.buffer.charAt(i)==="}"&&e--,i++;if(i===this.buffer.length)throw this.characterNumber=r+1,this.lineNumber=s,this.parseError('Error parsing attribute hash - Did not find a terminating "}"');this.token={attributeHash:!0,token:"ATTRHASH",tokenString:this.buffer.substring(this.bufferIndex,i+1),matched:this.buffer.substring(this.bufferIndex,i+1)},this.advanceCharsInBuffer(i-this.bufferIndex+1)}this.matchSingleCharToken("(",{openBracket:!0,token:"OPENBRACKET"}),this.matchSingleCharToken(")",{closeBracket:!0,token:"CLOSEBRACKET"}),this.matchSingleCharToken("=",{equal:!0,token:"EQUAL"}),this.matchSingleCharToken("/",{slash:!0,token:"SLASH"}),this.matchSingleCharToken("!",{exclamation:!0,token:"EXCLAMATION"}),this.matchSingleCharToken("-",{minus:!0,token:"MINUS"}),this.matchSingleCharToken("&",{amp:!0,token:"AMP"}),this.matchSingleCharToken("<",{lt:!0,token:"LT"}),this.matchSingleCharToken(">",{gt:!0,token:"GT"}),this.matchSingleCharToken("~",{tilde:!0,token:"TILDE"}),this.token===null&&(this.token={unknown:!0,token:"UNKNOWN"})}return this.token},e.prototype.lookAhead=function(e){var t,n,r,i,s,o,u,a;a=null;if(e>0){i=this.token,u=this.prevToken,r=this.currentLine,o=this.lineNumber,n=this.characterNumber,t=this.bufferIndex,s=0;while(s++0)return this.buffer+=e},e.prototype.appendToOutputBuffer=function(e){if(e&&e.length>0)return this.flush(),this.outputBuffer+=e},e.prototype.flush=function(){return this.buffer&&this.buffer.length>0&&(this.outputBuffer+=this.generator.generateFlush(this.buffer)),this.buffer=""},e.prototype.output=function(){return this.outputBuffer},e.prototype.trimWhitespace=function(){var e,t;if(this.buffer.length>0){t=this.buffer.length-1;while(t>0){e=this.buffer.charAt(t);if(e===" "||e===" "||e==="\n")t--;else{if(!(t>1)||e!=="n"&&e!=="t"||this.buffer.charAt(t-1)!=="\\")break;t-=2}}if(t>0&&t0&&(r=this.replaceReservedWordsInHash(r),this.outputBuffer.appendToOutputBuffer(' hashFunction = function () { return eval("hashObject = '+r.replace(/"/g,'\\"').replace(/\n/g,"\\n")+'"); };\n')),i.length>0&&this.outputBuffer.appendToOutputBuffer(' objRefFn = function () { return eval("objRef = '+i.replace(/"/g,'\\"')+'"); };\n'),this.outputBuffer.appendToOutputBuffer(' html.push(haml.HamlRuntime.generateElementAttributes(context, "'+e+'", ["'+t.join('","')+'"], objRefFn, '+JSON.stringify(n)+", hashFunction, "+s.lineNumber+", "+s.characterNumber+', "'+this.escapeCode(s.currentLine)+'"));\n')},t.prototype.replaceReservedWordsInHash=function(e){var t,n,r,i,s;n=e,s=["class","for"];for(r=0,i=s.length;r0&&(s=e.charAt(u.index-1)),u.index>1&&(o=e.charAt(u.index-2)),s==="\\"&&o!=="\\"?(u.index!==0&&this.outputBuffer.append(this.processText(e.substring(i,u.index-1),n)),this.outputBuffer.append(this.processText(u[0]),n)):(this.outputBuffer.append(this.processText(e.substring(i,u.index)),n),this.appendEmbeddedCode(r.indentText(this.indent+1),u[1],n.escapeHTML,n.perserveWhitespace,t)),i=this.embeddedCodeBlockMatcher.lastIndex,u=this.embeddedCodeBlockMatcher.exec(e);if(i0&&(r=this.replaceReservedWordsInHash(r),this.outputBuffer.appendToOutputBuffer(" hashFunction = function () { return "+r+"; };\n")),i.length>0&&this.outputBuffer.appendToOutputBuffer(" objRefFn = function () { return "+i+"; };\n"),this.outputBuffer.appendToOutputBuffer(' html.push(haml.HamlRuntime.generateElementAttributes(context, "'+e+'", ["'+t.join('","')+'"], objRefFn, '+JSON.stringify(n)+", hashFunction, "+s.lineNumber+", "+s.characterNumber+', "'+this.escapeCode(s.currentLine)+'"));\n')},t.prototype.initOutput=function(){return this.outputBuffer.appendToOutputBuffer(" var html = [];\n var hashFunction = null, hashObject = null, objRef = null, objRefFn = null, value= null;\n with (context || {}) {\n")},t}(i),n=function(e){function t(){this.outputBuffer=new haml.Buffer(this)}return l(t,e),t.prototype.appendEmbeddedCode=function(e,t,n,r,i){var s;return this.outputBuffer.flush(),s=this.calcCodeIndent(),this.outputBuffer.appendToOutputBuffer(s+"try\n"),this.outputBuffer.appendToOutputBuffer(s+" exp = CoffeeScript.compile('"+t.replace(/'/g,"\\'").replace(/\\n/g,"\\\\n")+"', bare: true)\n"),this.outputBuffer.appendToOutputBuffer(s+" value = eval(exp)\n"),this.outputBuffer.appendToOutputBuffer(s+" value ?= ''\n"),n?this.outputBuffer.appendToOutputBuffer(s+" html.push(haml.HamlRuntime.escapeHTML(String(value)))\n"):r?this.outputBuffer.appendToOutputBuffer(s+" html.push(haml.HamlRuntime.perserveWhitespace(String(value)))\n"):this.outputBuffer.appendToOutputBuffer(s+" html.push(String(value))\n"),this.outputBuffer.appendToOutputBuffer(s+"catch e \n"),this.outputBuffer.appendToOutputBuffer(s+" throw new Error(haml.HamlRuntime.templateError("+i.lineNumber+", "+i.characterNumber+", '"+this.escapeCode(i.currentLine)+"',\n"),this.outputBuffer.appendToOutputBuffer(s+" 'Error evaluating expression - ' + e))\n")},t.prototype.initOutput=function(){return this.outputBuffer.appendToOutputBuffer("html = []\n")},t.prototype.closeAndReturnOutput=function(){return this.outputBuffer.flush(),this.outputBuffer.output()+'return html.join("")\n'},t.prototype.appendCodeLine=function(e,t){return this.outputBuffer.flush(),this.outputBuffer.appendToOutputBuffer(this.calcCodeIndent()),this.outputBuffer.appendToOutputBuffer((_.str||_).trim(e)),this.outputBuffer.appendToOutputBuffer(t),this.prevCodeIndent=this.indent},t.prototype.lineMatchesStartFunctionBlock=function(e){return e.match(/\) [\-=]>\s*$/)},t.prototype.lineMatchesStartBlock=function(e){return!0},t.prototype.closeOffCodeBlock=function(e){return this.outputBuffer.flush()},t.prototype.closeOffFunctionBlock=function(e){return this.outputBuffer.flush()},t.prototype.generateCodeForDynamicAttributes=function(e,t,n,r,i,s){var o;return this.outputBuffer.flush(),o=this.calcCodeIndent(),r.length>0&&(r=this.replaceReservedWordsInHash(r),this.outputBuffer.appendToOutputBuffer(o+"hashFunction = () -> s = CoffeeScript.compile('"+r.replace(/'/g,"\\'").replace(/\n/g,"\\n")+"', bare: true); eval 'hashObject = ' + s\n")),i.length>0&&this.outputBuffer.appendToOutputBuffer(o+"objRefFn = () -> s = CoffeeScript.compile('"+i.replace(/'/g,"\\'")+"', bare: true); eval 'objRef = ' + s\n"),this.outputBuffer.appendToOutputBuffer(o+"html.push(haml.HamlRuntime.generateElementAttributes(this, '"+e+"', ['"+t.join("','")+"'], objRefFn ? null, "+JSON.stringify(n)+", hashFunction ? null, "+s.lineNumber+", "+s.characterNumber+", '"+this.escapeCode(s.currentLine)+"'))\n")},t.prototype.replaceReservedWordsInHash=function(e){var t,n,r,i,s;n=e,s=["class","for"];for(r=0,i=s.length;r0&&(r=e.charAt(s.index-1)),s.index>1&&(i=e.charAt(s.index-2)),r==="\\"&&i!=="\\"?(s.index!==0&&(n+=this._escapeText(e.substring(t,s.index-1))),n+=this._escapeText("\\"+s[0])):(n+=this._escapeText(e.substring(t,s.index)),n+=s[0]),t=this.embeddedCodeBlockMatcher.lastIndex,s=this.embeddedCodeBlockMatcher.exec(e);return t=i;t=0<=i?++n:--n)if(((s=this.elementStack[t])!=null?s.block:void 0)||((o=this.elementStack[t])!=null?o.fnBlock:void 0))e+=1;return r.indentText(e)},t.prototype.appendTextContents=function(e,t,n,r){var i,s;if(t&&e.match(/#{[^}]*}/)){this.outputBuffer.flush(),i=s="";if(r!=null?r.escapeHTML:void 0)i="haml.HamlRuntime.escapeHTML(",s=")";else if(r!=null?r.perserveWhitespace:void 0)i="haml.HamlRuntime.perserveWhitespace(",s=")";return this.outputBuffer.appendToOutputBuffer(this.calcCodeIndent()+"html.push("+i+'"'+this.escapeCode(e)+'"'+s+")\n")}if(r!=null?r.escapeHTML:void 0)e=haml.HamlRuntime.escapeHTML(e);if(r!=null?r.perserveWhitespace:void 0)e=haml.HamlRuntime.perserveWhitespace(e);return this.outputBuffer.append(e)},t}(t),u={plain:function(e,t,n,r){var i,s,o;for(s=0,o=e.length;s\n'),t.outputBuffer.append(n+"//\n"),t.outputBuffer.append(n+"\n")},css:function(e,t,n,r){var i,s,o;t.outputBuffer.append(n+'\n")},cdata:function(e,t,n,r){var i,s,o;t.outputBuffer.append(n+"\n")},preserve:function(e,t,n,r){return t.appendTextContents(e.join("\n")+"\n",!0,r,{perserveWhitespace:!0})},escape:function(e,t,n,r){var i,s,o;for(s=0,o=e.length;s0){s=i.split(/\s+/);switch(s[0]){case"XML":s.length>1?n.outputBuffer.append(""):n.outputBuffer.append("");break;case"Strict":n.outputBuffer.append('');break;case"Frameset":n.outputBuffer.append('');break;case"5":n.outputBuffer.append("");break;case"1.1":n.outputBuffer.append('');break;case"Basic":n.outputBuffer.append('');break;case"Mobile":n.outputBuffer.append('');break;case"RDFa":n.outputBuffer.append('')}}else n.outputBuffer.append('');return n.outputBuffer.append(this._newline(e)),e.getNextToken()}},_filter:function(e,t,n){var r,i,s,o;if(e.token.filter){r=e.token.tokenString;if(!haml.filters[r])throw e.parseError("Filter '"+r+"' not registered. Filter functions need to be added to 'haml.filters'.");e.skipToEOLorEOF(),e.getNextToken(),s=haml._whitespace(e),i=[];while(!e.token.eof&&s>t)o=e.skipToEOLorEOF(),i.push(haml.HamlRuntime.indentText(s-t-1)+o),e.getNextToken(),s=haml._whitespace(e);return haml.filters[r](i,n,haml.HamlRuntime.indentText(t),e.currentParsePoint()),e.pushBackToken()}},_commentLine:function(e,t,n,i){var s,o;if(e.token.comment){e.skipToEOLorEOF(),e.getNextToken(),o=this._whitespace(e);while(!e.token.eof&&o>t)e.skipToEOLorEOF(),e.getNextToken(),o=this._whitespace(e);if(o>0)return e.pushBackToken()}else if(e.token.slash)return haml._closeElements(t,n,e,i),i.outputBuffer.append(r.indentText(t)),i.outputBuffer.append(""+t[e].eol):t[e].htmlConditionalComment?i.outputBuffer.append(r.indentText(e)+""+t[e].eol):t[e].block?i.closeOffCodeBlock(n):t[e].fnBlock?i.closeOffFunctionBlock(n):(s=!t[e].tagOptions||t[e].tagOptions.innerWhitespace,s?i.outputBuffer.append(r.indentText(e)):i.outputBuffer.trimWhitespace(),i.outputBuffer.append(""),o=!t[e].tagOptions|| +t[e].tagOptions.outerWhitespace,haml._parentInnerWhitespace(t,e)&&o&&i.outputBuffer.append("\n")),t[e]=null,i.mark()},_closeElements:function(e,t,n,r){var i,s;i=t.length-1,s=[];while(i>=e)s.push(this._closeElement(i--,t,n,r));return s},_openElement:function(e,t,n,i,s,o,u,a,f,l,c){var h,p,d;h=n.length===0?"div":n,p=this._parentInnerWhitespace(f,t),d=!l||l.outerWhitespace,d||c.outputBuffer.trimWhitespace(),t>0&&p&&d&&c.outputBuffer.append(r.indentText(t)),c.outputBuffer.append("<"+h),a.length>0||o.length>0?c.generateCodeForDynamicAttributes(i,s,u,a,o,e):c.outputBuffer.append(r.generateElementAttributes(null,i,s,null,u,null,e.lineNumber,e.characterNumber,e.currentLine));if(l.selfClosingTag){c.outputBuffer.append("/>");if(l.outerWhitespace)return c.outputBuffer.append("\n")}else{c.outputBuffer.append(">"),f[t]={tag:h,tagOptions:l};if(l.innerWhitespace)return c.outputBuffer.append("\n")}},_isSelfClosingTag:function(e){return e==="meta"||e==="img"||e==="link"||e==="script"||e==="br"||e==="hr"},_tagHasContents:function(e,t){var n;return t.isEolOrEof()?(n=t.lookAhead(1),n.ws&&n.tokenString.length/2>e):!0},_parentInnerWhitespace:function(e,t){return t===0||!e[t-1]||!e[t-1].tagOptions||e[t-1].tagOptions.innerWhitespace},_lineHasElement:function(e,t,n){return e.length>0||t.length>0||n.length>0},hasValue:function(e){return e!=null&&e!==!1},attrValue:function(e,t){return e==="selected"||e==="checked"||e==="disabled"?e:t},_whitespace:function(e){var t,n,r;n=0;if(e.token.ws){t=0,r=e.token.tokenString;while(t