PageRenderTime 30ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/ajax/libs//1.3.7/defiant.js

https://gitlab.com/Mirros/cdnjs
JavaScript | 879 lines | 637 code | 38 blank | 204 comment | 53 complexity | 3ce1e124bfe7ea9db55e3815cd82b981 MD5 | raw file
  1. /*
  2. * defiant.js [v1.3.6]
  3. * http://www.defiantjs.com
  4. * Copyright (c) 2013-2015, Hakan Bilgin <hbi@longscript.com>
  5. * Licensed under the MIT License
  6. */
  7. /*
  8. * x10.js v0.1.3
  9. * Web worker wrapper with simple interface
  10. *
  11. * Copyright (c) 2013-2015, Hakan Bilgin <hbi@longscript.com>
  12. * Licensed under the MIT License
  13. */
  14. (function(window, undefined) {
  15. //'use strict';
  16. var x10 = {
  17. init: function() {
  18. return this;
  19. },
  20. work_handler: function(event) {
  21. var args = Array.prototype.slice.call(event.data, 1),
  22. func = event.data[0],
  23. ret = tree[func].apply(tree, args);
  24. // return process finish
  25. postMessage([func, ret]);
  26. },
  27. setup: function(tree) {
  28. var url = window.URL || window.webkitURL,
  29. script = 'var tree = {'+ this.parse(tree).join(',') +'};',
  30. blob = new Blob([script + 'self.addEventListener("message", '+ this.work_handler.toString() +', false);'],
  31. {type: 'text/javascript'}),
  32. worker = new Worker(url.createObjectURL(blob));
  33. // thread pipe
  34. worker.onmessage = function(event) {
  35. var args = Array.prototype.slice.call(event.data, 1),
  36. func = event.data[0];
  37. x10.observer.emit('x10:'+ func, args);
  38. };
  39. return worker;
  40. },
  41. call_handler: function(func, worker) {
  42. return function() {
  43. var args = Array.prototype.slice.call(arguments, 0, -1),
  44. callback = arguments[arguments.length-1];
  45. // add method name
  46. args.unshift(func);
  47. // listen for 'done'
  48. x10.observer.on('x10:'+ func, function(event) {
  49. callback(event.detail[0]);
  50. });
  51. // start worker
  52. worker.postMessage(args);
  53. };
  54. },
  55. compile: function(hash) {
  56. var worker = this.setup(typeof(hash) === 'function' ? {func: hash} : hash),
  57. obj = {},
  58. fn;
  59. // create return object
  60. if (typeof(hash) === 'function') {
  61. obj.func = this.call_handler('func', worker);
  62. return obj.func;
  63. } else {
  64. for (fn in hash) {
  65. obj[fn] = this.call_handler(fn, worker);
  66. }
  67. return obj;
  68. }
  69. },
  70. parse: function(tree, isArray) {
  71. var hash = [],
  72. key,
  73. val,
  74. v;
  75. for (key in tree) {
  76. v = tree[key];
  77. // handle null
  78. if (v === null) {
  79. hash.push(key +':null');
  80. continue;
  81. }
  82. // handle undefined
  83. if (v === undefined) {
  84. hash.push(key +':undefined');
  85. continue;
  86. }
  87. switch (v.constructor) {
  88. case Date: val = 'new Date('+ v.valueOf() +')'; break;
  89. case Object: val = '{'+ this.parse(v).join(',') +'}'; break;
  90. case Array: val = '['+ this.parse(v, true).join(',') +']'; break;
  91. case String: val = '"'+ v.replace(/"/g, '\\"') +'"'; break;
  92. case RegExp:
  93. case Function: val = v.toString(); break;
  94. default: val = v;
  95. }
  96. if (isArray) hash.push(val);
  97. else hash.push(key +':'+ val);
  98. }
  99. return hash;
  100. },
  101. // simple event emitter
  102. observer: (function() {
  103. var stack = {};
  104. return {
  105. on: function(type, fn) {
  106. if (!stack[type]) {
  107. stack[type] = [];
  108. }
  109. stack[type].unshift(fn);
  110. },
  111. off: function(type, fn) {
  112. if (!stack[type]) return;
  113. var i = stack[type].indexOf(fn);
  114. stack[type].splice(i,1);
  115. },
  116. emit: function(type, detail) {
  117. if (!stack[type]) return;
  118. var event = {
  119. type : type,
  120. detail : detail,
  121. isCanceled : false,
  122. cancelBubble : function() {
  123. this.isCanceled = true;
  124. }
  125. },
  126. len = stack[type].length;
  127. while(len--) {
  128. if (event.isCanceled) return;
  129. stack[type][len](event);
  130. }
  131. }
  132. };
  133. })()
  134. };
  135. if (typeof module === "undefined") {
  136. // publish x10
  137. window.x10 = x10.init();
  138. } else {
  139. module.exports = x10.init();
  140. }
  141. })(this);
  142. (function(window, module, undefined) {
  143. 'use strict';
  144. var Defiant = {
  145. is_ie : /(msie|trident)/i.test(navigator.userAgent),
  146. is_safari : /safari/i.test(navigator.userAgent),
  147. env : 'production',
  148. xml_decl : '<?xml version="1.0" encoding="utf-8"?>',
  149. namespace : 'xmlns:d="defiant-namespace"',
  150. tabsize : 4,
  151. render: function(template, data) {
  152. var processor = new XSLTProcessor(),
  153. span = document.createElement('span'),
  154. opt = {match: '/'},
  155. tmpltXpath,
  156. scripts,
  157. temp,
  158. sorter;
  159. // handle arguments
  160. switch (typeof(template)) {
  161. case 'object':
  162. this.extend(opt, template);
  163. if (!opt.data) opt.data = data;
  164. break;
  165. case 'string':
  166. opt.template = template;
  167. opt.data = data;
  168. break;
  169. default:
  170. throw 'error';
  171. }
  172. opt.data = JSON.toXML(opt.data);
  173. tmpltXpath = '//xsl:template[@name="'+ opt.template +'"]';
  174. if (!this.xsl_template) this.gatherTemplates();
  175. if (opt.sorter) {
  176. sorter = this.node.selectSingleNode(this.xsl_template, tmpltXpath +'//xsl:for-each//xsl:sort');
  177. if (sorter) {
  178. if (opt.sorter.order) sorter.setAttribute('order', opt.sorter.order);
  179. if (opt.sorter.select) sorter.setAttribute('select', opt.sorter.select);
  180. sorter.setAttribute('data-type', opt.sorter.type || 'text');
  181. }
  182. }
  183. temp = this.node.selectSingleNode(this.xsl_template, tmpltXpath);
  184. temp.setAttribute('match', opt.match);
  185. processor.importStylesheet(this.xsl_template);
  186. span.appendChild(processor.transformToFragment(opt.data, document));
  187. temp.removeAttribute('match');
  188. if (this.is_safari) {
  189. scripts = span.getElementsByTagName('script');
  190. for (var i=0, il=scripts.length; i<il; i++) scripts[i].defer = true;
  191. }
  192. return span.innerHTML;
  193. },
  194. gatherTemplates: function() {
  195. var scripts = document.getElementsByTagName('script'),
  196. str = '',
  197. i = 0,
  198. il = scripts.length;
  199. for (; i<il; i++) {
  200. if (scripts[i].type === 'defiant/xsl-template') str += scripts[i].innerHTML;
  201. }
  202. this.xsl_template = this.xmlFromString('<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" '+ this.namespace +'>'+ str.replace(/defiant:(\w+)/g, '$1') +'</xsl:stylesheet>');
  203. },
  204. getSnapshot: function(data, callback) {
  205. return JSON.toXML(data, callback || true);
  206. },
  207. xmlFromString: function(str) {
  208. var parser,
  209. doc;
  210. str = str.replace(/>\s{1,}</g, '><');
  211. if (str.trim().match(/<\?xml/) === null) {
  212. str = this.xml_decl + str;
  213. }
  214. if (this.is_ie) {
  215. doc = new ActiveXObject('Msxml2.DOMDocument');
  216. doc.loadXML(str);
  217. if (str.indexOf('xsl:stylesheet') === -1) {
  218. doc.setProperty('SelectionLanguage', 'XPath');
  219. }
  220. } else {
  221. parser = new DOMParser();
  222. doc = parser.parseFromString(str, 'text/xml');
  223. }
  224. return doc;
  225. },
  226. extend: function(src, dest) {
  227. for (var content in dest) {
  228. if (!src[content] || typeof(dest[content]) !== 'object') {
  229. src[content] = dest[content];
  230. } else {
  231. this.extend(src[content], dest[content]);
  232. }
  233. }
  234. return src;
  235. },
  236. node: {}
  237. };
  238. // Export
  239. window.Defiant = module.exports = Defiant;
  240. })(
  241. typeof window !== 'undefined' ? window : {},
  242. typeof module !== 'undefined' ? module : {}
  243. );
  244. if (typeof(XSLTProcessor) === 'undefined') {
  245. // emulating XSLT Processor (enough to be used in defiant)
  246. var XSLTProcessor = function() {};
  247. XSLTProcessor.prototype = {
  248. importStylesheet: function(xsldoc) {
  249. this.xsldoc = xsldoc;
  250. },
  251. transformToFragment: function(data, doc) {
  252. var str = data.transformNode(this.xsldoc),
  253. span = document.createElement('span');
  254. span.innerHTML = str;
  255. return span;
  256. }
  257. };
  258. } else if (typeof(XSLTProcessor) !== 'function' && !XSLTProcessor) {
  259. // throw error
  260. throw 'XSLTProcessor transformNode not implemented';
  261. }
  262. // extending STRING
  263. if (!String.prototype.fill) {
  264. String.prototype.fill = function(i,c) {
  265. var str = this;
  266. c = c || ' ';
  267. for (; str.length<i; str+=c){}
  268. return str;
  269. };
  270. }
  271. if (!String.prototype.trim) {
  272. String.prototype.trim = function () {
  273. return this.replace(/^\s+|\s+$/gm, '');
  274. };
  275. }
  276. if (!String.prototype.xTransform) {
  277. String.prototype.xTransform = function () {
  278. var str = this;
  279. if (this.indexOf('translate(') === -1) {
  280. str = this.replace(/contains\(([^,]+),([^\\)]+)\)/g, function(c,h,n) {
  281. var a = 'abcdefghijklmnopqrstuvwxyz',
  282. q = n.trim().slice(-1);
  283. return "contains(translate("+ h +", "+ q + a.toUpperCase() + q +", "+ q + a + q +"),"+ n.toLowerCase() +")";
  284. });
  285. }
  286. return str.toString();
  287. };
  288. }
  289. /* jshint ignore:start */
  290. if (typeof(JSON) === 'undefined') {
  291. window.JSON = {
  292. parse: function (sJSON) { return eval("(" + sJSON + ")"); },
  293. stringify: function (vContent) {
  294. if (vContent instanceof Object) {
  295. var sOutput = "";
  296. if (vContent.constructor === Array) {
  297. for (var nId = 0; nId < vContent.length; sOutput += this.stringify(vContent[nId]) + ",", nId++);
  298. return "[" + sOutput.substr(0, sOutput.length - 1) + "]";
  299. }
  300. if (vContent.toString !== Object.prototype.toString) {
  301. return "\"" + vContent.toString().replace(/"/g, "\\$&") + "\"";
  302. }
  303. for (var sProp in vContent) {
  304. sOutput += "\"" + sProp.replace(/"/g, "\\$&") + "\":" + this.stringify(vContent[sProp]) + ",";
  305. }
  306. return "{" + sOutput.substr(0, sOutput.length - 1) + "}";
  307. }
  308. return typeof vContent === "string" ? "\"" + vContent.replace(/"/g, "\\$&") + "\"" : String(vContent);
  309. }
  310. };
  311. }
  312. /* jshint ignore:end */
  313. if (!JSON.toXML) {
  314. JSON.toXML = function(tree, callback) {
  315. 'use strict';
  316. var interpreter = {
  317. map : [],
  318. rx_validate_name : /^(?!xml)[a-z_][\w\d.:]*$/i,
  319. rx_node : /<(.+?)( .*?)>/,
  320. rx_constructor : /<(.+?)( d:contr=".*?")>/,
  321. rx_namespace : / xmlns\:d="defiant\-namespace"/,
  322. rx_data : /(<.+?>)(.*?)(<\/d:data>)/i,
  323. rx_function : /function (\w+)/i,
  324. namespace : 'xmlns:d="defiant-namespace"',
  325. to_xml_str: function(tree) {
  326. return {
  327. str: this.hash_to_xml(null, tree),
  328. map: this.map
  329. };
  330. },
  331. hash_to_xml: function(name, tree, array_child) {
  332. var is_array = tree.constructor === Array,
  333. self = this,
  334. elem = [],
  335. attr = [],
  336. key,
  337. val,
  338. val_is_array,
  339. type,
  340. is_attr,
  341. cname,
  342. constr,
  343. cnName,
  344. i,
  345. il,
  346. fn = function(key, tree) {
  347. val = tree[key];
  348. if (val === null || val === undefined || val.toString() === 'NaN') val = null;
  349. is_attr = key.slice(0,1) === '@';
  350. cname = array_child ? name : key;
  351. if (cname == +cname && tree.constructor !== Object) cname = 'd:item';
  352. if (val === null) {
  353. constr = null;
  354. cnName = false;
  355. } else {
  356. constr = val.constructor;
  357. cnName = constr.toString().match(self.rx_function)[1];
  358. }
  359. if (is_attr) {
  360. attr.push( cname.slice(1) +'="'+ self.escape_xml(val) +'"' );
  361. if (cnName !== 'String') attr.push( 'd:'+ cname.slice(1) +'="'+ cnName +'"' );
  362. } else if (val === null) {
  363. elem.push( self.scalar_to_xml( cname, val ) );
  364. } else {
  365. switch (constr) {
  366. case Function:
  367. // if constructor is function, then it's not a JSON structure
  368. throw 'JSON data should not contain functions. Please check jour structure.';
  369. /* falls through */
  370. case Object:
  371. elem.push( self.hash_to_xml( cname, val ) );
  372. break;
  373. case Array:
  374. if (key === cname) {
  375. val_is_array = val.constructor === Array;
  376. if (val_is_array) {
  377. i = val.length;
  378. while (i--) {
  379. if (val[i] === null || !val[i] || val[i].constructor === Array) val_is_array = true;
  380. if (!val_is_array && val[i].constructor === Object) val_is_array = true;
  381. }
  382. }
  383. elem.push( self.scalar_to_xml( cname, val, val_is_array ) );
  384. break;
  385. }
  386. /* falls through */
  387. case String:
  388. if (typeof(val) === 'string') {
  389. val = val.toString().replace(/\&/g, '&amp;')
  390. .replace(/\r|\n/g, '&#13;');
  391. }
  392. if (cname === '#text') {
  393. // prepare map
  394. self.map.push(tree);
  395. attr.push('d:mi="'+ self.map.length +'"');
  396. attr.push('d:constr="'+ cnName +'"');
  397. elem.push( self.escape_xml(val) );
  398. break;
  399. }
  400. /* falls through */
  401. case Number:
  402. case Boolean:
  403. if (cname === '#text' && cnName !== 'String') {
  404. // prepare map
  405. self.map.push(tree);
  406. attr.push('d:mi="'+ self.map.length +'"');
  407. attr.push('d:constr="'+ cnName +'"');
  408. elem.push( self.escape_xml(val) );
  409. break;
  410. }
  411. elem.push( self.scalar_to_xml( cname, val ) );
  412. break;
  413. }
  414. }
  415. };
  416. if (tree.constructor === Array) {
  417. i = 0;
  418. il = tree.length;
  419. for (; i<il; i++) {
  420. fn(i.toString(), tree);
  421. }
  422. } else {
  423. for (key in tree) {
  424. fn(key, tree);
  425. }
  426. }
  427. if (!name) {
  428. name = 'd:data';
  429. attr.push(this.namespace);
  430. if (is_array) attr.push('d:constr="Array"');
  431. }
  432. if (name.match(this.rx_validate_name) === null) {
  433. attr.push( 'd:name="'+ name +'"' );
  434. name = 'd:name';
  435. }
  436. if (array_child) return elem.join('');
  437. // prepare map
  438. this.map.push(tree);
  439. attr.push('d:mi="'+ this.map.length +'"');
  440. return '<'+ name + (attr.length ? ' '+ attr.join(' ') : '') + (elem.length ? '>'+ elem.join('') +'</'+ name +'>' : '/>' );
  441. },
  442. scalar_to_xml: function(name, val, override) {
  443. var attr = '',
  444. text,
  445. constr,
  446. cnName;
  447. // check whether the nodename is valid
  448. if (name.match(this.rx_validate_name) === null) {
  449. attr += ' d:name="'+ name +'"';
  450. name = 'd:name';
  451. override = false;
  452. }
  453. if (val === null || val.toString() === 'NaN') val = null;
  454. if (val === null) return '<'+ name +' d:constr="null"/>';
  455. if (val.length === 1 && val[0].constructor === Object) {
  456. text = this.hash_to_xml(false, val[0]);
  457. var a1 = text.match(this.rx_node),
  458. a2 = text.match(this.rx_constructor);
  459. a1 = (a1 !== null)? a1[2]
  460. .replace(this.rx_namespace, '')
  461. .replace(/>/, '')
  462. .replace(/"\/$/, '"') : '';
  463. a2 = (a2 !== null)? a2[2] : '';
  464. text = text.match(this.rx_data);
  465. text = (text !== null)? text[2] : '';
  466. return '<'+ name + a1 +' '+ a2 +' d:type="ArrayItem">'+ text +'</'+ name +'>';
  467. } else if (val.length === 0 && val.constructor === Array) {
  468. return '<'+ name +' d:constr="Array"/>';
  469. }
  470. // else
  471. if (override) {
  472. return this.hash_to_xml( name, val, true );
  473. }
  474. constr = val.constructor;
  475. cnName = constr.toString().match(this.rx_function)[1];
  476. text = (constr === Array) ? this.hash_to_xml( 'd:item', val, true )
  477. : this.escape_xml(val);
  478. attr += ' d:constr="'+ cnName +'"';
  479. // prepare map
  480. this.map.push(val);
  481. attr += ' d:mi="'+ this.map.length +'"';
  482. return (name === '#text') ? this.escape_xml(val) : '<'+ name + attr +'>'+ text +'</'+ name +'>';
  483. },
  484. escape_xml: function(text) {
  485. return String(text) .replace(/</g, '&lt;')
  486. .replace(/>/g, '&gt;')
  487. .replace(/"/g, '&quot;')
  488. .replace(/&nbsp;/g, '&#160;');
  489. }
  490. },
  491. processed,
  492. doc,
  493. task;
  494. // depending on request
  495. switch (typeof callback) {
  496. case 'function':
  497. // compile interpreter with 'x10.js'
  498. task = x10.compile(interpreter);
  499. // parse in a dedicated thread
  500. task.to_xml_str(tree, function(processed) {
  501. // snapshot distinctly improves performance
  502. callback({
  503. doc: Defiant.xmlFromString(processed.str),
  504. src: tree,
  505. map: processed.map
  506. });
  507. });
  508. return;
  509. case 'boolean':
  510. processed = interpreter.to_xml_str.call(interpreter, tree);
  511. // return snapshot
  512. return {
  513. doc: Defiant.xmlFromString(processed.str),
  514. src: tree,
  515. map: processed.map
  516. };
  517. default:
  518. processed = interpreter.to_xml_str.call(interpreter, tree);
  519. doc = Defiant.xmlFromString(processed.str);
  520. this.search.map = processed.map;
  521. return doc;
  522. }
  523. };
  524. }
  525. if (!JSON.search) {
  526. JSON.search = function(tree, xpath, single) {
  527. 'use strict';
  528. var isSnapshot = tree.doc && tree.doc.nodeType,
  529. doc = isSnapshot ? tree.doc : JSON.toXML(tree),
  530. map = isSnapshot ? tree.map : this.search.map,
  531. src = isSnapshot ? tree.src : tree,
  532. xres = Defiant.node[ single ? 'selectSingleNode' : 'selectNodes' ](doc, xpath.xTransform()),
  533. ret = [],
  534. mapIndex,
  535. i;
  536. if (single) xres = [xres];
  537. i = xres.length;
  538. while (i--) {
  539. switch(xres[i].nodeType) {
  540. case 2:
  541. case 3:
  542. ret.unshift( xres[i].nodeValue );
  543. break;
  544. default:
  545. mapIndex = +xres[i].getAttribute('d:mi');
  546. //if (map[mapIndex-1] !== false) {
  547. ret.unshift( map[mapIndex-1] );
  548. //}
  549. }
  550. }
  551. // if environment = development, add search tracing
  552. if (Defiant.env === 'development') {
  553. this.trace = JSON.mtrace(src, ret, xres);
  554. }
  555. return ret;
  556. };
  557. }
  558. if (!JSON.mtrace) {
  559. JSON.mtrace = function(root, hits, xres) {
  560. 'use strict';
  561. var win = window,
  562. stringify = JSON.stringify,
  563. sroot = stringify( root, null, '\t' ).replace(/\t/g, ''),
  564. trace = [],
  565. i = 0,
  566. il = xres.length,
  567. od = il ? xres[i].ownerDocument.documentElement : false,
  568. map = this.search.map,
  569. hstr,
  570. cConstr,
  571. fIndex = 0,
  572. mIndex,
  573. lStart,
  574. lEnd;
  575. for (; i<il; i++) {
  576. switch (xres[i].nodeType) {
  577. case 2:
  578. cConstr = xres[i].ownerElement ? xres[i].ownerElement.getAttribute('d:'+ xres[i].nodeName) : 'String';
  579. hstr = '"@'+ xres[i].nodeName +'": '+ win[ cConstr ]( hits[i] );
  580. mIndex = sroot.indexOf(hstr);
  581. lEnd = 0;
  582. break;
  583. case 3:
  584. cConstr = xres[i].parentNode.getAttribute('d:constr');
  585. hstr = win[ cConstr ]( hits[i] );
  586. hstr = '"'+ xres[i].parentNode.nodeName +'": '+ (hstr === 'Number' ? hstr : '"'+ hstr +'"');
  587. mIndex = sroot.indexOf(hstr);
  588. lEnd = 0;
  589. break;
  590. default:
  591. if (xres[i] === od) continue;
  592. if (xres[i].getAttribute('d:constr') === 'String' || xres[i].getAttribute('d:constr') === 'Number') {
  593. cConstr = xres[i].getAttribute('d:constr');
  594. hstr = win[ cConstr ]( hits[i] );
  595. mIndex = sroot.indexOf(hstr, fIndex);
  596. hstr = '"'+ xres[i].nodeName +'": '+ (cConstr === 'Number' ? hstr : '"'+ hstr +'"');
  597. lEnd = 0;
  598. fIndex = mIndex + 1;
  599. } else {
  600. hstr = stringify( hits[i], null, '\t' ).replace(/\t/g, '');
  601. mIndex = sroot.indexOf(hstr);
  602. lEnd = hstr.match(/\n/g).length;
  603. }
  604. }
  605. lStart = sroot.substring(0,mIndex).match(/\n/g).length+1;
  606. trace.push([lStart, lEnd]);
  607. }
  608. return trace;
  609. };
  610. }
  611. Defiant.node.selectNodes = function(XNode, XPath) {
  612. if (XNode.evaluate) {
  613. var ns = XNode.createNSResolver(XNode.documentElement),
  614. qI = XNode.evaluate(XPath, XNode, ns, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null),
  615. res = [],
  616. i = 0,
  617. il = qI.snapshotLength;
  618. for (; i<il; i++) {
  619. res.push( qI.snapshotItem(i) );
  620. }
  621. return res;
  622. } else {
  623. return XNode.selectNodes(XPath);
  624. }
  625. };
  626. Defiant.node.selectSingleNode = function(XNode, XPath) {
  627. if (XNode.evaluate) {
  628. var xI = this.selectNodes(XNode, XPath);
  629. return (xI.length > 0)? xI[0] : null;
  630. } else {
  631. return XNode.selectSingleNode(XPath);
  632. }
  633. };
  634. Defiant.node.prettyPrint = function(node) {
  635. var root = Defiant,
  636. tabs = root.tabsize,
  637. decl = root.xml_decl.toLowerCase(),
  638. ser,
  639. xstr;
  640. if (root.is_ie) {
  641. xstr = node.xml;
  642. } else {
  643. ser = new XMLSerializer();
  644. xstr = ser.serializeToString(node);
  645. }
  646. if (root.env !== 'development') {
  647. // if environment is not development, remove defiant related info
  648. xstr = xstr.replace(/ \w+\:d=".*?"| d\:\w+=".*?"/g, '');
  649. }
  650. var str = xstr.trim().replace(/(>)\s*(<)(\/*)/g, '$1\n$2$3'),
  651. lines = str.split('\n'),
  652. indent = -1,
  653. i = 0,
  654. il = lines.length,
  655. start,
  656. end;
  657. for (; i<il; i++) {
  658. if (i === 0 && lines[i].toLowerCase() === decl) continue;
  659. start = lines[i].match(/<[A-Za-z_\:]+.*?>/g) !== null;
  660. //start = lines[i].match(/<[^\/]+>/g) !== null;
  661. end = lines[i].match(/<\/[\w\:]+>/g) !== null;
  662. if (lines[i].match(/<.*?\/>/g) !== null) start = end = true;
  663. if (start) indent++;
  664. lines[i] = String().fill(indent, '\t') + lines[i];
  665. if (start && end) indent--;
  666. if (!start && end) indent--;
  667. }
  668. return lines.join('\n').replace(/\t/g, String().fill(tabs, ' '));
  669. };
  670. Defiant.node.toJSON = function(xnode, stringify) {
  671. 'use strict';
  672. var interpret = function(leaf) {
  673. var obj = {},
  674. win = window,
  675. attr,
  676. type,
  677. item,
  678. cname,
  679. cConstr,
  680. cval,
  681. text,
  682. i, il, a;
  683. switch (leaf.nodeType) {
  684. case 1:
  685. cConstr = leaf.getAttribute('d:constr');
  686. if (cConstr === 'Array') obj = [];
  687. else if (cConstr === 'String' && leaf.textContent === '') obj = '';
  688. attr = leaf.attributes;
  689. i = 0;
  690. il = attr.length;
  691. for (; i<il; i++) {
  692. a = attr.item(i);
  693. if (a.nodeName.match(/\:d|d\:/g) !== null) continue;
  694. cConstr = leaf.getAttribute('d:'+ a.nodeName);
  695. if (cConstr && cConstr !== 'undefined') {
  696. if (a.nodeValue === 'null') cval = null;
  697. else cval = win[ cConstr ]( (a.nodeValue === 'false') ? '' : a.nodeValue );
  698. } else {
  699. cval = a.nodeValue;
  700. }
  701. obj['@'+ a.nodeName] = cval;
  702. }
  703. break;
  704. case 3:
  705. type = leaf.parentNode.getAttribute('d:type');
  706. cval = (type) ? win[ type ]( leaf.nodeValue === 'false' ? '' : leaf.nodeValue ) : leaf.nodeValue;
  707. obj = cval;
  708. break;
  709. }
  710. if (leaf.hasChildNodes()) {
  711. i = 0;
  712. il = leaf.childNodes.length;
  713. for(; i<il; i++) {
  714. item = leaf.childNodes.item(i);
  715. cname = item.nodeName;
  716. attr = leaf.attributes;
  717. if (cname === 'd:name') {
  718. cname = item.getAttribute('d:name');
  719. }
  720. if (cname === '#text') {
  721. cConstr = leaf.getAttribute('d:constr');
  722. if (cConstr === 'undefined') cConstr = undefined;
  723. text = item.textContent || item.text;
  724. cval = cConstr === 'Boolean' && text === 'false' ? '' : text;
  725. if (!cConstr && !attr.length) obj = cval;
  726. else if (cConstr && il === 1) {
  727. obj = win[cConstr](cval);
  728. } else if (!leaf.hasChildNodes()) {
  729. obj[cname] = (cConstr)? win[cConstr](cval) : cval;
  730. } else {
  731. if (attr.length < 3) obj = (cConstr)? win[cConstr](cval) : cval;
  732. else obj[cname] = (cConstr)? win[cConstr](cval) : cval;
  733. }
  734. } else {
  735. if (item.getAttribute('d:constr') === 'null') {
  736. if (obj[cname] && obj[cname].push) obj[cname].push(null);
  737. else if (item.previousSibling) obj[cname] = [obj[cname], null];
  738. else obj[cname] = [obj[cname]];
  739. continue;
  740. }
  741. if (obj[cname]) {
  742. if (obj[cname].push) obj[cname].push(interpret(item));
  743. else obj[cname] = [obj[cname], interpret(item)];
  744. continue;
  745. }
  746. cConstr = item.getAttribute('d:constr');
  747. switch (cConstr) {
  748. case 'null':
  749. if (obj.push) obj.push(null);
  750. else obj[cname] = null;
  751. break;
  752. case 'Array':
  753. //console.log( Defiant.node.prettyPrint(item) );
  754. if (item.parentNode.firstChild === item && cConstr === 'Array' && cname !== 'd:item') {
  755. if (cname === 'd:item' || cConstr === 'Array') {
  756. cval = interpret(item);
  757. obj[cname] = cval.length ? [cval] : cval;
  758. } else {
  759. obj[cname] = interpret(item);
  760. }
  761. }
  762. else if (obj.push) obj.push( interpret(item) );
  763. else obj[cname] = interpret(item);
  764. break;
  765. case 'String':
  766. case 'Number':
  767. case 'Boolean':
  768. text = item.textContent || item.text;
  769. cval = cConstr === 'Boolean' && text === 'false' ? '' : text;
  770. if (obj.push) obj.push( win[cConstr](cval) );
  771. else obj[cname] = interpret(item);
  772. break;
  773. default:
  774. if (obj.push) obj.push( interpret( item ) );
  775. else obj[cname] = interpret( item );
  776. }
  777. }
  778. }
  779. }
  780. if (leaf.nodeType === 1 && leaf.getAttribute('d:type') === 'ArrayItem') {
  781. obj = [obj];
  782. }
  783. return obj;
  784. },
  785. node = (xnode.nodeType === 9) ? xnode.documentElement : xnode,
  786. ret = interpret(node),
  787. rn = ret[node.nodeName];
  788. // exclude root, if "this" is root node
  789. if (node === node.ownerDocument.documentElement && rn && rn.constructor === Array) {
  790. ret = rn;
  791. }
  792. if (stringify && stringify.toString() === 'true') stringify = '\t';
  793. return stringify ? JSON.stringify(ret, null, stringify) : ret;
  794. };
  795. // check if jQuery is present
  796. if (typeof(jQuery) !== 'undefined') {
  797. (function ( $ ) {
  798. 'use strict';
  799. $.fn.defiant = function(template, xpath) {
  800. this.html( Defiant.render(template, xpath) );
  801. return this;
  802. };
  803. }(jQuery));
  804. }