| [ Index ] |
PHP Cross Reference of Moodle 310 |
[Summary view] [Print] [Text view]
1 // The MIT License 2 // 3 // Copyright (c) 2009 Chris Wanstrath (Ruby) 4 // Copyright (c) 2010-2014 Jan Lehnardt (JavaScript) 5 // Copyright (c) 2010-2015 The mustache.js community 6 // 7 // Permission is hereby granted, free of charge, to any person obtaining 8 // a copy of this software and associated documentation files (the 9 // "Software"), to deal in the Software without restriction, including 10 // without limitation the rights to use, copy, modify, merge, publish, 11 // distribute, sublicense, and/or sell copies of the Software, and to 12 // permit persons to whom the Software is furnished to do so, subject to 13 // the following conditions: 14 // 15 // The above copyright notice and this permission notice shall be 16 // included in all copies or substantial portions of the Software. 17 // 18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 // 26 27 // Description of import into Moodle: 28 // Checkout from https://github.com/moodle/custom-mustache.js Branch: LAMBDA_ARGS 29 // Rebase onto latest release tag from https://github.com/janl/mustache.js 30 // Copy mustache.js into lib/amd/src/ in Moodle folder. 31 // Add the license as a comment to the file and these instructions. 32 // Add jshint tags so this file is not linted. 33 // Remove the "global define:" comment (hint for linter) 34 // Make sure that you have not removed the custom code for '$' and '<'. 35 36 /*! 37 * mustache.js - Logic-less {{mustache}} templates with JavaScript 38 * http://github.com/janl/mustache.js 39 */ 40 41 /* jshint ignore:start */ 42 43 (function defineMustache (global, factory) { 44 if (typeof exports === 'object' && exports && typeof exports.nodeName !== 'string') { 45 factory(exports); // CommonJS 46 } else if (typeof define === 'function' && define.amd) { 47 define(['exports'], factory); // AMD 48 } else { 49 global.Mustache = {}; 50 factory(global.Mustache); // script, wsh, asp 51 } 52 }(this, function mustacheFactory (mustache) { 53 54 var objectToString = Object.prototype.toString; 55 var isArray = Array.isArray || function isArrayPolyfill (object) { 56 return objectToString.call(object) === '[object Array]'; 57 }; 58 59 function isFunction (object) { 60 return typeof object === 'function'; 61 } 62 63 /** 64 * More correct typeof string handling array 65 * which normally returns typeof 'object' 66 */ 67 function typeStr (obj) { 68 return isArray(obj) ? 'array' : typeof obj; 69 } 70 71 function escapeRegExp (string) { 72 return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&'); 73 } 74 75 /** 76 * Null safe way of checking whether or not an object, 77 * including its prototype, has a given property 78 */ 79 function hasProperty (obj, propName) { 80 return obj != null && typeof obj === 'object' && (propName in obj); 81 } 82 83 /** 84 * Safe way of detecting whether or not the given thing is a primitive and 85 * whether it has the given property 86 */ 87 function primitiveHasOwnProperty (primitive, propName) { 88 return ( 89 primitive != null 90 && typeof primitive !== 'object' 91 && primitive.hasOwnProperty 92 && primitive.hasOwnProperty(propName) 93 ); 94 } 95 96 // Workaround for https://issues.apache.org/jira/browse/COUCHDB-577 97 // See https://github.com/janl/mustache.js/issues/189 98 var regExpTest = RegExp.prototype.test; 99 function testRegExp (re, string) { 100 return regExpTest.call(re, string); 101 } 102 103 var nonSpaceRe = /\S/; 104 function isWhitespace (string) { 105 return !testRegExp(nonSpaceRe, string); 106 } 107 108 var entityMap = { 109 '&': '&', 110 '<': '<', 111 '>': '>', 112 '"': '"', 113 "'": ''', 114 '/': '/', 115 '`': '`', 116 '=': '=' 117 }; 118 119 function escapeHtml (string) { 120 return String(string).replace(/[&<>"'`=\/]/g, function fromEntityMap (s) { 121 return entityMap[s]; 122 }); 123 } 124 125 var whiteRe = /\s*/; 126 var spaceRe = /\s+/; 127 var equalsRe = /\s*=/; 128 var curlyRe = /\s*\}/; 129 var tagRe = /#|\^|\/|>|\{|&|=|!|\$|</; 130 131 /** 132 * Breaks up the given `template` string into a tree of tokens. If the `tags` 133 * argument is given here it must be an array with two string values: the 134 * opening and closing tags used in the template (e.g. [ "<%", "%>" ]). Of 135 * course, the default is to use mustaches (i.e. mustache.tags). 136 * 137 * A token is an array with at least 4 elements. The first element is the 138 * mustache symbol that was used inside the tag, e.g. "#" or "&". If the tag 139 * did not contain a symbol (i.e. {{myValue}}) this element is "name". For 140 * all text that appears outside a symbol this element is "text". 141 * 142 * The second element of a token is its "value". For mustache tags this is 143 * whatever else was inside the tag besides the opening symbol. For text tokens 144 * this is the text itself. 145 * 146 * The third and fourth elements of the token are the start and end indices, 147 * respectively, of the token in the original template. 148 * 149 * Tokens that are the root node of a subtree contain two more elements: 1) an 150 * array of tokens in the subtree and 2) the index in the original template at 151 * which the closing tag for that section begins. 152 * 153 * Tokens for partials also contain two more elements: 1) a string value of 154 * indendation prior to that tag and 2) the index of that tag on that line - 155 * eg a value of 2 indicates the partial is the third tag on this line. 156 */ 157 function parseTemplate (template, tags) { 158 if (!template) 159 return []; 160 var lineHasNonSpace = false; 161 var sections = []; // Stack to hold section tokens 162 var tokens = []; // Buffer to hold the tokens 163 var spaces = []; // Indices of whitespace tokens on the current line 164 var hasTag = false; // Is there a {{tag}} on the current line? 165 var nonSpace = false; // Is there a non-space char on the current line? 166 var indentation = ''; // Tracks indentation for tags that use it 167 var tagIndex = 0; // Stores a count of number of tags encountered on a line 168 169 // Strips all whitespace tokens array for the current line 170 // if there was a {{#tag}} on it and otherwise only space. 171 function stripSpace () { 172 if (hasTag && !nonSpace) { 173 while (spaces.length) 174 delete tokens[spaces.pop()]; 175 } else { 176 spaces = []; 177 } 178 179 hasTag = false; 180 nonSpace = false; 181 } 182 183 var openingTagRe, closingTagRe, closingCurlyRe; 184 function compileTags (tagsToCompile) { 185 if (typeof tagsToCompile === 'string') 186 tagsToCompile = tagsToCompile.split(spaceRe, 2); 187 188 if (!isArray(tagsToCompile) || tagsToCompile.length !== 2) 189 throw new Error('Invalid tags: ' + tagsToCompile); 190 191 openingTagRe = new RegExp(escapeRegExp(tagsToCompile[0]) + '\\s*'); 192 closingTagRe = new RegExp('\\s*' + escapeRegExp(tagsToCompile[1])); 193 closingCurlyRe = new RegExp('\\s*' + escapeRegExp('}' + tagsToCompile[1])); 194 } 195 196 compileTags(tags || mustache.tags); 197 198 var scanner = new Scanner(template); 199 200 var start, type, value, chr, token, openSection; 201 while (!scanner.eos()) { 202 start = scanner.pos; 203 204 // Match any text between tags. 205 value = scanner.scanUntil(openingTagRe); 206 207 if (value) { 208 for (var i = 0, valueLength = value.length; i < valueLength; ++i) { 209 chr = value.charAt(i); 210 211 if (isWhitespace(chr)) { 212 spaces.push(tokens.length); 213 indentation += chr; 214 } else { 215 nonSpace = true; 216 lineHasNonSpace = true; 217 indentation += ' '; 218 } 219 220 tokens.push([ 'text', chr, start, start + 1 ]); 221 start += 1; 222 223 // Check for whitespace on the current line. 224 if (chr === '\n') { 225 stripSpace(); 226 indentation = ''; 227 tagIndex = 0; 228 lineHasNonSpace = false; 229 } 230 } 231 } 232 233 // Match the opening tag. 234 if (!scanner.scan(openingTagRe)) 235 break; 236 237 hasTag = true; 238 239 // Get the tag type. 240 type = scanner.scan(tagRe) || 'name'; 241 scanner.scan(whiteRe); 242 243 // Get the tag value. 244 if (type === '=') { 245 value = scanner.scanUntil(equalsRe); 246 scanner.scan(equalsRe); 247 scanner.scanUntil(closingTagRe); 248 } else if (type === '{') { 249 value = scanner.scanUntil(closingCurlyRe); 250 scanner.scan(curlyRe); 251 scanner.scanUntil(closingTagRe); 252 type = '&'; 253 } else { 254 value = scanner.scanUntil(closingTagRe); 255 } 256 257 // Match the closing tag. 258 if (!scanner.scan(closingTagRe)) 259 throw new Error('Unclosed tag at ' + scanner.pos); 260 261 if (type == '>') { 262 token = [ type, value, start, scanner.pos, indentation, tagIndex, lineHasNonSpace ]; 263 } else { 264 token = [ type, value, start, scanner.pos ]; 265 } 266 tagIndex++; 267 tokens.push(token); 268 269 if (type === '#' || type === '^' || type === '$' || type === '<') { 270 sections.push(token); 271 } else if (type === '/') { 272 // Check section nesting. 273 openSection = sections.pop(); 274 275 if (!openSection) 276 throw new Error('Unopened section "' + value + '" at ' + start); 277 278 if (openSection[1] !== value) 279 throw new Error('Unclosed section "' + openSection[1] + '" at ' + start); 280 } else if (type === 'name' || type === '{' || type === '&') { 281 nonSpace = true; 282 } else if (type === '=') { 283 // Set the tags for the next time around. 284 compileTags(value); 285 } 286 } 287 288 stripSpace(); 289 290 // Make sure there are no open sections when we're done. 291 openSection = sections.pop(); 292 293 if (openSection) 294 throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos); 295 296 return nestTokens(squashTokens(tokens)); 297 } 298 299 /** 300 * Combines the values of consecutive text tokens in the given `tokens` array 301 * to a single token. 302 */ 303 function squashTokens (tokens) { 304 var squashedTokens = []; 305 306 var token, lastToken; 307 for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) { 308 token = tokens[i]; 309 310 if (token) { 311 if (token[0] === 'text' && lastToken && lastToken[0] === 'text') { 312 lastToken[1] += token[1]; 313 lastToken[3] = token[3]; 314 } else { 315 squashedTokens.push(token); 316 lastToken = token; 317 } 318 } 319 } 320 321 return squashedTokens; 322 } 323 324 /** 325 * Forms the given array of `tokens` into a nested tree structure where 326 * tokens that represent a section have two additional items: 1) an array of 327 * all tokens that appear in that section and 2) the index in the original 328 * template that represents the end of that section. 329 */ 330 function nestTokens (tokens) { 331 var nestedTokens = []; 332 var collector = nestedTokens; 333 var sections = []; 334 335 var token, section; 336 for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) { 337 token = tokens[i]; 338 339 switch (token[0]) { 340 case '$': 341 case '<': 342 case '#': 343 case '^': 344 collector.push(token); 345 sections.push(token); 346 collector = token[4] = []; 347 break; 348 case '/': 349 section = sections.pop(); 350 section[5] = token[2]; 351 collector = sections.length > 0 ? sections[sections.length - 1][4] : nestedTokens; 352 break; 353 default: 354 collector.push(token); 355 } 356 } 357 358 return nestedTokens; 359 } 360 361 /** 362 * A simple string scanner that is used by the template parser to find 363 * tokens in template strings. 364 */ 365 function Scanner (string) { 366 this.string = string; 367 this.tail = string; 368 this.pos = 0; 369 } 370 371 /** 372 * Returns `true` if the tail is empty (end of string). 373 */ 374 Scanner.prototype.eos = function eos () { 375 return this.tail === ''; 376 }; 377 378 /** 379 * Tries to match the given regular expression at the current position. 380 * Returns the matched text if it can match, the empty string otherwise. 381 */ 382 Scanner.prototype.scan = function scan (re) { 383 var match = this.tail.match(re); 384 385 if (!match || match.index !== 0) 386 return ''; 387 388 var string = match[0]; 389 390 this.tail = this.tail.substring(string.length); 391 this.pos += string.length; 392 393 return string; 394 }; 395 396 /** 397 * Skips all text until the given regular expression can be matched. Returns 398 * the skipped string, which is the entire tail if no match can be made. 399 */ 400 Scanner.prototype.scanUntil = function scanUntil (re) { 401 var index = this.tail.search(re), match; 402 403 switch (index) { 404 case -1: 405 match = this.tail; 406 this.tail = ''; 407 break; 408 case 0: 409 match = ''; 410 break; 411 default: 412 match = this.tail.substring(0, index); 413 this.tail = this.tail.substring(index); 414 } 415 416 this.pos += match.length; 417 418 return match; 419 }; 420 421 /** 422 * Represents a rendering context by wrapping a view object and 423 * maintaining a reference to the parent context. 424 */ 425 function Context (view, parentContext) { 426 this.view = view; 427 this.blocks = {}; 428 this.cache = { '.': this.view }; 429 this.parent = parentContext; 430 } 431 432 /** 433 * Creates a new context using the given view with this context 434 * as the parent. 435 */ 436 Context.prototype.push = function push (view) { 437 return new Context(view, this); 438 }; 439 440 /** 441 * Set a value in the current block context. 442 */ 443 Context.prototype.setBlockVar = function set (name, value) { 444 var blocks = this.blocks; 445 446 blocks[name] = value; 447 448 return value; 449 }; 450 451 /** 452 * Clear all current block vars. 453 */ 454 Context.prototype.clearBlockVars = function clearBlockVars () { 455 this.blocks = {}; 456 }; 457 458 /** 459 * Get a value only from the current block context. 460 */ 461 Context.prototype.getBlockVar = function getBlockVar (name) { 462 var blocks = this.blocks; 463 464 var value; 465 if (blocks.hasOwnProperty(name)) { 466 value = blocks[name]; 467 } else { 468 if (this.parent) { 469 value = this.parent.getBlockVar(name); 470 } 471 } 472 // Can return undefined. 473 return value; 474 }; 475 476 /** 477 * Returns the value of the given name in this context, traversing 478 * up the context hierarchy if the value is absent in this context's view. 479 */ 480 Context.prototype.lookup = function lookup (name) { 481 var cache = this.cache; 482 483 var value; 484 if (cache.hasOwnProperty(name)) { 485 value = cache[name]; 486 } else { 487 var context = this, intermediateValue, names, index, lookupHit = false; 488 489 while (context) { 490 if (name.indexOf('.') > 0) { 491 intermediateValue = context.view; 492 names = name.split('.'); 493 index = 0; 494 495 /** 496 * Using the dot notion path in `name`, we descend through the 497 * nested objects. 498 * 499 * To be certain that the lookup has been successful, we have to 500 * check if the last object in the path actually has the property 501 * we are looking for. We store the result in `lookupHit`. 502 * 503 * This is specially necessary for when the value has been set to 504 * `undefined` and we want to avoid looking up parent contexts. 505 * 506 * In the case where dot notation is used, we consider the lookup 507 * to be successful even if the last "object" in the path is 508 * not actually an object but a primitive (e.g., a string, or an 509 * integer), because it is sometimes useful to access a property 510 * of an autoboxed primitive, such as the length of a string. 511 **/ 512 while (intermediateValue != null && index < names.length) { 513 if (index === names.length - 1) 514 lookupHit = ( 515 hasProperty(intermediateValue, names[index]) 516 || primitiveHasOwnProperty(intermediateValue, names[index]) 517 ); 518 519 intermediateValue = intermediateValue[names[index++]]; 520 } 521 } else { 522 intermediateValue = context.view[name]; 523 524 /** 525 * Only checking against `hasProperty`, which always returns `false` if 526 * `context.view` is not an object. Deliberately omitting the check 527 * against `primitiveHasOwnProperty` if dot notation is not used. 528 * 529 * Consider this example: 530 * ``` 531 * Mustache.render("The length of a football field is {{#length}}{{length}}{{/length}}.", {length: "100 yards"}) 532 * ``` 533 * 534 * If we were to check also against `primitiveHasOwnProperty`, as we do 535 * in the dot notation case, then render call would return: 536 * 537 * "The length of a football field is 9." 538 * 539 * rather than the expected: 540 * 541 * "The length of a football field is 100 yards." 542 **/ 543 lookupHit = hasProperty(context.view, name); 544 } 545 546 if (lookupHit) { 547 value = intermediateValue; 548 break; 549 } 550 551 context = context.parent; 552 } 553 554 cache[name] = value; 555 } 556 557 if (isFunction(value)) 558 value = value.call(this.view); 559 560 return value; 561 }; 562 563 /** 564 * A Writer knows how to take a stream of tokens and render them to a 565 * string, given a context. It also maintains a cache of templates to 566 * avoid the need to parse the same template twice. 567 */ 568 function Writer () { 569 this.cache = {}; 570 } 571 572 /** 573 * Clears all cached templates in this writer. 574 */ 575 Writer.prototype.clearCache = function clearCache () { 576 this.cache = {}; 577 }; 578 579 /** 580 * Parses and caches the given `template` according to the given `tags` or 581 * `mustache.tags` if `tags` is omitted, and returns the array of tokens 582 * that is generated from the parse. 583 */ 584 Writer.prototype.parse = function parse (template, tags) { 585 var cache = this.cache; 586 var cacheKey = template + ':' + (tags || mustache.tags).join(':'); 587 var tokens = cache[cacheKey]; 588 589 if (tokens == null) 590 tokens = cache[cacheKey] = parseTemplate(template, tags); 591 592 return tokens; 593 }; 594 595 /** 596 * High-level method that is used to render the given `template` with 597 * the given `view`. 598 * 599 * The optional `partials` argument may be an object that contains the 600 * names and templates of partials that are used in the template. It may 601 * also be a function that is used to load partial templates on the fly 602 * that takes a single argument: the name of the partial. 603 * 604 * If the optional `tags` argument is given here it must be an array with two 605 * string values: the opening and closing tags used in the template (e.g. 606 * [ "<%", "%>" ]). The default is to mustache.tags. 607 */ 608 Writer.prototype.render = function render (template, view, partials, tags) { 609 var tokens = this.parse(template, tags); 610 var context = (view instanceof Context) ? view : new Context(view); 611 return this.renderTokens(tokens, context, partials, template, tags); 612 }; 613 614 /** 615 * Low-level method that renders the given array of `tokens` using 616 * the given `context` and `partials`. 617 * 618 * Note: The `originalTemplate` is only ever used to extract the portion 619 * of the original template that was contained in a higher-order section. 620 * If the template doesn't use higher-order sections, this argument may 621 * be omitted. 622 */ 623 Writer.prototype.renderTokens = function renderTokens (tokens, context, partials, originalTemplate, tags) { 624 var buffer = ''; 625 626 var token, symbol, value; 627 for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) { 628 value = undefined; 629 token = tokens[i]; 630 symbol = token[0]; 631 632 if (symbol === '#') value = this.renderSection(token, context, partials, originalTemplate); 633 else if (symbol === '^') value = this.renderInverted(token, context, partials, originalTemplate); 634 else if (symbol === '>') value = this.renderPartial(token, context, partials, tags); 635 else if (symbol === '<') value = this.renderBlock(token, context, partials, originalTemplate); 636 else if (symbol === '$') value = this.renderBlockVariable(token, context, partials, originalTemplate); 637 else if (symbol === '&') value = this.unescapedValue(token, context); 638 else if (symbol === 'name') value = this.escapedValue(token, context); 639 else if (symbol === 'text') value = this.rawValue(token); 640 641 if (value !== undefined) 642 buffer += value; 643 } 644 645 return buffer; 646 }; 647 648 Writer.prototype.renderSection = function renderSection (token, context, partials, originalTemplate) { 649 var self = this; 650 var buffer = ''; 651 var value = context.lookup(token[1]); 652 653 // This function is used to render an arbitrary template 654 // in the current context by higher-order sections. 655 function subRender (template) { 656 return self.render(template, context, partials); 657 } 658 659 if (!value) return; 660 661 if (isArray(value)) { 662 for (var j = 0, valueLength = value.length; j < valueLength; ++j) { 663 buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate); 664 } 665 } else if (typeof value === 'object' || typeof value === 'string' || typeof value === 'number') { 666 buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate); 667 } else if (isFunction(value)) { 668 if (typeof originalTemplate !== 'string') 669 throw new Error('Cannot use higher-order sections without the original template'); 670 671 // Extract the portion of the original template that the section contains. 672 value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender); 673 674 if (value != null) 675 buffer += value; 676 } else { 677 buffer += this.renderTokens(token[4], context, partials, originalTemplate); 678 } 679 return buffer; 680 }; 681 682 Writer.prototype.renderInverted = function renderInverted (token, context, partials, originalTemplate) { 683 var value = context.lookup(token[1]); 684 685 // Use JavaScript's definition of falsy. Include empty arrays. 686 // See https://github.com/janl/mustache.js/issues/186 687 if (!value || (isArray(value) && value.length === 0)) 688 return this.renderTokens(token[4], context, partials, originalTemplate); 689 }; 690 691 Writer.prototype.indentPartial = function indentPartial (partial, indentation, lineHasNonSpace) { 692 var filteredIndentation = indentation.replace(/[^ \t]/g, ''); 693 var partialByNl = partial.split('\n'); 694 for (var i = 0; i < partialByNl.length; i++) { 695 if (partialByNl[i].length && (i > 0 || !lineHasNonSpace)) { 696 partialByNl[i] = filteredIndentation + partialByNl[i]; 697 } 698 } 699 return partialByNl.join('\n'); 700 }; 701 702 Writer.prototype.renderPartial = function renderPartial (token, context, partials, tags) { 703 if (!partials) return; 704 705 var value = isFunction(partials) ? partials(token[1]) : partials[token[1]]; 706 if (value != null) { 707 var lineHasNonSpace = token[6]; 708 var tagIndex = token[5]; 709 var indentation = token[4]; 710 var indentedValue = value; 711 if (tagIndex == 0 && indentation) { 712 indentedValue = this.indentPartial(value, indentation, lineHasNonSpace); 713 } 714 return this.renderTokens(this.parse(indentedValue, tags), context, partials, indentedValue); 715 } 716 }; 717 718 Writer.prototype.renderBlock = function renderBlock (token, context, partials, originalTemplate) { 719 if (!partials) return; 720 721 var value = isFunction(partials) ? partials(token[1]) : partials[token[1]]; 722 if (value != null) 723 // Ignore any wrongly set block vars before we started. 724 context.clearBlockVars(); 725 // We are only rendering to record the default block variables. 726 this.renderTokens(token[4], context, partials, originalTemplate); 727 // Now we render and return the result. 728 var result = this.renderTokens(this.parse(value), context, partials, value); 729 // Don't leak the block variables outside this include. 730 context.clearBlockVars(); 731 return result; 732 }; 733 734 Writer.prototype.renderBlockVariable = function renderBlockVariable (token, context, partials, originalTemplate) { 735 var value = token[1]; 736 737 var exists = context.getBlockVar(value); 738 if (!exists) { 739 context.setBlockVar(value, originalTemplate.slice(token[3], token[5])); 740 return this.renderTokens(token[4], context, partials, originalTemplate); 741 } else { 742 return this.renderTokens(this.parse(exists), context, partials, exists); 743 } 744 }; 745 746 Writer.prototype.unescapedValue = function unescapedValue (token, context) { 747 var value = context.lookup(token[1]); 748 if (value != null) 749 return value; 750 }; 751 752 Writer.prototype.escapedValue = function escapedValue (token, context) { 753 var value = context.lookup(token[1]); 754 if (value != null) 755 return mustache.escape(value); 756 }; 757 758 Writer.prototype.rawValue = function rawValue (token) { 759 return token[1]; 760 }; 761 762 mustache.name = 'mustache.js'; 763 mustache.version = '3.1.0'; 764 mustache.tags = [ '{{', '}}' ]; 765 766 // All high-level mustache.* functions use this writer. 767 var defaultWriter = new Writer(); 768 769 /** 770 * Clears all cached templates in the default writer. 771 */ 772 mustache.clearCache = function clearCache () { 773 return defaultWriter.clearCache(); 774 }; 775 776 /** 777 * Parses and caches the given template in the default writer and returns the 778 * array of tokens it contains. Doing this ahead of time avoids the need to 779 * parse templates on the fly as they are rendered. 780 */ 781 mustache.parse = function parse (template, tags) { 782 return defaultWriter.parse(template, tags); 783 }; 784 785 /** 786 * Renders the `template` with the given `view` and `partials` using the 787 * default writer. If the optional `tags` argument is given here it must be an 788 * array with two string values: the opening and closing tags used in the 789 * template (e.g. [ "<%", "%>" ]). The default is to mustache.tags. 790 */ 791 mustache.render = function render (template, view, partials, tags) { 792 if (typeof template !== 'string') { 793 throw new TypeError('Invalid template! Template should be a "string" ' + 794 'but "' + typeStr(template) + '" was given as the first ' + 795 'argument for mustache#render(template, view, partials)'); 796 } 797 798 return defaultWriter.render(template, view, partials, tags); 799 }; 800 801 // This is here for backwards compatibility with 0.4.x., 802 /*eslint-disable */ // eslint wants camel cased function name 803 mustache.to_html = function to_html (template, view, partials, send) { 804 /*eslint-enable*/ 805 806 var result = mustache.render(template, view, partials); 807 808 if (isFunction(send)) { 809 send(result); 810 } else { 811 return result; 812 } 813 }; 814 815 // Export the escaping function so that the user may override it. 816 // See https://github.com/janl/mustache.js/issues/244 817 mustache.escape = escapeHtml; 818 819 // Export these mainly for testing, but also for advanced usage. 820 mustache.Scanner = Scanner; 821 mustache.Context = Context; 822 mustache.Writer = Writer; 823 824 return mustache; 825 })); 826 /* jshint ignore:end */
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Wed Jan 22 11:59:49 2025 | Cross-referenced by PHPXref 0.7.1 |