index.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. /**
  2. * Expose `parse`.
  3. */
  4. module.exports = parse;
  5. /**
  6. * Tests for browser support.
  7. */
  8. var innerHTMLBug = false;
  9. var bugTestDiv;
  10. if (typeof document !== 'undefined') {
  11. bugTestDiv = document.createElement('div');
  12. // Setup
  13. bugTestDiv.innerHTML = ' <link/><table></table><a href="/a">a</a><input type="checkbox"/>';
  14. // Make sure that link elements get serialized correctly by innerHTML
  15. // This requires a wrapper element in IE
  16. innerHTMLBug = !bugTestDiv.getElementsByTagName('link').length;
  17. bugTestDiv = undefined;
  18. }
  19. /**
  20. * Wrap map from jquery.
  21. */
  22. var map = {
  23. legend: [1, '<fieldset>', '</fieldset>'],
  24. tr: [2, '<table><tbody>', '</tbody></table>'],
  25. col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
  26. // for script/link/style tags to work in IE6-8, you have to wrap
  27. // in a div with a non-whitespace character in front, ha!
  28. _default: innerHTMLBug ? [1, 'X<div>', '</div>'] : [0, '', '']
  29. };
  30. map.td =
  31. map.th = [3, '<table><tbody><tr>', '</tr></tbody></table>'];
  32. map.option =
  33. map.optgroup = [1, '<select multiple="multiple">', '</select>'];
  34. map.thead =
  35. map.tbody =
  36. map.colgroup =
  37. map.caption =
  38. map.tfoot = [1, '<table>', '</table>'];
  39. map.polyline =
  40. map.ellipse =
  41. map.polygon =
  42. map.circle =
  43. map.text =
  44. map.line =
  45. map.path =
  46. map.rect =
  47. map.g = [1, '<svg xmlns="http://www.w3.org/2000/svg" version="1.1">','</svg>'];
  48. /**
  49. * Parse `html` and return a DOM Node instance, which could be a TextNode,
  50. * HTML DOM Node of some kind (<div> for example), or a DocumentFragment
  51. * instance, depending on the contents of the `html` string.
  52. *
  53. * @param {String} html - HTML string to "domify"
  54. * @param {Document} doc - The `document` instance to create the Node for
  55. * @return {DOMNode} the TextNode, DOM Node, or DocumentFragment instance
  56. * @api private
  57. */
  58. function parse(html, doc) {
  59. if ('string' != typeof html) throw new TypeError('String expected');
  60. // default to the global `document` object
  61. if (!doc) doc = document;
  62. // tag name
  63. var m = /<([\w:]+)/.exec(html);
  64. if (!m) return doc.createTextNode(html);
  65. html = html.replace(/^\s+|\s+$/g, ''); // Remove leading/trailing whitespace
  66. var tag = m[1];
  67. // body support
  68. if (tag == 'body') {
  69. var el = doc.createElement('html');
  70. el.innerHTML = html;
  71. return el.removeChild(el.lastChild);
  72. }
  73. // wrap map
  74. var wrap = Object.prototype.hasOwnProperty.call(map, tag) ? map[tag] : map._default;
  75. var depth = wrap[0];
  76. var prefix = wrap[1];
  77. var suffix = wrap[2];
  78. var el = doc.createElement('div');
  79. el.innerHTML = prefix + html + suffix;
  80. while (depth--) el = el.lastChild;
  81. // one element
  82. if (el.firstChild == el.lastChild) {
  83. return el.removeChild(el.firstChild);
  84. }
  85. // several elements
  86. var fragment = doc.createDocumentFragment();
  87. while (el.firstChild) {
  88. fragment.appendChild(el.removeChild(el.firstChild));
  89. }
  90. return fragment;
  91. }