A server-side web framework written in Forth. http://www.1-9-9-1.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

130 lines
4.7KB

  1. /*jslint browser: true*/
  2. (function () {
  3. // Used for giving the page a bit more contrast / interest / edge.
  4. var pretags = Array.prototype.slice.call(document.querySelectorAll("pre"));
  5. function createTab (pre, tabs) {
  6. var lines = pre.innerHTML.split("\n");
  7. var tabname = lines[0].replace(/\\\s+?/, "");
  8. pre.innerHTML = lines.slice(1).join("\n");
  9. pre.setAttribute("data-tab-name", tabname);
  10. var tab = document.createElement("div");
  11. tab.innerHTML = tabname;
  12. tab.onclick = function () {
  13. var browser = this.parentElement.parentElement;
  14. var selected = browser.querySelectorAll(".selected");
  15. selected[0].className = selected[1].className = "";
  16. var file = browser.querySelector("[data-tab-name='" + tabname + "']");
  17. file.className = this.className = "selected";
  18. };
  19. tabs.appendChild(tab);
  20. }
  21. function syntactify (type, content) {
  22. return "<span class='" + type + "'>" + content + "</span>";
  23. }
  24. function parseForth (pre) {
  25. var content = pre.innerHTML;
  26. // Keywords:
  27. content = content.replace(/( (;|1991:)(\s+?|$))|(\/1991 )|(include )|(s\+|\$type|loop|do)/g, function (match) {
  28. return syntactify("keyword", match);
  29. }).replace(/(\n|>)(: \S+)/g, function (match, p1, p2) {
  30. // Special case of word definitions.
  31. return p1 + syntactify("keyword", p2);
  32. });
  33. // Strings:
  34. content = content.replace(/s" .*"/g, function (match) {
  35. return syntactify("string", match);
  36. });
  37. // Numbers:
  38. content = content.replace(/(>|\s+)(\d+)(<|\s+)/g, function (match, p1, p2, p3) {
  39. return p1 + syntactify("number", p2) + p3;
  40. }).replace(/(>|\s+)(\d+)(<|\s+)/g, function (match, p1, p2, p3) {
  41. return p1 + syntactify("number", p2) + p3;
  42. }).replace(/&lt;# #s #&gt;/g, function (match) {
  43. return syntactify("number", match);
  44. });
  45. // Comments:
  46. content = content.replace(/\\\ .*/g, function (match) {
  47. return syntactify("comment", match);
  48. }).replace(/\( .* \)/g, function (match) {
  49. return syntactify("comment", match);
  50. });
  51. pre.innerHTML = content;
  52. }
  53. function parseHTML (pre) {
  54. var content = pre.innerHTML;
  55. // Replace html closing brace.
  56. content = content.replace(/>/g, "&gt;");
  57. // DOCTYPE
  58. content = content.replace(/&lt;!DOCTYPE html&gt;/, function (match) {
  59. return syntactify("comment", match);
  60. });
  61. // Keyword wrappers
  62. content = content.replace(/\$?(&(lt|gt);(\/|\$)?)/g, function (match) {
  63. return syntactify("keyword-wrapper", match);
  64. });
  65. // Keywords
  66. content = content.replace(/(>)(html|head|body|code|title)(<)/g, function (match, p1, p2, p3) {
  67. return p1 + syntactify("keyword", p2) + p3;
  68. }).replace(/(>)(meta)( )/g, function (match, p1, p2, p3) {
  69. return p1 + syntactify("keyword", p2) + p3;
  70. });
  71. pre.innerHTML = content;
  72. }
  73. function parseSyntax (pre) {
  74. var ft = pre.getAttribute("data-tab-name").split(".").slice(-1)[0];
  75. if (ft === "fs") {
  76. parseForth(pre);
  77. } else if (ft === "html") {
  78. parseHTML(pre);
  79. }
  80. }
  81. function convertToBrowser (div) {
  82. div.className = "browser";
  83. var tabs = document.createElement("div");
  84. tabs.className = "tabs";
  85. Array.prototype.forEach.call(div.children, function (pre) {
  86. createTab(pre, tabs);
  87. parseSyntax(pre);
  88. });
  89. div.children[0].className = tabs.children[0].className = "selected";
  90. div.insertBefore(tabs, div.children[0]);
  91. }
  92. function collectPre (siblings) {
  93. var sibling = siblings.slice(-1)[0];
  94. while (sibling) {
  95. sibling = sibling.nextSibling;
  96. if (sibling && sibling.nodeType === 1) {
  97. if (sibling.nodeName.toLowerCase() !== "pre") {
  98. sibling = null;
  99. } else {
  100. break;
  101. }
  102. }
  103. }
  104. if (sibling) {
  105. sibling.parsed = true;
  106. siblings.push(sibling);
  107. return collectPre(siblings);
  108. }
  109. return siblings;
  110. }
  111. pretags.forEach(function (pre) {
  112. if (!pre.parsed) {
  113. var div = document.createElement("div");
  114. pre.parentElement.insertBefore(div, pre);
  115. var allPre = collectPre([pre]);
  116. allPre.forEach(function (p) {
  117. div.appendChild(p);
  118. });
  119. pre.parsed = true;
  120. convertToBrowser(div);
  121. }
  122. });
  123. }());