Created
June 26, 2013 18:33
-
-
Save dhcole/5870069 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<title></title> | |
<meta charset="utf-8"> | |
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script> | |
<script src="liquid.js"></script> | |
</head> | |
<body> | |
<div id="content"></div> | |
<script> | |
var data = {"site":{"baseurl":"/"},"post":{"published":true,"layout":"blog","category":"blog","title":"Using Leaflet plugins with MapBox.js: A Showcase","image":"http://farm6.staticflickr.com/5452/9046572530_f9baa455f4_o.png","permalink":"/blog/leaflet-plugins-with-mapbox-js","tags":["John Firebaugh"]},"page":{"published":true,"layout":"blog","category":"blog","title":"Using Leaflet plugins with MapBox.js: A Showcase","image":"http://farm6.staticflickr.com/5452/9046572530_f9baa455f4_o.png","permalink":"/blog/leaflet-plugins-with-mapbox-js","tags":["John Firebaugh"]},"content":"<p>One of the reasons we built <a href=\"http://www.mapbox.com/blog/mapbox-js-with-leaflet/\">MapBox.js\nv1</a> on top of Leaflet was\nits robust plugin ecosystem. The <a href=\"http://leafletjs.com/plugins.html\">Leaflet plugins\npage</a> lists dozens of plugins, and more are\nbeing added every week. In fact, MapBox.js itself is structured as a Leaflet\nplugin, unlocking a world of interesting possibilities for map interaction and\nenhancement. Here are a few of our favorites.</p>\n<p><img src=\"http://farm6.staticflickr.com/5452/9046572530_f9baa455f4_o.png\" alt=\"\"></p>"}; | |
$(function() { | |
$('#content').html(Liquid.parse($('#template').html()).render(data)); | |
}); | |
</script> | |
<script type="text/liquid" id="template"> | |
{% if page.mapid %} | |
<div id="blog-map" class=""></div> | |
{% elsif page.splash == "none" or page.splash == null %} | |
{% else %} | |
<div class='clearfix splash pad3 {{page.splashclass}}' style='background-image:url({{site.baseurl}}{{page.splash}});background-repeat:no-repeat;'></div> | |
{% endif %} | |
{% unless page.tags contains "batman" %} | |
<!-- Standard Posts --> | |
<div class='clearfix contain single-post'> | |
<div class='cell9 pad3 prose-container'> | |
{% if page.notice %} | |
<div class='notice pad2'> | |
<h3><span class='icon alert'></span>{{page.notice.title}}</h3> | |
{{page.notice.message | markdownify}} | |
</div> | |
{% endif %} | |
<h1>{{page.title}}</h1> | |
<div class="blog-info"> | |
<span class="blog-date">{{page.date | date:"%B %d %Y"}}</span> | |
</div> | |
<div class='prose'> | |
{{content}} | |
{% if page.tags contains "action" %} | |
<div class='blog-action'> | |
<p>Get started with MapBox now.</p> | |
<a class='button big' href='https://tiles.mapbox.com/signup'>signup<span class='icon reverse next'></span></a> | |
</div> | |
{% endif %} | |
</div> | |
</div> | |
</div> | |
{% else %} | |
<!-- Batman posts --> | |
<div class='clearfix batman single-post'> | |
<div class="contain clearfix"> | |
<div class='cell10 margin1'> | |
<div class="blog-info pad3w centered"> | |
<span class="blog-date">{{page.date | date:"%B %d %Y"}}</span> | |
{% if author.hidden %} | |
<span class="blog-author">By <a href='https://twitter.com/{{author.twitter}}'>{{author.title}}</a></span> | |
{% else %} | |
<span class="blog-author">By <a href='{{site.baseurl}}/about/team/#{{author.title|downcase|replace:' ','-'}}'>{{author.title}}</a></span> | |
{% endif %} | |
</div> | |
<div class='prose'> | |
{{content}} | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- End if/else batman --> | |
{% endunless %} | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var Liquid = { | |
author: 'M@ McCray <darthapo@gmail.com>', | |
version: '1.2.1', | |
readTemplateFile: function(path) { | |
throw ("This liquid context does not allow includes."); | |
}, | |
registerFilters: function(filters) { | |
Liquid.Template.registerFilter(filters); | |
}, | |
parse: function(src) { | |
return Liquid.Template.parse(src); | |
} | |
}; | |
if (!Array.prototype.indexOf) { | |
Array.prototype.indexOf = function(obj) { | |
for (var i=0; i<this.length; i++) { | |
if (this[i] == obj) return i; | |
} | |
return -1; | |
}; | |
} | |
if (!Array.prototype.clear) { | |
Array.prototype.clear = function() { | |
this.length = 0; | |
}; | |
} | |
if (!Array.prototype.map) { | |
Array.prototype.map = function(fun /*, thisp*/) { | |
var len = this.length; | |
if (typeof fun != "function") | |
throw 'Array.map requires first argument to be a function'; | |
var res = new Array(len); | |
var thisp = arguments[1]; | |
for (var i = 0; i < len; i++) { | |
if (i in this) | |
res[i] = fun.call(thisp, this[i], i, this); | |
} | |
return res; | |
}; | |
} | |
if (!Array.prototype.first) { | |
Array.prototype.first = function() { | |
return this[0]; | |
}; | |
} | |
if (!Array.prototype.last) { | |
Array.prototype.last = function() { | |
return this[this.length - 1]; | |
}; | |
} | |
if (!Array.prototype.flatten) { | |
Array.prototype.flatten = function() { | |
var len = this.length; | |
var arr = []; | |
for (var i = 0; i < len; i++) { | |
if (this[i] instanceof Array) { | |
arr = arr.concat(this[i]); | |
} else { | |
arr.push(this[i]); | |
} | |
} | |
return arr; | |
}; | |
} | |
if (!Array.prototype.each) { | |
Array.prototype.each = function(fun /*, thisp*/) { | |
var len = this.length; | |
if (typeof fun != "function") | |
throw 'Array.each requires first argument to be a function'; | |
var thisp = arguments[1]; | |
for (var i = 0; i < len; i++) { | |
if (i in this) | |
fun.call(thisp, this[i], i, this); | |
} | |
return null; | |
}; | |
} | |
if (!Array.prototype.include) { | |
Array.prototype.include = function(arg) { | |
var len = this.length; | |
return this.indexOf(arg) >= 0; | |
for (var i = 0; i < len; i++) { | |
if (arg == this[i]) return true; | |
} | |
return false; | |
}; | |
} | |
if (!String.prototype.capitalize) { | |
String.prototype.capitalize = function() { | |
return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); | |
}; | |
} | |
if (!String.prototype.strip) { | |
String.prototype.strip = function() { | |
return this.replace(/^\s+/, '').replace(/\s+$/, ''); | |
}; | |
} | |
Liquid.extensions = {}; | |
Liquid.extensions.object = {}; | |
Liquid.extensions.object.update = function(newObj) { | |
for (var p in newObj) { | |
this[p] = newObj[p]; | |
} | |
return this; | |
}; | |
Liquid.extensions.object.hasKey = function(arg) { | |
return !!this[arg]; | |
}; | |
Liquid.extensions.object.hasValue = function(arg) { | |
for (var p in this) { | |
if (this[p] == arg) return true; | |
} | |
return false; | |
}; | |
/* Simple JavaScript Inheritance | |
* By John Resig http://ejohn.org/ | |
* MIT Licensed. | |
*/ | |
(function(){ | |
var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; | |
this.Class = function(){}; | |
Class.extend = function(prop) { | |
var _super = this.prototype; | |
initializing = true; | |
var prototype = new this(); | |
initializing = false; | |
for (var name in prop) { | |
prototype[name] = typeof prop[name] == "function" && | |
typeof _super[name] == "function" && fnTest.test(prop[name]) ? | |
(function(name, fn){ | |
return function() { | |
var tmp = this._super; | |
this._super = _super[name]; | |
var ret = fn.apply(this, arguments); | |
this._super = tmp; | |
return ret; | |
}; | |
})(name, prop[name]) : | |
prop[name]; | |
} | |
function Class() { | |
if ( !initializing && this.init ) | |
this.init.apply(this, arguments); | |
} | |
Class.prototype = prototype; | |
Class.prototype.constructor = Class; | |
Class.extend = arguments.callee; | |
return Class; | |
}; | |
})(); | |
Liquid.Tag = Class.extend({ | |
init: function(tagName, markup, tokens) { | |
this.tagName = tagName; | |
this.markup = markup; | |
this.nodelist = this.nodelist || []; | |
this.parse(tokens); | |
}, | |
parse: function(tokens) { | |
}, | |
render: function(context) { | |
return ''; | |
} | |
}); | |
Liquid.Block = Liquid.Tag.extend({ | |
init: function(tagName, markup, tokens){ | |
this.blockName = tagName; | |
this.blockDelimiter = "end"+ this.blockName; | |
this._super(tagName, markup, tokens); | |
}, | |
parse: function(tokens) { | |
if (!this.nodelist) this.nodelist = []; | |
this.nodelist.clear(); | |
var token = tokens.shift(); | |
tokens.push(''); // To ensure we don't lose the last token passed in... | |
while(tokens.length) { | |
if( /^\{\%/.test(token) ) { // It's a tag... | |
var tagParts = token.match(/^\{\%\s*(\w+)\s*(.*)?\%\}$/); | |
if(tagParts) { | |
if( this.blockDelimiter == tagParts[1] ) { | |
this.endTag(); | |
return; | |
} | |
if( tagParts[1] in Liquid.Template.tags ) { | |
this.nodelist.push( new Liquid.Template.tags[tagParts[1]]( tagParts[1], tagParts[2], tokens ) ); | |
} else { | |
this.unknownTag( tagParts[1], tagParts[2], tokens ); | |
} | |
} else { | |
throw ( "Tag '"+ token +"' was not properly terminated with: %}"); | |
} | |
} else if(/^\{\{/.test(token)) { // It's a variable... | |
this.nodelist.push( this.createVariable(token) ); | |
} else { //if(token != '') { | |
this.nodelist.push( token ); | |
} // Ignores tokens that are empty | |
token = tokens.shift(); // Assign the next token to loop again... | |
} | |
this.assertMissingDelimitation(); | |
}, | |
endTag: function() {}, | |
unknownTag: function(tag, params, tokens) { | |
switch(tag) { | |
case 'else': throw (this.blockName +" tag does not expect else tag"); break; | |
case 'end': throw ("'end' is not a valid delimiter for "+ this.blockName +" tags. use "+ this.blockDelimiter); break; | |
default: throw ("Unknown tag: "+ tag); | |
} | |
}, | |
createVariable: function(token) { | |
var match = token.match(/^\{\{(.*)\}\}$/); | |
if(match) { return new Liquid.Variable(match[1]); } | |
else { throw ("Variable '"+ token +"' was not properly terminated with: }}"); } | |
}, | |
render: function(context) { | |
return this.renderAll(this.nodelist, context); | |
}, | |
renderAll: function(list, context) { | |
return (list || []).map(function(token, i){ | |
var output = ''; | |
try { // hmmm... feels a little heavy | |
output = ( token['render'] ) ? token.render(context) : token; | |
} catch(e) { | |
output = context.handleError(e); | |
} | |
return output; | |
}); | |
}, | |
assertMissingDelimitation: function(){ | |
throw (this.blockName +" tag was never closed"); | |
} | |
}); | |
Liquid.Document = Liquid.Block.extend({ | |
init: function(tokens){ | |
this.blockDelimiter = []; // [], really? | |
this.parse(tokens); | |
}, | |
assertMissingDelimitation: function() { | |
} | |
}); | |
Liquid.Strainer = Class.extend({ | |
init: function(context) { | |
this.context = context; | |
}, | |
respondTo: function(methodName) { | |
methodName = methodName.toString(); | |
if (methodName.match(/^__/)) return false; | |
if (Liquid.Strainer.requiredMethods.include(methodName)) return false; | |
return (methodName in this); | |
} | |
}); | |
Liquid.Strainer.filters = {}; | |
Liquid.Strainer.globalFilter = function(filters) { | |
for (var f in filters) { | |
Liquid.Strainer.filters[f] = filters[f]; | |
} | |
} | |
Liquid.Strainer.requiredMethods = ['respondTo', 'context']; | |
Liquid.Strainer.create = function(context) { | |
var strainer = new Liquid.Strainer(context); | |
for (var f in Liquid.Strainer.filters) { | |
strainer[f] = Liquid.Strainer.filters[f]; | |
} | |
return strainer; | |
} | |
Liquid.Context = Class.extend({ | |
init: function(assigns, registers, rethrowErrors) { | |
this.scopes = [ assigns ? assigns : {} ]; | |
this.registers = registers ? registers : {}; | |
this.errors = []; | |
this.rethrowErrors = rethrowErrors; | |
this.strainer = Liquid.Strainer.create(this); | |
}, | |
get: function(varname) { | |
return this.resolve(varname); | |
}, | |
set: function(varname, value) { | |
this.scopes[0][varname] = value; | |
}, | |
hasKey: function(key) { | |
return (this.resolve(key)) ? true : false; | |
}, | |
push: function() { | |
var scpObj = {}; | |
this.scopes.unshift(scpObj); | |
return scpObj // Is this right? | |
}, | |
merge: function(newScope) { | |
return Liquid.extensions.object.update.call(this.scopes[0], newScope); | |
}, | |
pop: function() { | |
if(this.scopes.length == 1){ throw "Context stack error"; } | |
return this.scopes.shift(); | |
}, | |
stack: function(lambda, bind) { | |
var result = null; | |
this.push(); | |
try { | |
result = lambda.apply(bind ? bind : this.strainer); | |
} finally { | |
this.pop(); | |
} | |
return result; | |
}, | |
invoke: function(method, args) { | |
if( this.strainer.respondTo(method) ) { | |
var result = this.strainer[method].apply(this.strainer, args); | |
return result; | |
} else { | |
return (args.length == 0) ? null : args[0]; // was: $pick | |
} | |
}, | |
resolve: function(key) { | |
switch(key) { | |
case null: | |
case 'nil': | |
case 'null': | |
case '': | |
return null; | |
case 'true': | |
return true; | |
case 'false': | |
return false; | |
case 'blank': | |
case 'empty': | |
return ''; | |
default: | |
if((/^'(.*)'$/).test(key)) // Single quoted strings | |
{ return key.replace(/^'(.*)'$/, '$1'); } | |
else if((/^"(.*)"$/).test(key)) // Double quoted strings | |
{ return key.replace(/^"(.*)"$/, '$1'); } | |
else if((/^(\d+)$/).test(key)) // Integer... | |
{ return parseInt( key.replace(/^(\d+)$/ , '$1') ); } | |
else if((/^(\d[\d\.]+)$/).test(key)) // Float... | |
{ return parseFloat( key.replace(/^(\d[\d\.]+)$/, '$1') ); } | |
else if((/^\((\S+)\.\.(\S+)\)$/).test(key)) {// Ranges | |
var range = key.match(/^\((\S+)\.\.(\S+)\)$/), | |
left = parseInt(range[1]), | |
right = parseInt(range[2]), | |
arr = []; | |
if (isNaN(left) || isNaN(right)) { | |
left = range[1].charCodeAt(0); | |
right = range[2].charCodeAt(0); | |
var limit = right-left+1; | |
for (var i=0; i<limit; i++) arr.push(String.fromCharCode(i+left)); | |
} else { // okay to make array | |
var limit = right-left+1; | |
for (var i=0; i<limit; i++) arr.push(i+left); | |
} | |
return arr; | |
} else { | |
var result = this.variable(key); | |
return result; | |
} | |
} | |
}, | |
findVariable: function(key) { | |
for (var i=0; i < this.scopes.length; i++) { | |
var scope = this.scopes[i]; | |
if( scope && typeof(scope[key]) !== 'undefined' ) { | |
var variable = scope[key]; | |
if(typeof(variable) == 'function'){ | |
variable = variable.apply(this); | |
scope[key] = variable; | |
} | |
if(variable && typeof(variable) == 'object' && ('toLiquid' in variable)) { | |
variable = variable.toLiquid(); | |
} | |
if(variable && typeof(variable) == 'object' && ('setContext' in variable)){ | |
variable.setContext(self); | |
} | |
return variable; | |
} | |
}; | |
return null; | |
}, | |
variable: function(markup) { | |
if(typeof markup != 'string') { | |
return null; | |
} | |
var parts = markup.match( /\[[^\]]+\]|(?:[\w\-]\??)+/g ), | |
firstPart = parts.shift(), | |
squareMatch = firstPart.match(/^\[(.*)\]$/); | |
if(squareMatch) | |
{ firstPart = this.resolve( squareMatch[1] ); } | |
var object = this.findVariable(firstPart), | |
self = this; | |
if(object) { | |
parts.each(function(part){ | |
var squareMatch = part.match(/^\[(.*)\]$/); | |
if(squareMatch) { | |
var part = self.resolve( squareMatch[1] ); | |
if( typeof(object[part]) == 'function'){ object[part] = object[part].apply(this); }// Array? | |
object = object[part]; | |
if(typeof(object) == 'object' && ('toLiquid' in object)){ object = object.toLiquid(); } | |
} else { | |
if( (typeof(object) == 'object' || typeof(object) == 'hash') && (part in object)) { | |
var res = object[part]; | |
if( typeof(res) == 'function'){ res = object[part] = res.apply(self) ; } | |
if( typeof(res) == 'object' && ('toLiquid' in res)){ object = res.toLiquid(); } | |
else { object = res; } | |
} | |
else if( (/^\d+$/).test(part) ) { | |
var pos = parseInt(part); | |
if( typeof(object[pos]) == 'function') { object[pos] = object[pos].apply(self); } | |
if(typeof(object[pos]) == 'object' && typeof(object[pos]) == 'object' && ('toLiquid' in object[pos])) { object = object[pos].toLiquid(); } | |
else { object = object[pos]; } | |
} | |
else if( object && typeof(object[part]) == 'function' && ['length', 'size', 'first', 'last'].include(part) ) { | |
object = object[part].apply(part); | |
if('toLiquid' in object){ object = object.toLiquid(); } | |
} | |
else { | |
return object = null; | |
} | |
if(typeof(object) == 'object' && ('setContext' in object)){ object.setContext(self); } | |
} | |
}); | |
} | |
return object; | |
}, | |
addFilters: function(filters) { | |
filters = filters.flatten(); | |
filters.each(function(f){ | |
if(typeof(f) != 'object'){ throw ("Expected object but got: "+ typeof(f)) } | |
this.strainer.addMethods(f); | |
}); | |
}, | |
handleError: function(err) { | |
this.errors.push(err); | |
if(this.rethrowErrors){ throw err; } | |
return "Liquid error: " + (err.message ? err.message : (err.description ? err.description : err)); | |
} | |
}); | |
Liquid.Template = Class.extend({ | |
init: function() { | |
this.root = null; | |
this.registers = {}; | |
this.assigns = {}; | |
this.errors = []; | |
this.rethrowErrors = false; | |
}, | |
parse: function(src) { | |
this.root = new Liquid.Document( Liquid.Template.tokenize(src) ); | |
return this; | |
}, | |
render: function() { | |
if(!this.root){ return ''; } | |
var args = { | |
ctx: arguments[0], | |
filters: arguments[1], | |
registers: arguments[2] | |
} | |
var context = null; | |
if(args.ctx instanceof Liquid.Context ) { | |
context = args.ctx; | |
this.assigns = context.assigns; | |
this.registers = context.registers; | |
} else { | |
if(args.ctx){ | |
Liquid.extensions.object.update.call(this.assigns, args.ctx); | |
} | |
if(args.registers){ | |
Liquid.extensions.object.update.call(this.registers, args.registers); | |
} | |
context = new Liquid.Context(this.assigns, this.registers, this.rethrowErrors) | |
} | |
if(args.filters){ context.addFilters(arg.filters); } | |
try { | |
return this.root.render(context).join(''); | |
} finally { | |
this.errors = context.errors; | |
} | |
}, | |
renderWithErrors: function() { | |
var savedRethrowErrors = this.rethrowErrors; | |
this.rethrowErrors = true; | |
var res = this.render.apply(this, arguments); | |
this.rethrowErrors = savedRethrowErrors; | |
return res; | |
} | |
}); | |
Liquid.Template.tags = {}; | |
Liquid.Template.registerTag = function(name, klass) { | |
Liquid.Template.tags[ name ] = klass; | |
} | |
Liquid.Template.registerFilter = function(filters) { | |
Liquid.Strainer.globalFilter(filters) | |
} | |
Liquid.Template.tokenize = function(src) { | |
var tokens = src.split( /(\{\%.*?\%\}|\{\{.*?\}\}?)/ ); | |
if(tokens[0] == ''){ tokens.shift(); } | |
return tokens; | |
} | |
Liquid.Template.parse = function(src) { | |
return (new Liquid.Template()).parse(src); | |
} | |
Liquid.Variable = Class.extend({ | |
init: function(markup) { | |
this.markup = markup; | |
this.name = null; | |
this.filters = []; | |
var self = this; | |
var match = markup.match(/\s*("[^"]+"|'[^']+'|[^\s,|]+)/); | |
if( match ) { | |
this.name = match[1]; | |
var filterMatches = markup.match(/\|\s*(.*)/); | |
if(filterMatches) { | |
var filters = filterMatches[1].split(/\|/); | |
filters.each(function(f){ | |
var matches = f.match(/\s*(\w+)/); | |
if(matches) { | |
var filterName = matches[1]; | |
var filterArgs = []; | |
(f.match(/(?:[:|,]\s*)("[^"]+"|'[^']+'|[^\s,|]+)/g) || []).flatten().each(function(arg){ | |
var cleanupMatch = arg.match(/^[\s|:|,]*(.*?)[\s]*$/); | |
if(cleanupMatch) | |
{ filterArgs.push( cleanupMatch[1] );} | |
}); | |
self.filters.push( [filterName, filterArgs] ); | |
} | |
}); | |
} | |
} | |
}, | |
render: function(context) { | |
if(this.name == null){ return ''; } | |
var output = context.get(this.name); | |
this.filters.each(function(filter) { | |
var filterName = filter[0], | |
filterArgs = (filter[1] || []).map(function(arg){ | |
return context.get(arg); | |
}); | |
filterArgs.unshift(output); // Push in input value into the first argument spot... | |
output = context.invoke(filterName, filterArgs); | |
}); | |
return output; | |
} | |
}); | |
Liquid.Condition = Class.extend({ | |
init: function(left, operator, right) { | |
this.left = left; | |
this.operator = operator; | |
this.right = right; | |
this.childRelation = null; | |
this.childCondition = null; | |
this.attachment = null; | |
}, | |
evaluate: function(context) { | |
context = context || new Liquid.Context(); | |
var result = this.interpretCondition(this.left, this.right, this.operator, context); | |
switch(this.childRelation) { | |
case 'or': | |
return (result || this.childCondition.evaluate(context)); | |
case 'and': | |
return (result && this.childCondition.evaluate(context)); | |
default: | |
return result; | |
} | |
}, | |
or: function(condition) { | |
this.childRelation = 'or'; | |
this.childCondition = condition; | |
}, | |
and: function(condition) { | |
this.childRelation = 'and'; | |
this.childCondition = condition; | |
}, | |
attach: function(attachment) { | |
this.attachment = attachment; | |
return this.attachment; | |
}, | |
isElse: false, | |
interpretCondition: function(left, right, op, context) { | |
if(!op) | |
{ return context.get(left); } | |
left = context.get(left); | |
right = context.get(right); | |
op = Liquid.Condition.operators[op]; | |
if(!op) | |
{ throw ("Unknown operator "+ op); } | |
var results = op(left, right); | |
return results; | |
}, | |
toString: function() { | |
return "<Condition "+ this.left +" "+ this.operator +" "+ this.right +">"; | |
} | |
}); | |
Liquid.Condition.operators = { | |
'==': function(l,r) { return (l == r); }, | |
'=': function(l,r) { return (l == r); }, | |
'!=': function(l,r) { return (l != r); }, | |
'<>': function(l,r) { return (l != r); }, | |
'<': function(l,r) { return (l < r); }, | |
'>': function(l,r) { return (l > r); }, | |
'<=': function(l,r) { return (l <= r); }, | |
'>=': function(l,r) { return (l >= r); }, | |
'contains': function(l,r) { return l.include(r); }, | |
'hasKey': function(l,r) { return Liquid.extensions.object.hasKey.call(l, r); }, | |
'hasValue': function(l,r) { return Liquid.extensions.object.hasValue.call(l, r); } | |
} | |
Liquid.ElseCondition = Liquid.Condition.extend({ | |
isElse: true, | |
evaluate: function(context) { | |
return true; | |
}, | |
toString: function() { | |
return "<ElseCondition>"; | |
} | |
}); | |
Liquid.Drop = Class.extend({ | |
setContext: function(context) { | |
this.context = context; | |
}, | |
beforeMethod: function(method) { | |
}, | |
invokeDrop: function(method) { | |
var results = this.beforeMethod(); | |
if( !results && (method in this) ) | |
{ results = this[method].apply(this); } | |
return results; | |
}, | |
hasKey: function(name) { | |
return true; | |
} | |
}); | |
var hackObjectEach = function(fun /*, thisp*/) { | |
if (typeof fun != "function") | |
throw 'Object.each requires first argument to be a function'; | |
var i = 0; | |
var thisp = arguments[1]; | |
for (var p in this) { | |
var value = this[p], pair = [p, value]; | |
pair.key = p; | |
pair.value = value; | |
fun.call(thisp, pair, i, this); | |
i++; | |
} | |
return null; | |
}; | |
Liquid.Template.registerTag( 'assign', Liquid.Tag.extend({ | |
tagSyntax: /((?:\(?[\w\-\.\[\]]\)?)+)\s*=\s*((?:"[^"]+"|'[^']+'|[^\s,|]+)+)/, | |
init: function(tagName, markup, tokens) { | |
var parts = markup.match(this.tagSyntax) | |
if( parts ) { | |
this.to = parts[1]; | |
this.from = parts[2]; | |
} else { | |
throw ("Syntax error in 'assign' - Valid syntax: assign [var] = [source]"); | |
} | |
this._super(tagName, markup, tokens) | |
}, | |
render: function(context) { | |
context.scopes.last()[this.to.toString()] = context.get(this.from); | |
return ''; | |
} | |
})); | |
Liquid.Template.registerTag( 'cache', Liquid.Block.extend({ | |
tagSyntax: /(\w+)/, | |
init: function(tagName, markup, tokens) { | |
var parts = markup.match(this.tagSyntax) | |
if( parts ) { | |
this.to = parts[1]; | |
} else { | |
throw ("Syntax error in 'cache' - Valid syntax: cache [var]"); | |
} | |
this._super(tagName, markup, tokens); | |
}, | |
render: function(context) { | |
var output = this._super(context); | |
context.scopes.last()[this.to] = [output].flatten().join(''); | |
return ''; | |
} | |
})); | |
Liquid.Template.registerTag( 'capture', Liquid.Block.extend({ | |
tagSyntax: /(\w+)/, | |
init: function(tagName, markup, tokens) { | |
var parts = markup.match(this.tagSyntax) | |
if( parts ) { | |
this.to = parts[1]; | |
} else { | |
throw ("Syntax error in 'capture' - Valid syntax: capture [var]"); | |
} | |
this._super(tagName, markup, tokens); | |
}, | |
render: function(context) { | |
var output = this._super(context); | |
context.set( this.to, [output].flatten().join('') ); | |
return ''; | |
} | |
})); | |
Liquid.Template.registerTag( 'case', Liquid.Block.extend({ | |
tagSyntax : /("[^"]+"|'[^']+'|[^\s,|]+)/, | |
tagWhenSyntax : /("[^"]+"|'[^']+'|[^\s,|]+)(?:(?:\s+or\s+|\s*\,\s*)("[^"]+"|'[^']+'|[^\s,|]+.*))?/, | |
init: function(tagName, markup, tokens) { | |
this.blocks = []; | |
this.nodelist = []; | |
var parts = markup.match(this.tagSyntax) | |
if( parts ) { | |
this.left = parts[1]; | |
} else { | |
throw ("Syntax error in 'case' - Valid syntax: case [condition]"); | |
} | |
this._super(tagName, markup, tokens); | |
}, | |
unknownTag: function(tag, markup, tokens) { | |
switch(tag) { | |
case 'when': | |
this.recordWhenCondition(markup); | |
break; | |
case 'else': | |
this.recordElseCondition(markup); | |
break; | |
default: | |
this._super(tag, markup, tokens); | |
} | |
}, | |
render: function(context) { | |
var self = this, | |
output = [], | |
execElseBlock = true; | |
context.stack(function(){ | |
for (var i=0; i < self.blocks.length; i++) { | |
var block = self.blocks[i]; | |
if( block.isElse ) { | |
if(execElseBlock == true){ output = [output, self.renderAll(block.attachment, context)].flatten(); } | |
return output; | |
} else if( block.evaluate(context) ) { | |
execElseBlock = false; | |
output = [output, self.renderAll(block.attachment, context)].flatten(); | |
} | |
}; | |
}); | |
return output; | |
}, | |
recordWhenCondition: function(markup) { | |
while(markup) { | |
var parts = markup.match(this.tagWhenSyntax); | |
if(!parts) { | |
throw ("Syntax error in tag 'case' - Valid when condition: {% when [condition] [or condition2...] %} "); | |
} | |
markup = parts[2]; | |
var block = new Liquid.Condition(this.left, '==', parts[1]); | |
this.blocks.push( block ); | |
this.nodelist = block.attach([]); | |
} | |
}, | |
recordElseCondition: function(markup) { | |
if( (markup || '').strip() != '') { | |
throw ("Syntax error in tag 'case' - Valid else condition: {% else %} (no parameters) ") | |
} | |
var block = new Liquid.ElseCondition(); | |
this.blocks.push(block); | |
this.nodelist = block.attach([]); | |
} | |
})); | |
Liquid.Template.registerTag( 'comment', Liquid.Block.extend({ | |
render: function(context) { | |
return ''; | |
} | |
})); | |
Liquid.Template.registerTag( 'cycle', Liquid.Tag.extend({ | |
tagSimpleSyntax: /"[^"]+"|'[^']+'|[^\s,|]+/, | |
tagNamedSyntax: /("[^"]+"|'[^']+'|[^\s,|]+)\s*\:\s*(.*)/, | |
init: function(tag, markup, tokens) { | |
var matches, variables; | |
matches = markup.match(this.tagNamedSyntax); | |
if(matches) { | |
this.variables = this.variablesFromString(matches[2]); | |
this.name = matches[1]; | |
} else { | |
matches = markup.match(this.tagSimpleSyntax); | |
if(matches) { | |
this.variables = this.variablesFromString(markup); | |
this.name = "'"+ this.variables.toString() +"'"; | |
} else { | |
throw ("Syntax error in 'cycle' - Valid syntax: cycle [name :] var [, var2, var3 ...]"); | |
} | |
} | |
this._super(tag, markup, tokens); | |
}, | |
render: function(context) { | |
var self = this, | |
key = context.get(self.name), | |
output = ''; | |
if(!context.registers['cycle']) { | |
context.registers['cycle'] = {}; | |
} | |
if(!context.registers['cycle'][key]) { | |
context.registers['cycle'][key] = 0; | |
} | |
context.stack(function(){ | |
var iter = context.registers['cycle'][key], | |
results = context.get( self.variables[iter] ); | |
iter += 1; | |
if(iter == self.variables.length){ iter = 0; } | |
context.registers['cycle'][key] = iter; | |
output = results; | |
}); | |
return output; | |
}, | |
variablesFromString: function(markup) { | |
return markup.split(',').map(function(varname){ | |
var match = varname.match(/\s*("[^"]+"|'[^']+'|[^\s,|]+)\s*/); | |
return (match[1]) ? match[1] : null | |
}); | |
} | |
})); | |
Liquid.Template.registerTag( 'for', Liquid.Block.extend({ | |
tagSyntax: /(\w+)\s+in\s+((?:\(?[\w\-\.\[\]]\)?)+)/, | |
init: function(tag, markup, tokens) { | |
var matches = markup.match(this.tagSyntax); | |
if(matches) { | |
this.variableName = matches[1]; | |
this.collectionName = matches[2]; | |
this.name = this.variableName +"-"+ this.collectionName; | |
this.attributes = {}; | |
var attrmarkup = markup.replace(this.tagSyntax, ''); | |
var attMatchs = markup.match(/(\w*?)\s*\:\s*("[^"]+"|'[^']+'|[^\s,|]+)/g); | |
if(attMatchs) { | |
attMatchs.each(function(pair){ | |
pair = pair.split(":"); | |
this.attributes.set[pair[0].strip()] = pair[1].strip(); | |
}, this); | |
} | |
} else { | |
throw ("Syntax error in 'for loop' - Valid syntax: for [item] in [collection]"); | |
} | |
this._super(tag, markup, tokens); | |
}, | |
render: function(context) { | |
var self = this, | |
output = [], | |
collection = (context.get(this.collectionName) || []), | |
range = [0, collection.length]; | |
if(!context.registers['for']){ context.registers['for'] = {}; } | |
if(this.attributes['limit'] || this.attributes['offset']) { | |
var offset = 0, | |
limit = 0, | |
rangeEnd = 0, | |
segment = null; | |
if(this.attributes['offset'] == 'continue') | |
{ offset = context.registers['for'][this.name]; } | |
else | |
{ offset = context.get( this.attributes['offset'] ) || 0; } | |
limit = context.get( this.attributes['limit'] ); | |
rangeEnd = (limit) ? offset + limit + 1 : collection.length; | |
range = [ offset, rangeEnd - 1 ]; | |
context.registers['for'][this.name] = rangeEnd; | |
} | |
segment = collection.slice(range[0], range[1]); | |
if(!segment || segment.length == 0){ return ''; } | |
context.stack(function(){ | |
var length = segment.length; | |
segment.each(function(item, index){ | |
context.set( self.variableName, item ); | |
context.set( 'forloop', { | |
name: self.name, | |
length: length, | |
index: (index + 1), | |
index0: index, | |
rindex: (length - index), | |
rindex0:(length - index - 1), | |
first: (index == 0), | |
last: (index == (length - 1)) | |
}); | |
output.push( (self.renderAll(self.nodelist, context) || []).join('') ); | |
}); | |
}); | |
return [output].flatten().join(''); | |
} | |
})); | |
Liquid.Template.registerTag( 'if', Liquid.Block.extend({ | |
tagSyntax: /("[^"]+"|'[^']+'|[^\s,|]+)\s*([=!<>a-z_]+)?\s*("[^"]+"|'[^']+'|[^\s,|]+)?/, | |
init: function(tag, markup, tokens) { | |
this.nodelist = []; | |
this.blocks = []; | |
this.pushBlock('if', markup); | |
this._super(tag, markup, tokens); | |
}, | |
unknownTag: function(tag, markup, tokens) { | |
if( ['elsif', 'else'].include(tag) ) { | |
this.pushBlock(tag, markup); | |
} else { | |
this._super(tag, markup, tokens); | |
} | |
}, | |
render: function(context) { | |
var self = this, | |
output = ''; | |
context.stack(function(){ | |
for (var i=0; i < self.blocks.length; i++) { | |
var block = self.blocks[i]; | |
if( block.evaluate(context) ) { | |
output = self.renderAll(block.attachment, context); | |
return; | |
} | |
}; | |
}) | |
return [output].flatten().join(''); | |
}, | |
pushBlock: function(tag, markup) { | |
var block; | |
if(tag == 'else') { | |
block = new Liquid.ElseCondition(); | |
} else { | |
var expressions = markup.split(/\b(and|or)\b/).reverse(), | |
expMatches = expressions.shift().match( this.tagSyntax ); | |
if(!expMatches){ throw ("Syntax Error in tag '"+ tag +"' - Valid syntax: "+ tag +" [expression]"); } | |
var condition = new Liquid.Condition(expMatches[1], expMatches[2], expMatches[3]); | |
while(expressions.length > 0) { | |
var operator = expressions.shift(), | |
expMatches = expressions.shift().match( this.tagSyntax ); | |
if(!expMatches){ throw ("Syntax Error in tag '"+ tag +"' - Valid syntax: "+ tag +" [expression]"); } | |
var newCondition = new Liquid.Condition(expMatches[1], expMatches[2], expMatches[3]); | |
newCondition[operator](condition); | |
condition = newCondition; | |
} | |
block = condition; | |
} | |
block.attach([]); | |
this.blocks.push(block); | |
this.nodelist = block.attachment; | |
} | |
})); | |
Liquid.Template.registerTag( 'ifchanged', Liquid.Block.extend({ | |
render: function(context) { | |
var self = this, | |
output = ''; | |
context.stack(function(){ | |
var results = self.renderAll(self.nodelist, context).join(''); | |
if(results != context.registers['ifchanged']) { | |
output = results; | |
context.registers['ifchanged'] = output; | |
} | |
}); | |
return output; | |
} | |
})); | |
Liquid.Template.registerTag( 'include', Liquid.Tag.extend({ | |
tagSyntax: /((?:"[^"]+"|'[^']+'|[^\s,|]+)+)(\s+(?:with|for)\s+((?:"[^"]+"|'[^']+'|[^\s,|]+)+))?/, | |
init: function(tag, markup, tokens) { | |
var matches = (markup || '').match(this.tagSyntax); | |
if(matches) { | |
this.templateName = matches[1]; | |
this.templateNameVar = this.templateName.substring(1, this.templateName.length - 1); | |
this.variableName = matches[3]; | |
this.attributes = {}; | |
var attMatchs = markup.match(/(\w*?)\s*\:\s*("[^"]+"|'[^']+'|[^\s,|]+)/g); | |
if(attMatchs) { | |
attMatchs.each(function(pair){ | |
pair = pair.split(":"); | |
this.attributes[pair[0].strip()] = pair[1].strip(); | |
}, this); | |
} | |
} else { | |
throw ("Error in tag 'include' - Valid syntax: include '[template]' (with|for) [object|collection]"); | |
} | |
this._super(tag, markup, tokens); | |
}, | |
render: function(context) { | |
var self = this, | |
source = Liquid.readTemplateFile( context.get(this.templateName) ), | |
partial = Liquid.parse(source), | |
variable = context.get((this.variableName || this.templateNameVar)), | |
output = ''; | |
context.stack(function(){ | |
self.attributes.each = hackObjectEach; | |
self.attributes.each(function(pair){ | |
context.set(pair.key, context.get(pair.value)); | |
}) | |
if(variable instanceof Array) { | |
output = variable.map(function(variable){ | |
context.set( self.templateNameVar, variable ); | |
return partial.render(context); | |
}); | |
} else { | |
context.set(self.templateNameVar, variable); | |
output = partial.render(context); | |
} | |
}); | |
output = [output].flatten().join(''); | |
return output | |
} | |
})); | |
Liquid.Template.registerTag( 'unless', Liquid.Template.tags['if'].extend({ | |
render: function(context) { | |
var self = this, | |
output = ''; | |
context.stack(function(){ | |
var block = self.blocks[0]; | |
if( !block.evaluate(context) ) { | |
output = self.renderAll(block.attachment, context); | |
return; | |
} | |
for (var i=1; i < self.blocks.length; i++) { | |
var block = self.blocks[i]; | |
if( block.evaluate(context) ) { | |
output = self.renderAll(block.attachment, context); | |
return; | |
} | |
}; | |
}) | |
return output; | |
} | |
})); | |
Liquid.Template.registerFilter({ | |
size: function(iterable) { | |
return (iterable['length']) ? iterable.length : 0; | |
}, | |
downcase: function(input) { | |
return input.toString().toLowerCase(); | |
}, | |
upcase: function(input) { | |
return input.toString().toUpperCase(); | |
}, | |
capitalize: function(input) { | |
return input.toString().capitalize(); | |
}, | |
escape: function(input) { | |
input = input.toString(); | |
input = input.replace(/&/g, '&'); | |
input = input.replace(/</g, '<'); | |
input = input.replace(/>/g, '>'); | |
input = input.replace(/"/g, '"'); | |
return input; | |
}, | |
h: function(input) { | |
input = input.toString(); | |
input = input.replace(/&/g, '&'); | |
input = input.replace(/</g, '<'); | |
input = input.replace(/>/g, '>'); | |
input = input.replace(/"/g, '"'); | |
return input; | |
}, | |
truncate: function(input, length, string) { | |
if(!input || input == ''){ return ''; } | |
length = length || 50; | |
string = string || "..."; | |
var seg = input.slice(0, length); | |
return (input.length > length ? | |
input.slice(0, length) + string : | |
input); | |
}, | |
truncatewords: function(input, words, string) { | |
if(!input || input == ''){ return ''; } | |
words = parseInt(words || 15); | |
string = string || '...'; | |
var wordlist = input.toString().split(" "), | |
l = Math.max((words), 0); | |
return (wordlist.length > l) ? wordlist.slice(0,l).join(' ') + string : input; | |
}, | |
truncate_words: function(input, words, string) { | |
if(!input || input == ''){ return ''; } | |
words = parseInt(words || 15); | |
string = string || '...'; | |
var wordlist = input.toString().split(" "), | |
l = Math.max((words), 0); | |
return (wordlist.length > l) ? wordlist.slice(0,l).join(' ') + string : input; | |
}, | |
strip_html: function(input) { | |
return input.toString().replace(/<.*?>/g, ''); | |
}, | |
strip_newlines: function(input) { | |
return input.toString().replace(/\n/g, '') | |
}, | |
join: function(input, separator) { | |
separator = separator || ' '; | |
return input.join(separator); | |
}, | |
sort: function(input) { | |
return input.sort(); | |
}, | |
reverse: function(input) { | |
return input.reverse(); | |
}, | |
replace: function(input, string, replacement) { | |
replacement = replacement || ''; | |
return input.toString().replace(new RegExp(string, 'g'), replacement); | |
}, | |
replace_first: function(input, string, replacement) { | |
replacement = replacement || ''; | |
return input.toString().replace(new RegExp(string, ""), replacement); | |
}, | |
newline_to_br: function(input) { | |
return input.toString().replace(/\n/g, "<br/>\n"); | |
}, | |
date: function(input, format) { | |
var date; | |
if( input instanceof Date ){ date = input; } | |
if(!(date instanceof Date) && input == 'now'){ date = new Date(); } | |
if(!(date instanceof Date)){ date = new Date(input); } | |
if(!(date instanceof Date)){ date = new Date(Date.parse(input));} | |
if(!(date instanceof Date)){ return input; } // Punt | |
return date.strftime(format); | |
}, | |
first: function(input) { | |
return input[0]; | |
}, | |
last: function(input) { | |
input = input; | |
return input[input.length -1]; | |
} | |
}); | |
if(!(new Date()).strftime) {(function(){ | |
Date.ext={};Date.ext.util={};Date.ext.util.xPad=function(x,pad,r){if(typeof (r)=="undefined"){r=10}for(;parseInt(x,10)<r&&r>1;r/=10){x=pad.toString()+x}return x.toString()};Date.prototype.locale="en-GB";if(document.getElementsByTagName("html")&&document.getElementsByTagName("html")[0].lang){Date.prototype.locale=document.getElementsByTagName("html")[0].lang}Date.ext.locales={};Date.ext.locales.en={a:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],A:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],b:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],B:["January","February","March","April","May","June","July","August","September","October","November","December"],c:"%a %d %b %Y %T %Z",p:["AM","PM"],P:["am","pm"],x:"%d/%m/%y",X:"%T"};Date.ext.locales["en-US"]=Date.ext.locales.en;Date.ext.locales["en-US"].c="%a %d %b %Y %r %Z";Date.ext.locales["en-US"].x="%D";Date.ext.locales["en-US"].X="%r";Date.ext.locales["en-GB"]=Date.ext.locales.en;Date.ext.locales["en-AU"]=Date.ext.locales["en-GB"];Date.ext.formats={a:function(d){return Date.ext.locales[d.locale].a[d.getDay()]},A:function(d){return Date.ext.locales[d.locale].A[d.getDay()]},b:function(d){return Date.ext.locales[d.locale].b[d.getMonth()]},B:function(d){return Date.ext.locales[d.locale].B[d.getMonth()]},c:"toLocaleString",C:function(d){return Date.ext.util.xPad(parseInt(d.getFullYear()/100,10),0)},d:["getDate","0"],e:["getDate"," "],g:function(d){return Date.ext.util.xPad(parseInt(Date.ext.util.G(d)/100,10),0)},G:function(d){var y=d.getFullYear();var V=parseInt(Date.ext.formats.V(d),10);var W=parseInt(Date.ext.formats.W(d),10);if(W>V){y++}else{if(W===0&&V>=52){y--}}return y},H:["getHours","0"],I:function(d){var I=d.getHours()%12;return Date.ext.util.xPad(I===0?12:I,0)},j:function(d){var ms=d-new Date(""+d.getFullYear()+"/1/1 GMT");ms+=d.getTimezoneOffset()*60000;var doy=parseInt(ms/60000/60/24,10)+1;return Date.ext.util.xPad(doy,0,100)},m:function(d){return Date.ext.util.xPad(d.getMonth()+1,0)},M:["getMinutes","0"],p:function(d){return Date.ext.locales[d.locale].p[d.getHours()>=12?1:0]},P:function(d){return Date.ext.locales[d.locale].P[d.getHours()>=12?1:0]},S:["getSeconds","0"],u:function(d){var dow=d.getDay();return dow===0?7:dow},U:function(d){var doy=parseInt(Date.ext.formats.j(d),10);var rdow=6-d.getDay();var woy=parseInt((doy+rdow)/7,10);return Date.ext.util.xPad(woy,0)},V:function(d){var woy=parseInt(Date.ext.formats.W(d),10);var dow1_1=(new Date(""+d.getFullYear()+"/1/1")).getDay();var idow=woy+(dow1_1>4||dow1_1<=1?0:1);if(idow==53&&(new Date(""+d.getFullYear()+"/12/31")).getDay()<4){idow=1}else{if(idow===0){idow=Date.ext.formats.V(new Date(""+(d.getFullYear()-1)+"/12/31"))}}return Date.ext.util.xPad(idow,0)},w:"getDay",W:function(d){var doy=parseInt(Date.ext.formats.j(d),10);var rdow=7-Date.ext.formats.u(d);var woy=parseInt((doy+rdow)/7,10);return Date.ext.util.xPad(woy,0,10)},y:function(d){return Date.ext.util.xPad(d.getFullYear()%100,0)},Y:"getFullYear",z:function(d){var o=d.getTimezoneOffset();var H=Date.ext.util.xPad(parseInt(Math.abs(o/60),10),0);var M=Date.ext.util.xPad(o%60,0);return(o>0?"-":"+")+H+M},Z:function(d){return d.toString().replace(/^.*\(([^)]+)\)$/,"$1")},"%":function(d){return"%"}};Date.ext.aggregates={c:"locale",D:"%m/%d/%y",h:"%b",n:"\n",r:"%I:%M:%S %p",R:"%H:%M",t:"\t",T:"%H:%M:%S",x:"locale",X:"locale"};Date.ext.aggregates.z=Date.ext.formats.z(new Date());Date.ext.aggregates.Z=Date.ext.formats.Z(new Date());Date.ext.unsupported={};Date.prototype.strftime=function(fmt){if(!(this.locale in Date.ext.locales)){if(this.locale.replace(/-[a-zA-Z]+$/,"") in Date.ext.locales){this.locale=this.locale.replace(/-[a-zA-Z]+$/,"")}else{this.locale="en-GB"}}var d=this;while(fmt.match(/%[cDhnrRtTxXzZ]/)){fmt=fmt.replace(/%([cDhnrRtTxXzZ])/g,function(m0,m1){var f=Date.ext.aggregates[m1];return(f=="locale"?Date.ext.locales[d.locale][m1]:f)})}var str=fmt.replace(/%([aAbBCdegGHIjmMpPSuUVwWyY%])/g,function(m0,m1){var f=Date.ext.formats[m1];if(typeof (f)=="string"){return d[f]()}else{if(typeof (f)=="function"){return f.call(d,d)}else{if(typeof (f)=="object"&&typeof (f[0])=="string"){return Date.ext.util.xPad(d[f[0]](),f[1])}else{return m1}}}});d=null;return str}; | |
})();} | |
/* Cross-Browser Split 1.0.1 | |
(c) Steven Levithan <stevenlevithan.com>; MIT License | |
An ECMA-compliant, uniform cross-browser split method | |
Fixes problems with IE's broken String#split method. | |
See http://blog.stevenlevithan.com/archives/cross-browser-split | |
*/ | |
var cbSplit; | |
if (!cbSplit) { | |
cbSplit = function (str, separator, limit) { | |
if (Object.prototype.toString.call(separator) !== "[object RegExp]") { | |
return cbSplit._nativeSplit.call(str, separator, limit); | |
} | |
var output = [], | |
lastLastIndex = 0, | |
flags = (separator.ignoreCase ? "i" : "") + | |
(separator.multiline ? "m" : "") + | |
(separator.sticky ? "y" : ""), | |
separator = RegExp(separator.source, flags + "g"), // make `global` and avoid `lastIndex` issues by working with a copy | |
separator2, match, lastIndex, lastLength; | |
str = str + ""; // type conversion | |
if (!cbSplit._compliantExecNpcg) { | |
separator2 = RegExp("^" + separator.source + "$(?!\\s)", flags); // doesn't need /g or /y, but they don't hurt | |
} | |
/* behavior for `limit`: if it's... | |
- `undefined`: no limit. | |
- `NaN` or zero: return an empty array. | |
- a positive number: use `Math.floor(limit)`. | |
- a negative number: no limit. | |
- other: type-convert, then use the above rules. */ | |
if (limit === undefined || +limit < 0) { | |
limit = Infinity; | |
} else { | |
limit = Math.floor(+limit); | |
if (!limit) { | |
return []; | |
} | |
} | |
while (match = separator.exec(str)) { | |
lastIndex = match.index + match[0].length; // `separator.lastIndex` is not reliable cross-browser | |
if (lastIndex > lastLastIndex) { | |
output.push(str.slice(lastLastIndex, match.index)); | |
if (!cbSplit._compliantExecNpcg && match.length > 1) { | |
match[0].replace(separator2, function () { | |
for (var i = 1; i < arguments.length - 2; i++) { | |
if (arguments[i] === undefined) { | |
match[i] = undefined; | |
} | |
} | |
}); | |
} | |
if (match.length > 1 && match.index < str.length) { | |
Array.prototype.push.apply(output, match.slice(1)); | |
} | |
lastLength = match[0].length; | |
lastLastIndex = lastIndex; | |
if (output.length >= limit) { | |
break; | |
} | |
} | |
if (separator.lastIndex === match.index) { | |
separator.lastIndex++; // avoid an infinite loop | |
} | |
} | |
if (lastLastIndex === str.length) { | |
if (lastLength || !separator.test("")) { | |
output.push(""); | |
} | |
} else { | |
output.push(str.slice(lastLastIndex)); | |
} | |
return output.length > limit ? output.slice(0, limit) : output; | |
}; | |
cbSplit._compliantExecNpcg = /()??/.exec("")[1] === undefined; // NPCG: nonparticipating capturing group | |
cbSplit._nativeSplit = String.prototype.split; | |
} // end `if (!cbSplit)` | |
String.prototype.split = function (separator, limit) { | |
return cbSplit(this, separator, limit); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment