lite
Version:
A cross platform template engine base on xml/html and javascript expression.
197 lines (185 loc) • 5.58 kB
JavaScript
/*
* foo://example.com:8042/over/there?name=ferret#nose
* \_/ \______________/\_________/ \_________/ \__/
* | | | | |
* scheme authority path query fragment
* | _____________________|__
* / \ / \
* urn:example:animal:ferret:nose
*/
var uriPattern = /^([a-zA-Z][\w\.]*)\:(?:(\/\/[^\/]*))?(\/?[^?#]*)(\?[^#]*)?(#[\s\S]*)?$/;
var absURIPattern = /^[a-zA-Z][\w\.]*\:/;
var uriChars = /\\|[\x22\x3c\x3e\x5c\x5e\x60\u1680\u180e\u202f\u205f\u3000]|[\x00-\x20]|[\x7b-\x7d]|[\x7f-\xa0]|[\u2000-\u200b]|[\u2028-\u2029]/g;
var allEncodes = /[\x2f\x60]|[\x00-\x29]|[\x2b-\x2c]|[\x3a-\x40]|[\x5b-\x5e]|[\x7b-\uffff]/g;
///[\x22\x25\x3c\x3e\x5c\x5e\x60\u1680\u180e\u202f\u205f\u3000]|[\x00-\x20]|[\x7b-\x7d]|[\x7f-\xa0]|[\u2000-\u200b]|[\u2028-\u2029]/g;
function encodeChar(i){
return "%"+(0x100+i).toString(16).substring(1)
}
function decodeChar(c){
var n = c.charCodeAt();
if (n < 0x80){
return encodeChar(n);
}else if (n < 0x800){
return encodeChar(0xc0 | (n >>> 6))+encodeChar(0x80 | (n & 0x3f))
}else{
return encodeChar( 0xe0 | ((n >>> 12) & 0x0f))+
encodeChar(0x80 | ((n >>> 6) & 0x3f))+
encodeChar(0x80 | (n & 0x3f))
}
}
function uriDecode(source){
//192,224,240
for(var result = [], i=1;i<source.length;i+=3){
var c = parseInt(source.substr(i,2),16);
if(c>=240){//其实无效,js无法处理超出2字节的字符
c = (c & 0x07)<<18;
c += (parseInt(source.substr(i+=3,2),16) &0x3f)<<12;
c += (parseInt(source.substr(i+=3,2),16) &0x3f)<<6;
c += (parseInt(source.substr(i+=3,2),16) &0x3f);
}else if(c>=224){
c = (c & 0x0f)<<12;
c += (parseInt(source.substr(i+=3,2),16) &0x3f)<<6;
c += (parseInt(source.substr(i+=3,2),16) &0x3f);
}else if(c>=192){
c = (c & 0x1f)<<6;
c += (parseInt(source.substr(i+=3,2),16) &0x3f);
}
result.push(String.fromCharCode(c))
}
return result.join('');
}
function uriReplace(c){
if(c == '\\'){
return '/';
}else{
return decodeChar(c);
}
}
function URI(path){
if(path instanceof URI){
return path;
}
if(/^\s*[<]/i.test(path)){
path = String(path).replace(uriChars,decodeChar)
return new URI("data:text/xml,"+path);
}else{
path = String(path).replace(uriChars,uriReplace)
}
//normalize
path = path.replace(/\/\.\/|\\\.\\|\\/g,'/');
if(/^\/|^[a-z]\:\//i.test(path)){
path = 'file://'+path;
}
while(path != (path = path.replace(/[^\/]+\/\.\.\//g,'')));
var match = path.match(uriPattern);
if(match){
setupURI(this,match);
}else{
console.error("url must be absolute,"+path)
}
}
function setupURI(uri,match){
uri.value = match[0];
uri.scheme = match[1];
uri.authority = match[2];
uri.path = match[3];
uri.query = match[4];
uri.fragment = match[5];
if('data' == uri.scheme){
match = uri.value
uri.source = decodeURIComponent(match.substring(match.indexOf(',')+1));
}
}
URI.prototype = {
resolve:function(path){
path = String(path);
if( /^\s*[#<]/.test(path) ||absURIPattern.test(path)){
path = new URI(path.replace(/^\s+/,''));
return path;
}
path = path.replace(uriChars,uriReplace)
if(path.charAt() != '/'){
var p = this.path;
path = p.replace(/[^\/]*$/,path);
}
return new URI(this.scheme + ':'+(this.authority||'') + path);
},
toString:function(){
return this.value;
}
}
var btoa = this.btoa || function(bs){
var b64 = [];
var bi = 0;
var len = bs.length;
while (bi <len) {
var b0 = bs.charCodeAt(bi++);
var b1 = bs.charCodeAt(bi++);
var b2 = bs.charCodeAt(bi++);
var data = (b0 << 16) + (b1 << 8) + (b2||0);
b64.push(
b64codes[(data >> 18) & 0x3F ],
b64codes[(data >> 12) & 0x3F],
b64codes[isNaN(b1) ? 64 : (data >> 6) & 0x3F],
b64codes[isNaN(b2) ? 64 : data & 0x3F]) ;
}
return b64.join('');
}
var b64codes = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split('');
function utf8Replacer(c){
var n = c.charCodeAt();
if (n < 0x800){
return String.fromCharCode(
(0xc0 | (n >>> 6)),
(0x80|(n & 0x3f)));
}else{
return String.fromCharCode(
(0xe0 | ((n >>> 12) & 0x0f)),
(0x80 | ((n >>> 6) & 0x3f)),
(0x80 | (n & 0x3f)));
}
}
function base64Encode(data){
data = data && data.replace(/[\u0080-\uFFFF]/g,utf8Replacer)||''
data = btoa(data) ;
return encodeURIComponent(data);
}
function buildURIMatcher(pattern){
var matcher = /\*+|[^\*\\\/]+?|[\\\/]/g;
var buf = ["^"];
var m
matcher.lastIndex = 0;
while (m = matcher.exec(pattern)) {
var item = m[0];
var len = item.length;
var c = item.charAt(0);
if (c == '*') {
if (len > 1) {
buf.push(".*");
} else {
buf.push("[^\\\\/]*");
}
} else if(len == 1 && c == '/' || c == '\\') {
buf.push("[\\\\/]");
}else{
buf.push(item.replace(/[^\w]/g,quteReqExp));
}
}
buf.push("$");
return buf.join('');
}
function quteReqExp(x){
switch(x){
case '.':
return '\\.';
case '\\':
return '\\\\';
default:
return '\\x'+(0x100 + x.charCodeAt()).toString(16).substring(1);
}
}
if(typeof require == 'function'){
exports.URI=URI;
exports.buildURIMatcher = buildURIMatcher;
exports.base64Encode=base64Encode;
}