1 2// json2html.js 2.2.1 3// https://www.json2html.com 4// (c) 2006-2022 Crystalline Technologies 5// json2html may be freely distributed under the MIT license. 6 7(function() { 8 9 "use strict"; 10 11 // Baseline setup 12 // -------------- 13 14 // Establish the root object, `window` (`self`) in the browser, `global` 15 // on the server, or `this` in some virtual machines. We use `self` 16 // instead of `window` for `WebWorker` support. 17 var root = typeof self == 'object' && self.self === self && self || 18 typeof global == 'object' && global.global === global && global || 19 this || 20 {}; 21 22 //Components {name:template} 23 var COMPONENTS = {}; 24 25 /* ---------------------------------------- Interactive HTML Object (iHTML) ------------------------------------------------ */ 26 27 function iHTML(html){ 28 29 //Object type 30 this.type = "iHTML"; 31 32 //html 33 this.html = html || ""; 34 35 //associated events 36 this.events = {}; 37 } 38 39 //Append an ihtml object 40 // obj = ihtml OR html string 41 iHTML.prototype.append = function(obj){ 42 43 if(obj) 44 if(obj.type === "iHTML") { 45 46 //Append the html 47 this.html += obj.html; 48 49 //Append the events 50 Object.assign(this.events, obj.events); 51 } 52 53 //Added for chaining 54 return(this); 55 }; 56 57 //Append HTML to this object 58 iHTML.prototype.appendHTML = function(html){ 59 this.html += html; 60 }; 61 62 //Spit out the object as json 63 iHTML.prototype.toJSON = function(){ 64 return({ 65 "html":this.html, 66 "events":this.events 67 }); 68 }; 69 70 /* ---------------------------------------- Tokenizer ------------------------------------------------ */ 71 72 function Tokenizer( tokenizers, doBuild ){ 73 74 if( !(this instanceof Tokenizer ) ) 75 return new Tokenizer( tokenizers, onEnd, onFound ); 76 77 this.tokenizers = tokenizers.splice ? tokenizers : [tokenizers]; 78 if( doBuild ) 79 this.doBuild = doBuild; 80 } 81 82 Tokenizer.prototype.parse = function( src ){ 83 this.src = src; 84 this.ended = false; 85 this.tokens = [ ]; 86 do this.next(); while( !this.ended ); 87 return this.tokens; 88 }; 89 90 Tokenizer.prototype.build = function( src, real ){ 91 if( src ) 92 this.tokens.push( 93 !this.doBuild ? src : 94 this.doBuild(src,real,this.tkn) 95 ); 96 }; 97 98 Tokenizer.prototype.next = function(){ 99 var self = this, 100 plain; 101 102 self.findMin(); 103 plain = self.src.slice(0, self.min); 104 105 self.build( plain, false ); 106 107 self.src = self.src.slice(self.min).replace(self.tkn,function( all ){ 108 self.build(all, true); 109 return ''; 110 }); 111 112 if( !self.src ) 113 self.ended = true; 114 }; 115 116 Tokenizer.prototype.findMin = function(){ 117 var self = this, i=0, tkn, idx; 118 self.min = -1; 119 self.tkn = ''; 120 121 while(( tkn = self.tokenizers[i++]) !== undefined ){ 122 idx = self.src[tkn.test?'search':'indexOf'](tkn); 123 if( idx != -1 && (self.min == -1 || idx < self.min )){ 124 self.tkn = tkn; 125 self.min = idx; 126 } 127 } 128 if( self.min == -1 ) 129 self.min = self.src.length; 130 }; 131 132 /* ---------------------------------------- Public Methods ------------------------------------------------ */ 133 134 if(!root.json2html) root.json2html = {}; 135 136 //Current Version 137 root.json2html.version = "2.2.1"; 138 139 //Render a json2html template 140 // obj : json object to render, or json string 141 // template: json2html template (array or json object) 142 // options : {} 143 // components : {name:template,...} 144 // output : ihtml | html 145 root.json2html.render = function(obj,template,options) { 146 147 //create the default object 148 var out = new iHTML(); 149 150 //Default options 151 var _options = { 152 "output":"html" 153 }; 154 155 //Parse the user defined options 156 if(options) { 157 158 // LEGACY support for events, now output 159 if(options.events) _options.output = "ihtml"; 160 161 //Add the other allowed options 162 _options.components = options.components; 163 _options.data = options.data; 164 165 //Make sure we don't overwrite the default value 166 if(options.output) _options.output = options.output; 167 } 168 169 //Allow for a json string of json object 170 var parsed = obj; 171 172 //Check for a string (JSON string or literal) 173 if(typeof(obj) === "string") {
174 try { 175 parsed = JSON.parse(obj); 176 } catch(e) { 177 //Assume that this is a literal string 178 parsed = obj; 179 } 180 } 181 182 //Set the object to the parsed value 183 // allows for JSON object or a string value of a JSON object or literal 184 obj = parsed; 185 186 //Render if we have a value template (object or array) 187 // and a data object that's not null or undefined 188 if(_typeof(template) === "object" && _typeof(obj) === "object") out = _render(obj, template, _options); 189 190 //Determine what output we need 191 switch(_options.output) { 192 193 case "ihtml": 194 return(out); 195 break; 196 197 //Default to html 198 default: 199 200 return(out.html); 201 break; 202 } 203 }; 204 205 //json2html component methods 206 root.json2html.component = { 207 208 //Add a component (name = string, template = json2html template) 209 //OR function(components) where component is obj with name:template property eg {"name":template,...} 210 "add":function(name,template){ 211 212 //Determine what we're adding 213 switch(typeof(name)) { 214 215 //Multiple components 216 case "object": 217 218 //Components 219 COMPONENTS = _extend(COMPONENTS,name); 220 break; 221 222 //One component 223 case "string": 224 COMPONENTS[name] = template; 225 break; 226 227 //Not supported 228 default: 229 break; 230 } 231 }, 232 233 //Get a component 234 "get":function(name) { 235 return(COMPONENTS[name]); 236 } 237 }; 238 239 //Allow access to the iHTML object 240 root.json2html.iHTML = iHTML; 241 242 //Encode the html string to text 243 root.json2html.toText = function(html) { 244 245 //Check for undefined or null 246 if(html === undefined || html === null) return(""); 247 248 //Otherwise convert to a string and encode HTML components 249 return html.toString() 250 .replace(/&/g, "&") 251 .replace(/</g, "<") 252 .replace(/>/g, ">") 253 .replace(/\"/g, """) 254 .replace(/\'/g, "'") 255 .replace(/\//g, "/"); 256 }; 257 258 //DEPRECATED (use json2html.render instead) 259 root.json2html.transform = root.json2html.render; 260 261 /* ---------------------------------------- jQuery Plugin ------------------------------------------------ */ 262 263 //If jQuery is defined add plugin 264 if(typeof(window) === "object") 265 if(window.jQuery) { 266 (function($){ 267 268 /* ---------------------------------------- Public Methods ------------------------------------------------ */ 269 270 //jQuery render template 271 // obj : json object to render or json string 272 // template: json2html template (array or json object) 273 // options : {} 274 // components : {name:template,...} 275 // data: object passed to jquery events 276 // output : ihtml | html 277 $.json2html = function(obj, template, options) { 278 279 //Make sure we have the json2html base loaded 280 if(typeof json2html === "undefined") return(undefined); 281 282 //Default options 283 var _options = { 284 "output":"ihtml" 285 }; 286 287 //Parse the user defined options 288 if(options) { 289 290 // LEGACY support for eventData, now data 291 if(options.eventData) _options.data = _options.eventData; 292 293 //Add the other allowed options 294 _options.components = options.components; 295 _options.data = options.data; 296 297 //Make sure we don't overwrite the default value 298 if(options.output) _options.output = options.output; 299 } 300 301 //Determine what type of object we want as the output 302 switch(_options.output){ 303 304 //LEGACY 305 case "json2html": 306 307 //iHTML object 308 case "ihtml": 309 310 //set the output as ihtml 311 _options.output = "ihtml"; 312 break; 313 314 //Return raw html (same as calling json2html.render) 315 default: 316 break; 317 } 318 319 return(json2html.render(obj, template, _options)); 320 }; 321 322 //jQuery render template via chaining 323 // obj : json object to render or json string 324 // template: json2html template (array or json object) 325 // options : {} 326 // components : {name:template,...} 327 // method: "append" | "replace" | "prepend"
328 // data: object passed to jquery events 329 $.fn.json2html = function(obj, template, options) { 330 331 //Make sure we have the json2html base loaded 332 if(typeof json2html === "undefined") return(undefined); 333 334 var _options = { 335 336 //Always set the output to ihtml 337 "output":"ihtml", 338 339 //Set the default method 340 "method":"append" 341 }; 342 343 //Parse the user defined options 344 if(options) { 345 346 // LEGACY support for eventData, now data 347 if(options.eventData) _options.data = _options.eventData; 348 349 //Set the method 350 if(options.method) _options.method = options.method; 351 352 // LEGACY support for append,prepend,replace, now method 353 if(options.prepend) _options.method = "prepend"; 354 if(options.replace) _options.method = "replace"; 355 if(options.append) _options.method = "append"; 356 357 //Add the other allowed options 358 _options.components = options.components; 359 _options.data = options.data; 360 } 361 362 //Render each object 363 return this.each(function(){ 364 365 //Render the template and attach to the dom 366 var dom = _dom(json2html.render(obj, template, _options)); 367 368 //Determine how we should add the new content 369 switch(_options.method) { 370 371 //Replace 372 case "replace": 373 $.fn.replaceWith.call($(this),dom.parent); 374 break; 375 376 //Prepend 377 case "prepend": 378 $.fn.prepend.call($(this),dom.parent); 379 break; 380 381 //Default to append 382 default: 383 $.fn.append.call($(this),dom.parent); 384 break; 385 } 386 387 //Throw the json2html.ready events (if any) 388 _onready(dom.ready); 389 }); 390 }; 391 392 //Hydrate the json2html elements with these events 393 $.fn.j2hHydrate = function(events) { 394 395 //Attach the events for each element 396 return this.each(function(){ 397 398 //Attach the events and trigger the onready for this element 399 _onready( _attachEvents($(this),events) ); 400 }); 401 }; 402 403 /* ---------------------------------------- Prviate Methods ------------------------------------------------ */ 404 405 //Trigger the on ready events 406 function _onready(events){ 407 408 //Trigger all the json2html.ready events 409 for(var i=0; i < events.length; i++) 410 events[i].trigger("j2h.ready"); 411 } 412 413 //Add the ihtml object to the dom 414 // returns the parent and ready event object 415 function _dom(ihtml) { 416 417 //Attach the html(string) 418 var parent = $(document.createElement("i")).html(ihtml.html); 419 420 //Attach the events to the parent object in the dom 421 var ready = _attachEvents($(parent),ihtml.events); 422 423 //Get the children to this result 424 return({"parent":$(parent).children(),"ready":ready}); 425 } 426 427 //Attach the events to the children of this element 428 function _attachEvents($parent,events) { 429 430 //Record json2html specific ready events 431 var ready = []; 432 433 //Check the $parent for all j2h events 434 $parent.find("[-j2h-e]").each(function(){ 435 436 //Get the events we should attach to this element 437 var attach = $(this).attr("-j2h-e"); 438 439 //Make sure we have some events to attach 440 if(attach) { 441 442 //split by " " (can contain multiple events per element) 443 var _events = attach.split(" "); 444 445 //Add each event 446 for(var i = 0; i < _events.length; i++) { 447 448 var event = events[_events[i]]; 449 450 //Don't have this event then just skip 451 if(!event) continue; 452 453 //Add the action to the data object 454 event.data.action = event.action; 455 456 //Add to ready 457 switch(event.type) { 458 459 //json2html specific event 460 case "ready": 461 462 //Sepcify that we'll need to trigger these later 463 ready.push($(this)); 464 465 //rename the event to j2h.ready 466 event.type = "j2h.ready"; 467 break; 468 469 //All other jquery events 470 default: 471 break; 472 } 473 474 //otherwise attach the events to the element 475 $(this).on(event.type,event.data,function(e){ 476 477 //attach the jquery event 478 e.data.event = e; 479 480 //call the appropriate method 481 if(_typeof(e.data.action) === "function") e.data.action.call($(this),e.data); 482 }); 483 } 484 } 485 486 //remove the event attribute 487 $(this).removeAttr("-j2h-e"); 488 }); 489 490 //Return the ready events 491 return(ready); 492 } 493 })(window.jQuery); 494 } 495 496 /* ---------------------------------------- Private Methods ------------------------------------------------ */ 497 498 //Render these object(s) using these temlpate(s) 499 function _render(obj, template, options, index, pobj) { 500 501 var ihtml = new iHTML(); 502 503 //Check to see what type of object we're rending 504 switch(_typeof(obj,true)) { 505 506 case "array": 507 508 //Itterrate through the array and render each object 509 var len=obj.length; 510 for(var j=0;j<len;++j) { 511 512 //Render the object using this template depending on the type of object 513 ihtml.append( _renderObj(obj[j], template, options, j, pobj) ); 514 } 515 break; 516 517 //Don't render for undefined or null objects 518 case "undefined": 519 case "null": 520 break; 521 522 //Make sure to allow for literals as well 523 default: 524 525 //Render the object using this template depending on the type of object 526 ihtml.append( _renderObj(obj, template, options, index, pobj) ); 527 break; 528 } 529 530 return(ihtml); 531 } 532 533 //Render an object using this template(s) 534 function _renderObj(obj, template, options, index, pobj) { 535 536 var ihtml = new iHTML(); 537 538 //Check the type of template we want to apply 539 switch(_typeof(template,true)) { 540 541 //Array of templates 542 case "array": 543 544 //Itterate through each template 545 var t_len = template.length; 546 for(var t=0; t < t_len; ++t) { 547 548 //Render the template and append 549 ihtml.append( _renderObj(obj, template[t], options, index) ); 550 } 551 552 break; 553 554 //single template & single object 555 case "object": 556 557 //Support for DEPRECATED obj 558 var fobj = template["{}"] || template.obj; 559 560 //Check to see if this template uses it's own data object 561 // allows us to run the template under a different data object 562 // AND we haven't already got the parent before (in the case of an array) 563 if( _typeof(fobj) === "function" && !pobj) { 564 565 //Set the parent object 566 pobj = obj; 567 568 //Get the new object 569 obj = fobj.call(obj,obj,index); 570 571 //Render the object (might be an array) 572 ihtml.append( _render(obj, template, options, index, pobj) ); 573 } else { 574 575 //Render the component 576 // or html 577 if(template["[]"]) ihtml.append( _component(pobj, obj, template, options, index) ); 578 else ihtml.append( _html(pobj, obj, template, options, index) ); 579 } 580 break; 581 } 582 583 return(ihtml); 584 } 585 586 //Get the property from the object 587 function _get(obj,path){ 588 589 //Split the path into it's seperate components 590 var _path = path.split("."); 591
592 //Set the object we use to query for this name to be the original object 593 var subObj = obj; 594 595 //Parse the object properties 596 var c_len = _path.length; 597 for (var i=0;i<c_len;++i) { 598 599 //Skip if we don't have this part of the path 600 if( _path[i].length > 0 ) { 601 602 //Get the sub object using the path 603 subObj = subObj[_path[i]]; 604 605 //Break if we don't have this sub object 606 if(subObj === null || subObj === undefined) break; 607 } 608 } 609 610 //Return an empty string if we don't have a value 611 if(subObj === null || subObj === undefined) return(""); 612 613 return(subObj); 614 } 615 616 //Get the html value of the object 617 function _getValue(obj, template, key, options, index) { 618 619 var out = ""; 620 621 //Get the template property 622 var prop = template[key]; 623 624 //Check the type of this template property 625 switch(_typeof(prop,true)) { 626 627 //Get the value from the function 628 case "function": 629 630 //Check what typeof value is for the object we're rendering 631 switch(_typeof(obj)) { 632 633 //If this is a json object or array then get the component that we want 634 case "object": 635 636 //Otherwise get the value 637 return( prop.call(obj,obj,index,options.data) ); 638 break; 639 640 //NOT SUPPORTED 641 case "function": 642 case "undefined": 643 case "null": 644 return(""); 645 break; 646 647 //BOOLEAN, NUMBER, BIGINT, STRING, SYMBOL 648 default: 649 650 //Create a new object with the properties (value & index) 651 var _obj = {"value":obj,"index":index,"data":options.data}; 652 return(prop.call(_obj,_obj,index,options.data)); 653 break; 654 } 655 break; 656 657 //Check for short hand ${..} 658 // NOTE that with es6 support short hand is parsed as a template literal 659 // otherwise parsed internally with simple variable replacement 660 case "string": 661 662 //Check to see if we have es6 support with this browser 663 if(json2html.es6) { 664 665 //Use template literals to parse strings 666 667 //Check what typeof value is for the object we're rendering 668 switch(_typeof(obj)) { 669 //If this is an json object then get the value we're looking for 670 case "object": 671 out = json2html.es6.interpolate.call(prop,obj); 672 break; 673 674 //NOT SUPPORTED 675 case "function": 676 case "undefined": 677 case "null": 678 return(""); 679 break; 680 681 //For literal arrays (and single objects) of type 682 //BOOLEAN, NUMBER, BIGINT, STRING, SYMBOL 683 default: 684 685 out = json2html.es6.interpolate.call(prop,{ 686 "value":obj, 687 "index":index 688 }); 689 690 break; 691 } 692 } else { 693 694 //Parse the property string and fill in any tokens using simple variable replacement 695 out = _parse(prop,function(all,path){ 696 697 //Check what typeof value is for the object we're rendering 698 switch(_typeof(obj)) { 699 700 //If this is an json object then get the value we're looking for 701 case "object": 702 return(_get(obj,path)); 703 break; 704 705 //NOT SUPPORTED 706 case "function": 707 case "undefined": 708 case "null": 709 return(""); 710 break; 711 712 //For literal arrays (and single objects) of type 713 //BOOLEAN, NUMBER, BIGINT, STRING, SYMBOL 714 default: 715 716 //Check the path of the shorthand 717 switch(path) { 718 719 //RESERVED word for literal array value 720 case "value": 721 return(obj); 722 break; 723 724 //RESERVED word for literal array value index 725 case "index": 726 727 //Return empty string if we don't have an index 728 // for objects 729 if(index === undefined || index === null) return(""); 730 else return(index); 731 break; 732 } 733 break; 734 } 735 }); 736 } 737 break; 738 739 //Spit out blank 740 case "null": 741 case "undefined": 742 case "object": 743 out = ""; 744 break; 745 746 //Arrays, and other literals 747 default: 748 749 //Get the string representation for this property 750 out = prop.toString(); 751 break; 752 } 753 754 755 return(out); 756 } 757 758 /* ---------------------------------------- Interpolate (Template Literals) -------------------------------------------- */ 759 760 //Extend object 761 // (obj1,obj2,...) 762 // creates a new object with properties of all objects 763 // shallow copy only 764 function _extend(){ 765 766 var out = {}; 767 768 //Itterate over all objects and copy each property 769 // shallow copy only 770 var len = arguments.length; 771 for(var i=0; i < len;i++) 772 for (var prop in arguments[i]) { out[prop] = arguments[i][prop]; } 773 774 return(out); 775 } 776 777 //isArray (fix for IE prior to 9) 778 function _isArray(obj) { 779 return Object.prototype.toString.call(obj) === "[object Array]"; 780 } 781 782 //Typeof helper 783 function _typeof(obj,checkArray) { 784 785 var type = typeof obj; 786 787 //Check what kind of object this is 788 if(type === "object") { 789 790 //Check for null 791 if(obj === null) return("null"); 792 793 //Check for array 794 if(checkArray) 795 if(_isArray(obj)) return("array"); 796 } 797 798 return(type); 799 } 800 801 //Get a new random id 802 function _id() { 803 var S4 = function() { 804 return (((1+Math.random())*0x10000)|0).toString(16).substring(1); 805 }; 806 return (S4()+S4()); 807 } 808 809 //Determines if we have a void element 810 // (No end tag, and must not contain any contents) 811 function _isVoidElement(element) { 812 813 //Determine if we match any of the void elements 814 // as specified by https://www.w3.org/TR/html5/syntax.html#void-elements 815 switch(element) { 816 817 //Allow these void elements 818 case "area": 819 case "base": 820 case "br": 821 case "col": 822 case "command": 823 case "embed": 824 case "hr": 825 case "img": 826 case "input": 827 case "keygen": 828 case "link": 829 case "meta": 830 case "param": 831 case "source": 832 case "track": 833 case "wbr": 834 return(true); 835 break; 836 837 //Otherwise we're not void 838 default: 839 return(false); 840 break; 841 } 842 } 843 844 //Use the tokenizer to parse the str 845 function _parse(str, method) { 846 847 let tokenizer = new Tokenizer([ 848 /\${([\w\.\,\$]+)}/ 849 ],function( src, real, re ){ 850 return real ? src.replace(re,method) : src; 851 } 852 ); 853 854 return(tokenizer.parse(str).join("")); 855 } 856
857 /* ---------------------------------------- Template Types ------------------------------------------------ */ 858 859 //default html type 860 // supports <> and legacy tag 861 // returns iHTML 862 function _html(pobj, obj, template, options, index){ 863 864 //Create a new ihtml object for the parent and it's children 865 var parent = new iHTML(), 866 children = new iHTML(); 867 868 //Set the default html element key 869 // and initialize the events arrau 870 var ele = "<>", 871 events = []; 872 873 //Look into the properties of this template 874 for (var prop in template) { 875 876 switch(prop) { 877 878 //DEPRECATED (use <> instead) 879 case "tag": 880 881 //Signal we're using a deprecated property 882 //TODO output warning?? 883 ele = "tag"; 884 885 //HTML element 886 case "<>": 887 888 //Get the element name (this can be tokenized) 889 parent.name = _getValue(pobj || obj, template, ele, options, index); 890 891 //Create a new element 892 parent.appendHTML("<" + parent.name); 893 break; 894 895 //DEPRECATED (use {} instead) 896 case "obj": 897 898 case "{}": 899 break; 900 901 //Encode text 902 case "text": 903 904 //Determine what kind of object this is 905 // array => NOT SUPPORTED 906 // other => text 907 // Encode the value as text and add it to the children 908 if(!_isArray(template[prop])) children.appendHTML( json2html.toText( _getValue(obj,template,prop,options,index) ) ); 909 910 break; 911 912 //DEPRECATED (use HTML instead) 913 case "children": 914 915 //Encode as HTML 916 // accepts array of children, functions, string, number, boolean 917 case "html": 918 919 //Determine if we have more than one template 920 // array & function => children 921 // other => html 922 switch(_typeof(template[prop],true)) { 923 924 case "array": 925 926 //render the children 927 children.append( _render(obj, template[prop], options, index) ); 928 break; 929 930 case "function": 931 932 //Get the result from the function 933 var temp = template[prop].call(obj, obj, index, options.data, options.$ihtml); 934 935 //Determine what type of result we have 936 switch(_typeof(temp,true)) { 937 938 //Only returned by json2html.render or $.json2html calls 939 case "object": 940 941 //Check the type of object 942 switch(temp.type) { 943 944 //Add the object as a template 945 case "iHTML": 946 children.append(temp); 947 break; 948 949 //Otherwise don't render 950 default: 951 952 break; 953 } 954 955 break; 956 957 //Not supported 958 case "function": 959 case "undefined": 960 case "null": 961 break; 962 963 //Render the array as a string 964 // append to html 965 case "array": 966 children.appendHTML(temp.toString()); 967 break; 968 969 //string, number, boolean, etc.. 970 // append to html 971 default: 972 children.appendHTML(temp); 973 break; 974 } 975 break; 976 977 default: 978 //Get the HTML associated with this element 979 children.appendHTML( _getValue(obj,template,prop,options,index) ); 980 break; 981 } 982 break; 983 984 default: 985 //Add the property as a attribute if it's not a key one 986 var isEvent = false;
987 988 //Check if the first two characters are 'on' then this is an event 989 if( prop.length > 2 ) 990 if( prop.substring(0,2).toLowerCase() === "on" ) { 991 992 //Determine if we should add events 993 if(options.output === "ihtml") { 994 995 //if so then setup the event data 996 var data = { 997 "obj":obj, 998 "data":options.data, 999 "index":index 1000 }; 1001 1002 //create a new id for this event 1003 var id = _id(); 1004 1005 //Add to the events for this element 1006 // we'll add these later using jquery 1007 parent.events[id] = {"type":prop.substring(2),"data":data,"action":template[prop]}; 1008 1009 //Add the event to the list of events for this element 1010 events.push(id); 1011 } 1012 1013 //this is an event 1014 isEvent = true; 1015 } 1016 1017 //If this wasn't an event AND we actually have a value then add it as a property 1018 if(!isEvent){ 1019 //Get the value 1020 var val = _getValue(obj, template, prop, options, index); 1021 1022 //Make sure we have a value 1023 if(val !== undefined) { 1024 var out; 1025 1026 //Determine the output type of this value (wrap with quotes) 1027 if(typeof val === "string") out = '"' + val.replace(/"/g, '"') + '"'; 1028 else out = val; 1029 1030 //create the name value pair 1031 parent.appendHTML(" " + prop + "=" + out); 1032 } 1033 } 1034 break; 1035 } 1036 } 1037 1038 //Insert temporary event property -j2h-e 1039 // with events seperated by a space 1040 // if needed 1041 if(events.length) parent.appendHTML(" -j2h-e='" + events.join(" ") + "'"); 1042 1043 //Check to see if the parent is an html element 1044 // or just a container 1045 if(parent.name) { 1046 1047 //Determine if this is a void element 1048 // shouldn't have any contents 1049 if(_isVoidElement(parent.name)) parent.appendHTML("/>"); 1050 else { 1051 1052 //Close the opening tag 1053 parent.appendHTML(">"); 1054 1055 //add the children 1056 parent.append(children); 1057 1058 //add the closing tag 1059 parent.appendHTML("</" + parent.name + ">"); 1060 } 1061 } else { 1062 1063 //Otherwise we don't have a parent html element 1064 // so just add the children to the empty parent 1065 parent.append(children); 1066 } 1067 1068 return(parent); 1069 } 1070 1071 //component type 1072 // supports [] 1073 // returns iHTML 1074 function _component(pobj, obj, template, options, index) { 1075 1076 //Create a new ihtml object for the parent 1077 var ihtml = new iHTML(); 1078 1079 var component = { 1080 "template":undefined, 1081 "name":undefined 1082 }; 1083 1084 for(var prop in template) { 1085 1086 //Check the property 1087 switch(prop) { 1088 1089 //REQUIRED 1090 case "[]": 1091 1092 //Get the component name (from the parent if we have one) 1093 var name = _getValue(pobj || obj, template, prop, options, index); 1094 1095 //Check for a local component first 1096 if(options.components) component.template = options.components[name]; 1097 1098 //Otherwise check the global components (if we didn't have a local template) 1099 if(!component.template) component.template = COMPONENTS[name]; 1100 1101 //Otherwise ignore 1102 break; 1103 1104 //Embed this template within the component 1105 // if needed 1106 case "html": 1107 1108 //Check what object type of template we allow 1109 switch(_typeof(template.html)) { 1110 1111 //Make sure we have an object or array 1112 case "object": 1113 1114 //Render the children 1115 // make sure to clear the parent 1116 // children don't have access to the parent 1117 options.$ihtml = _render(obj, template.html, options, index); 1118 break; 1119 } 1120 1121 break; 1122 } 1123 } 1124 1125 //If we don't have the component then exit 1126 // template can be an object or array 1127 if(_typeof(component.template) !== "object") return(ihtml); 1128 1129 //render the template and assign to the output 1130 // this template is considered a child to it won't have access to the parent 1131 ihtml.append(_render(obj, component.template, options)); 1132 1133 return(ihtml); 1134 } 1135}()); 1136
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.