1/*! 2 * artTemplate - Template Engine 3 * https://github.com/aui/artTemplate 4 * Released under the MIT, BSD, and GPL Licenses 5 */ 6 7!(function () { 8 9 10 /** 11 * 模æ¿å¼æ 12 * @name template 13 * @param {String} 模æ¿å 14 * @param {Object, String} æ°æ®ãå¦æä¸ºå符串åç¼è¯å¹¶ç¼åç¼è¯ç»æ 15 * @return {String, Function} 渲æå¥½çHTMLå符串æè æ¸²ææ¹æ³ 16 */ 17 var template = function (filename, content) { 18 return typeof content === 'string' 19 ? compile(content, { 20 filename: filename 21 }) 22 : renderFile(filename, content); 23 }; 24 25 26 template.version = '3.0.0'; 27 28 29 /** 30 * è®¾ç½®å ¨å±é ç½® 31 * @name template.config 32 * @param {String} åç§° 33 * @param {Any} å¼ 34 */ 35 template.config = function (name, value) { 36 defaults[name] = value; 37 }; 38 39 40 41 var defaults = template.defaults = { 42 openTag: '<%', // é»è¾è¯æ³å¼å§æ ç¾ 43 closeTag: '%>', // é»è¾è¯æ³ç»ææ ç¾ 44 escape: true, // æ¯å¦ç¼ç è¾åºåéç HTML å符 45 cache: true, // æ¯å¦å¼å¯ç¼åï¼ä¾èµ options ç filename åæ®µï¼ 46 compress: false, // æ¯å¦å缩è¾åº 47 parser: null // èªå®ä¹è¯æ³æ ¼å¼å¨ @see: template-syntax.js 48 }; 49 50 51 var cacheStore = template.cache = {}; 52 53 54 /** 55 * æ¸²ææ¨¡æ¿ 56 * @name template.render 57 * @param {String} æ¨¡æ¿ 58 * @param {Object} æ°æ® 59 * @return {String} 渲æå¥½çå符串 60 */ 61 template.render = function (source, options) { 62 return compile(source, options); 63 }; 64 65 66 /** 67 * æ¸²ææ¨¡æ¿(æ ¹æ®æ¨¡æ¿å) 68 * @name template.render 69 * @param {String} 模æ¿å 70 * @param {Object} æ°æ® 71 * @return {String} 渲æå¥½çå符串 72 */ 73 var renderFile = template.renderFile = function (filename, data) { 74 var fn = template.get(filename) || showDebugInfo({ 75 filename: filename, 76 name: 'Render Error', 77 message: 'Template not found' 78 }); 79 return data ? fn(data) : fn; 80 }; 81 82 83 /** 84 * è·åç¼è¯ç¼åï¼å¯ç±å¤é¨éåæ¤æ¹æ³ï¼ 85 * @param {String} 模æ¿å 86 * @param {Function} ç¼è¯å¥½ç彿° 87 */ 88 template.get = function (filename) { 89 90 var cache; 91 92 if (cacheStore[filename]) { 93 // 使ç¨å åç¼å 94 cache = cacheStore[filename]; 95 } else if (typeof document === 'object') { 96 // å 载模æ¿å¹¶ç¼è¯ 97 var elem = document.getElementById(filename); 98 99 if (elem) { 100 var source = (elem.value || elem.innerHTML) 101 .replace(/^\s*|\s*$/g, ''); 102 cache = compile(source, { 103 filename: filename 104 }); 105 } 106 } 107 108 return cache; 109 }; 110 111 112 var toString = function (value, type) { 113 114 if (typeof value !== 'string') { 115 116 type = typeof value; 117 if (type === 'number') { 118 value += ''; 119 } else if (type === 'function') { 120 value = toString(value.call(value)); 121 } else { 122 value = ''; 123 } 124 } 125 126 return value; 127 128 }; 129 130 131 var escapeMap = { 132 "<": "<", 133 ">": ">", 134 '"': """, 135 "'": "'", 136 "&": "&" 137 }; 138 139 140 var escapeFn = function (s) { 141 return escapeMap[s]; 142 }; 143 144 var escapeHTML = function (content) { 145 return toString(content) 146 .replace(/&(?![\w#]+;)|[<>"']/g, escapeFn); 147 }; 148 149 150 var isArray = Array.isArray || function (obj) { 151 return ({}).toString.call(obj) === '[object Array]'; 152 }; 153 154 155 var each = function (data, callback) { 156 var i, len; 157 if (isArray(data)) { 158 for (i = 0, len = data.length; i < len; i++) {
159 callback.call(data, data[i], i, data); 160 } 161 } else { 162 for (i in data) { 163 callback.call(data, data[i], i); 164 } 165 } 166 }; 167 168 169 var utils = template.utils = { 170 171 $helpers: {}, 172 173 $include: renderFile, 174 175 $string: toString, 176 177 $escape: escapeHTML, 178 179 $each: each 180 181 };/** 182 * æ·»å æ¨¡æ¿è¾ 婿¹æ³ 183 * @name template.helper 184 * @param {String} åç§° 185 * @param {Function} æ¹æ³ 186 */ 187 template.helper = function (name, helper) { 188 helpers[name] = helper; 189 }; 190 191 var helpers = template.helpers = utils.$helpers; 192 193 194 195 196 /** 197 * 模æ¿é误äºä»¶ï¼å¯ç±å¤é¨éåæ¤æ¹æ³ï¼ 198 * @name template.onerror 199 * @event 200 */ 201 template.onerror = function (e) { 202 var message = 'Template Error\n\n'; 203 for (var name in e) { 204 message += '<' + name + '>\n' + e[name] + '\n\n'; 205 } 206 207 if (typeof console === 'object') { 208 console.error(message); 209 } 210 }; 211 212 213 // 模æ¿è°è¯å¨ 214 var showDebugInfo = function (e) { 215 216 template.onerror(e); 217 218 return function () { 219 return '{Template Error}'; 220 }; 221 }; 222 223 224 /** 225 * ç¼è¯æ¨¡æ¿ 226 * 2012-6-6 @TooBug: define æ¹æ³åæ¹ä¸º compileï¼ä¸ Node Express ä¿æä¸è´ 227 * @name template.compile 228 * @param {String} 模æ¿å符串 229 * @param {Object} ç¼è¯é项 230 * 231 * - openTag {String} 232 * - closeTag {String} 233 * - filename {String} 234 * - escape {Boolean} 235 * - compress {Boolean} 236 * - debug {Boolean} 237 * - cache {Boolean} 238 * - parser {Function} 239 * 240 * @return {Function} æ¸²ææ¹æ³ 241 */ 242 var compile = template.compile = function (source, options) { 243 244 // åå¹¶é»è®¤é ç½® 245 options = options || {}; 246 for (var name in defaults) { 247 if (options[name] === undefined) { 248 options[name] = defaults[name]; 249 } 250 } 251 252 253 var filename = options.filename; 254 255 256 try { 257 258 var Render = compiler(source, options); 259 260 } catch (e) { 261 262 e.filename = filename || 'anonymous'; 263 e.name = 'Syntax Error'; 264 265 return showDebugInfo(e); 266 267 } 268 269 270 // 对ç¼è¯ç»æè¿è¡ä¸æ¬¡å è£ 271 272 function render(data) { 273 274 try { 275 276 return new Render(data, filename) + ''; 277 278 } catch (e) { 279 280 // è¿è¡æ¶åºéåèªå¨å¼å¯è°è¯æ¨¡å¼éæ°ç¼è¯ 281 if (!options.debug) { 282 options.debug = true; 283 return compile(source, options)(data); 284 } 285 286 return showDebugInfo(e)(); 287 288 } 289 290 } 291 292 293 render.prototype = Render.prototype; 294 render.toString = function () { 295 return Render.toString(); 296 }; 297 298 299 if (filename && options.cache) { 300 cacheStore[filename] = render; 301 } 302 303 304 return render; 305 306 }; 307 308 309 310 311 // æ°ç»è¿ä»£ 312 var forEach = utils.$each; 313 314 315 // éæåææ¨¡æ¿åé 316 var KEYWORDS = 317 // å ³é®å 318 'break,case,catch,continue,debugger,default,delete,do,else,false' 319 + ',finally,for,function,if,in,instanceof,new,null,return,switch,this' 320 + ',throw,true,try,typeof,var,void,while,with' 321 322 // ä¿çå 323 + ',abstract,boolean,byte,char,class,const,double,enum,export,extends' 324 + ',final,float,goto,implements,import,int,interface,long,native' 325 + ',package,private,protected,public,short,static,super,synchronized' 326 + ',throws,transient,volatile' 327 328 // ECMA 5 - use strict 329 + ',arguments,let,yield' 330 331 + ',undefined'; 332 333 var REMOVE_RE = /\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|\s*\.\s*[$\w\.]+/g; 334 var SPLIT_RE = /[^\w$]+/g; 335 var KEYWORDS_RE = new RegExp(["\\b" + KEYWORDS.replace(/,/g, '\\b|\\b') + "\\b"].join('|'), 'g'); 336 var NUMBER_RE = /^\d[^,]*|,\d[^,]*/g; 337 var BOUNDARY_RE = /^,+|,+$/g; 338 var SPLIT2_RE = /^$|,+/; 339 340 341 // è·ååé 342 function getVariable(code) { 343 return code 344 .replace(REMOVE_RE, '') 345 .replace(SPLIT_RE, ',') 346 .replace(KEYWORDS_RE, '') 347 .replace(NUMBER_RE, '') 348 .replace(BOUNDARY_RE, '') 349 .split(SPLIT2_RE); 350 }; 351 352 353 // åç¬¦ä¸²è½¬ä¹ 354 function stringify(code) { 355 return "'" + code 356 // åå¼å·ä¸åææ è½¬ä¹ 357 .replace(/('|\\)/g, '\\$1') 358 // æ¢è¡ç¬¦è½¬ä¹(windows + linux) 359 .replace(/\r/g, '\\r') 360 .replace(/\n/g, '\\n') + "'"; 361 } 362 363 364 function compiler(source, options) { 365 366 var debug = options.debug; 367 var openTag = options.openTag; 368 var closeTag = options.closeTag; 369 var parser = options.parser; 370 var compress = options.compress; 371 var escape = options.escape; 372 373 374 375 var line = 1; 376 var uniq = { $data: 1, $filename: 1, $utils: 1, $helpers: 1, $out: 1, $line: 1 }; 377 378 379 380 var isNewEngine = ''.trim;// '__proto__' in {} 381 var replaces = isNewEngine 382 ? ["$out='';", "$out+=", ";", "$out"] 383 : ["$out=[];", "$out.push(", ");", "$out.join('')"]; 384 385 var concat = isNewEngine 386 ? "$out+=text;return $out;" 387 : "$out.push(text);"; 388 389 var print = "function(){" 390 + "var text=''.concat.apply('',arguments);" 391 + concat 392 + "}"; 393 394 var include = "function(filename,data){" 395 + "data=data||$data;" 396 + "var text=$utils.$include(filename,data,$filename);" 397 + concat 398 + "}"; 399 400 var headerCode = "'use strict';" 401 + "var $utils=this,$helpers=$utils.$helpers," 402 + (debug ? "$line=0," : ""); 403 404 var mainCode = replaces[0]; 405 406 var footerCode = "return new String(" + replaces[3] + ");" 407 408 // htmlä¸é»è¾è¯æ³å离
409 forEach(source.split(openTag), function (code) { 410 code = code.split(closeTag); 411 412 var $0 = code[0]; 413 var $1 = code[1]; 414 415 // code: [html] 416 if (code.length === 1) { 417 418 mainCode += html($0); 419 420 // code: [logic, html] 421 } else { 422 423 mainCode += logic($0); 424 425 if ($1) { 426 mainCode += html($1); 427 } 428 } 429 430 431 }); 432 433 var code = headerCode + mainCode + footerCode; 434 435 // è°è¯è¯å¥ 436 if (debug) { 437 code = "try{" + code + "}catch(e){" 438 + "throw {" 439 + "filename:$filename," 440 + "name:'Render Error'," 441 + "message:e.message," 442 + "line:$line," 443 + "source:" + stringify(source) 444 + ".split(/\\n/)[$line-1].replace(/^\\s+/,'')" 445 + "};" 446 + "}"; 447 } 448 449 450 451 try { 452 453 454 var Render = new Function("$data", "$filename", code); 455 Render.prototype = utils; 456 457 return Render; 458 459 } catch (e) { 460 e.temp = "function anonymous($data,$filename) {" + code + "}"; 461 throw e; 462 } 463 464 465 466 467 // å¤ç HTML è¯å¥ 468 function html(code) { 469 470 // è®°å½è¡å· 471 line += code.split(/\n/).length - 1; 472 473 // å缩å¤ä½ç©ºç½ä¸æ³¨é 474 if (compress) { 475 code = code 476 .replace(/\s+/g, ' ') 477 .replace(/<!--[\w\W]*?-->/g, ''); 478 } 479 480 if (code) { 481 code = replaces[1] + stringify(code) + replaces[2] + "\n"; 482 } 483 484 return code; 485 } 486 487 488 // å¤çé»è¾è¯å¥ 489 function logic(code) { 490 491 var thisLine = line; 492 493 if (parser) { 494 495 // è¯æ³è½¬æ¢æä»¶é©å 496 code = parser(code, options); 497 498 } else if (debug) { 499 500 // è®°å½è¡å· 501 code = code.replace(/\n/g, function () { 502 line++; 503 return "$line=" + line + ";"; 504 }); 505 506 } 507 508 509 // è¾åºè¯å¥. ç¼ç : <%=value%> ä¸ç¼ç :<%=#value%> 510 // <%=#value%> çå v2.0.3 ä¹åç <%==value%> 511 if (code.indexOf('=') === 0) { 512 513 var escapeSyntax = escape && !/^=[=#]/.test(code); 514 515 code = code.replace(/^=[=#]?|[\s;]*$/g, ''); 516 517 // 对å 容ç¼ç 518 if (escapeSyntax) { 519 520 var name = code.replace(/\s*\([^\)]+\)/, ''); 521 522 // æé¤ utils.* | include | print 523 524 if (!utils[name] && !/^(include|print)$/.test(name)) { 525 code = "$escape(" + code + ")"; 526 } 527 528 // ä¸ç¼ç 529 } else { 530 code = "$string(" + code + ")"; 531 } 532 533 534 code = replaces[1] + code + replaces[2]; 535 536 } 537 538 if (debug) { 539 code = "$line=" + thisLine + ";" + code; 540 } 541 542 // æå模æ¿ä¸çåéå 543 forEach(getVariable(code), function (name) { 544 545 // name å¼å¯è½ä¸ºç©ºï¼å¨å®åä½çæ¬æµè§å¨ä¸ 546 if (!name || uniq[name]) { 547 return; 548 } 549 550 var value; 551 552 // å£°ææ¨¡æ¿åé 553 // èµå¼ä¼å 级: 554 // [include, print] > utils > helpers > data 555 if (name === 'print') { 556 557 value = print; 558 559 } else if (name === 'include') { 560 561 value = include; 562 563 } else if (utils[name]) { 564 565 value = "$utils." + name; 566 567 } else if (helpers[name]) { 568 569 value = "$helpers." + name; 570 571 } else { 572 573 value = "$data." + name; 574 } 575 576 headerCode += name + "=" + value + ","; 577 uniq[name] = true; 578 579 580 }); 581 582 return code + "\n"; 583 } 584 585 586 }; 587 588 589 590 // å®ä¹æ¨¡æ¿å¼æçè¯æ³ 591 592 593 defaults.openTag = '{{'; 594 defaults.closeTag = '}}'; 595 596 597 var filtered = function (js, filter) { 598 var parts = filter.split(':'); 599 var name = parts.shift(); 600 var args = parts.join(':') || ''; 601 602 if (args) { 603 args = ', ' + args; 604 } 605 606 return '$helpers.' + name + '(' + js + args + ')'; 607 } 608 609 610 defaults.parser = function (code, options) { 611 612 // var match = code.match(/([\w\$]*)(\b.*)/); 613 // var key = match[1]; 614 // var args = match[2]; 615 // var split = args.split(' '); 616 // split.shift(); 617 618 code = code.replace(/^\s/, ''); 619 620 var split = code.split(' '); 621 var key = split.shift(); 622 var args = split.join(' '); 623 624 625 626 switch (key) { 627 628 case 'if': 629 630 code = 'if(' + args + '){'; 631 break; 632 633 case 'else': 634 635 if (split.shift() === 'if') { 636 split = ' if(' + split.join(' ') + ')'; 637 } else { 638 split = ''; 639 } 640 641 code = '}else' + split + '{'; 642 break; 643 644 case '/if': 645 646 code = '}'; 647 break; 648 649 case 'each': 650 651 var object = split[0] || '$data'; 652 var as = split[1] || 'as'; 653 var value = split[2] || '$value'; 654 var index = split[3] || '$index'; 655 656 var param = value + ',' + index; 657 658 if (as !== 'as') { 659 object = '[]'; 660 } 661
662 code = '$each(' + object + ',function(' + param + '){'; 663 break; 664 665 case '/each': 666 667 code = '});'; 668 break; 669 670 case 'echo': 671 672 code = 'print(' + args + ');'; 673 break; 674 675 case 'print': 676 case 'include': 677 678 code = key + '(' + split.join(',') + ');'; 679 break; 680 681 default: 682 683 // è¿æ»¤å¨ï¼è¾ 婿¹æ³ï¼ 684 // {{value | filterA:'abcd' | filterB}} 685 // >>> $helpers.filterB($helpers.filterA(value, 'abcd')) 686 // TODO: {{ddd||aaa}} ä¸å å«ç©ºæ ¼ 687 if (/^\s*\|\s*[\w\$]/.test(args)) { 688 689 var escape = true; 690 691 // {{#value | link}} 692 if (code.indexOf('#') === 0) { 693 code = code.substr(1); 694 escape = false; 695 } 696 697 var i = 0; 698 var array = code.split('|'); 699 var len = array.length; 700 var val = array[i++]; 701 702 for (; i < len; i++) { 703 val = filtered(val, array[i]); 704 } 705 706 code = (escape ? '=' : '=#') + val; 707 708 // å³å°å¼ç¨ {{helperName value}} 709 } else if (template.helpers[key]) { 710 711 code = '=#' + key + '(' + split.join(',') + ');'; 712 713 // å å®¹ç´æ¥è¾åº {{value}} 714 } else { 715 716 code = '=' + code; 717 } 718 719 break; 720 } 721 722 723 return code; 724 }; 725 726 727 728 // RequireJS && SeaJS 729 if (typeof define === 'function') { 730 define('artTemplate', [], function () { 731 return template; 732 }); 733 734 // NodeJS 735 } else if (typeof exports !== 'undefined') { 736 module.exports = template; 737 } else { 738 this.template = template; 739 } 740 741})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.