monarch.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /// <reference path="../../node_modules/monaco-editor/monaco.d.ts" />
  2. "use strict";
  3. /*-----------------------------------------
  4. General helpers
  5. ------------------------------------------*/
  6. function clearInnerText(elem) {
  7. elem.innerHTML = "";
  8. }
  9. function getInnerText(elem) {
  10. var text = elem.innerText;
  11. if (!text) text = elem.textContent;
  12. return text;
  13. }
  14. function escapeToHTML(text) {
  15. return text
  16. .replace(/&/g, "&amp;")
  17. .replace(/</g, "&lt;")
  18. .replace(/>/g, "&gt;");
  19. }
  20. function appendInnerText(elem, txt) {
  21. txt = escapeToHTML(txt);
  22. elem.innerHTML += txt;
  23. }
  24. function setInnerText(elem, txt) {
  25. clearInnerText(elem);
  26. appendInnerText(elem, txt);
  27. }
  28. function getTextFromId(id) {
  29. var elem = document.getElementById(id);
  30. if (elem == null) return null;
  31. return getInnerText(elem);
  32. }
  33. /* -----------------------------------------
  34. The main loader for the workbench UI
  35. ------------------------------------------*/
  36. var outputPane = document.getElementById("monarchConsole");
  37. var isDirty = false;
  38. window.onbeforeunload = function (ev) {
  39. if (isDirty) {
  40. return "If you leave this page any unsaved work will be lost.";
  41. }
  42. };
  43. function createLangModel(languageId, text) {
  44. monaco.languages.register({ id: languageId });
  45. var langModel = monaco.editor.createModel(text, "javascript");
  46. var update = function () {
  47. var def = null;
  48. try {
  49. def = eval("(function(){ " + langModel.getValue() + "; })()"); // CodeQL [SM01632] langModel.getValue() is a default value with volatile user modifications. This is an essential functionality for the monarch playground and safe, as no injection is possible.
  50. } catch (err) {
  51. setInnerText(outputPane, err + "\n");
  52. return;
  53. }
  54. monaco.languages.setMonarchTokensProvider(languageId, def);
  55. setInnerText(outputPane, "up-to-date\n");
  56. };
  57. langModel.onDidChangeContent(function () {
  58. isDirty = true;
  59. update();
  60. });
  61. update();
  62. return langModel;
  63. }
  64. function readSamples(sampleSelect) {
  65. var samples = {};
  66. for (var i = 0; i < sampleSelect.options.length; i++) {
  67. var id = sampleSelect.options[i].value;
  68. if (!id || sampleSelect.options[i].disabled) {
  69. continue;
  70. }
  71. var languageId = "monarch-language-" + id;
  72. var sampleText = getTextFromId(id + "-sample");
  73. samples[id] = {
  74. languageId: languageId,
  75. langModel: createLangModel(languageId, getTextFromId(id)),
  76. langViewState: null,
  77. sampleModel: monaco.editor.createModel(sampleText, languageId),
  78. sampleViewState: null,
  79. };
  80. }
  81. return samples;
  82. }
  83. require(["vs/editor/editor.main"], function () {
  84. var sampleSelect = document.getElementById("sampleselect");
  85. var langPane = document.getElementById("langPane");
  86. var editorPane = document.getElementById("editor");
  87. // Adjust height of editors
  88. var screenHeight = window.innerHeight;
  89. if (screenHeight) {
  90. var paneHeight = 0.76 * screenHeight;
  91. langPane.style.height = paneHeight + "px";
  92. editorPane.style.height = paneHeight - 112 + "px"; // 100px + margin 10px + borders 2px
  93. }
  94. var SAMPLES = readSamples(sampleSelect);
  95. var CURRENT_SAMPLE = null;
  96. var langEditor = monaco.editor.create(langPane, {
  97. model: null,
  98. scrollBeyondLastLine: false,
  99. });
  100. var sampleEditor = monaco.editor.create(editorPane, {
  101. model: null,
  102. scrollBeyondLastLine: false,
  103. });
  104. var select = document.getElementById("themeselect");
  105. var currentTheme = "vs";
  106. select.onchange = function () {
  107. currentTheme = select.options[select.selectedIndex].value;
  108. monaco.editor.setTheme(currentTheme);
  109. };
  110. // on resize
  111. function refreshLayout() {
  112. langEditor.layout();
  113. sampleEditor.layout();
  114. }
  115. window.onresize = refreshLayout;
  116. // Switch to another sample
  117. function setEditorState(name) {
  118. if (!name || CURRENT_SAMPLE === name || !SAMPLES[name]) {
  119. return;
  120. }
  121. // Save previous sample's view state
  122. if (CURRENT_SAMPLE) {
  123. SAMPLES[CURRENT_SAMPLE].langViewState = langEditor.saveViewState();
  124. SAMPLES[CURRENT_SAMPLE].sampleViewState =
  125. sampleEditor.saveViewState();
  126. }
  127. CURRENT_SAMPLE = name;
  128. // Apply new sample
  129. langEditor.setModel(SAMPLES[CURRENT_SAMPLE].langModel);
  130. if (SAMPLES[CURRENT_SAMPLE].langViewState) {
  131. langEditor.restoreViewState(SAMPLES[CURRENT_SAMPLE].langViewState);
  132. }
  133. sampleEditor.setModel(SAMPLES[CURRENT_SAMPLE].sampleModel);
  134. if (SAMPLES[CURRENT_SAMPLE].sampleViewState) {
  135. sampleEditor.restoreViewState(
  136. SAMPLES[CURRENT_SAMPLE].sampleViewState
  137. );
  138. }
  139. }
  140. // Refresh the sample text
  141. function refreshSample() {
  142. var name = sampleSelect.options[sampleSelect.selectedIndex].value;
  143. setEditorState(name);
  144. }
  145. sampleSelect.onchange = refreshSample;
  146. refreshSample(); // initialize initial text
  147. }); // require