domConsole.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. export class DOMConsole {
  2. static get USER () {
  3. return 0;
  4. }
  5. static get INFO () {
  6. return 1;
  7. }
  8. static get ERR () {
  9. return 2;
  10. }
  11. static get INPUT () {
  12. return 3;
  13. }
  14. constructor (elementID) {
  15. this.input = null;
  16. this.cursorInterval = null;
  17. this.inputDiv = null;
  18. this.inputCMD = null;
  19. this.inputSpan = null;
  20. this.cursorRef = null;
  21. this.needInput = false;
  22. this.termDiv = null;
  23. this.anyKey = false;
  24. this.parent = $(elementID);
  25. this.setup();
  26. this.inputListeners = [];
  27. this.hideInput();
  28. }
  29. setup () {
  30. this._setupDom();
  31. this._setupEvents();
  32. }
  33. _setupEvents () {
  34. this.input.on("keydown", (event) => {
  35. if (!this.needInput) {
  36. return;
  37. }
  38. const keyCode = event.which;
  39. if (keyCode === 13 || this.anyKey) {
  40. let text = this.input.val();
  41. text = text.replace('[\n\r]+', '');
  42. this.notifyListeners(text);
  43. this._appendUserInput(text);
  44. this.input.val("");
  45. this.inputSpan.text("");
  46. }
  47. });
  48. }
  49. _setupDom () {
  50. this.termDiv = $("<div></div>");
  51. this.termDiv.addClass("ivprog-term-div");
  52. this.inputDiv = $(`
  53. <div id="ivprog-terminal-inputdiv">
  54. <div id="cmd">
  55. <span></span>
  56. <div id="cursor"></div>
  57. </div>
  58. </div>
  59. `);
  60. this.input = $('<input type="text" name="command" value=""/>');
  61. this.inputDiv.append(this.input);
  62. this.cursorRef = $(this.inputDiv.find("#cursor")[0]);
  63. this.inputSpan = $(this.inputDiv.find("#cmd").children('span')[0]);
  64. this.inputCMD = $(this.inputDiv.find("#cmd")[0]);
  65. //this.input.addClass("ivprog-term-input");
  66. this.termDiv.append(this.inputDiv);
  67. this.parent.append(this.termDiv);
  68. this._setupCursor();
  69. }
  70. _setupCursor () {
  71. const outerRef = this
  72. this.inputCMD.click(function() {
  73. if(outerRef.cursorInterval != null) {
  74. return;
  75. }
  76. outerRef.input.focus();
  77. outerRef.cursorInterval = window.setInterval(function() {
  78. if (outerRef.cursorRef.css('visibility') === 'visible') {
  79. outerRef.cursorRef.css({visibility: 'hidden'});
  80. } else {
  81. outerRef.cursorRef.css({visibility: 'visible'});
  82. }
  83. }, 550);
  84. });
  85. this.inputCMD.click();
  86. this.input.keyup(function() {
  87. outerRef.inputSpan.text(outerRef.input.val());
  88. });
  89. this.input.blur(function() {
  90. clearInterval(outerRef.cursorInterval);
  91. outerRef.cursorInterval = null;
  92. outerRef.cursorRef.css({visibility: 'visible'});
  93. });
  94. }
  95. notifyListeners (text) {
  96. this.inputListeners.forEach(resolve => resolve(text));
  97. this.inputListeners.splice(0, this.inputListeners.length);
  98. this.hideInput();
  99. this.anyKey = false;
  100. }
  101. write (text) {
  102. this._appendText(text, DOMConsole.USER);
  103. }
  104. info (text) {
  105. this._appendText(text, DOMConsole.INFO);
  106. }
  107. err (text) {
  108. this._appendText(text, DOMConsole.ERR);
  109. }
  110. _appendText (text, type) {
  111. const divClass = this.getClassForType(type);
  112. const textDiv = $("<div></div>");
  113. textDiv.addClass(divClass);
  114. textDiv.append(text);
  115. textDiv.insertBefore(this.inputDiv);
  116. this.scrollTerm();
  117. }
  118. _appendUserInput (text) {
  119. const divClass = this.getClassForType(DOMConsole.INPUT);
  120. const textDiv = $(`<div>
  121. <i class="icon keyboard outline" style="float:left"></i>
  122. <span>${text}</span>
  123. </div>`);
  124. textDiv.addClass(divClass);
  125. textDiv.insertBefore(this.inputDiv);
  126. this.scrollTerm();
  127. }
  128. scrollTerm () {
  129. this.termDiv.animate({
  130. scrollTop: this.termDiv.prop('scrollHeight')
  131. }, 0);
  132. }
  133. focus () {
  134. this.parent.show();
  135. const prev = this.inputDiv.prev();
  136. if(prev.length > 0)
  137. prev[0].scrollIntoView();
  138. }
  139. hide () {
  140. this.parent.hide();
  141. }
  142. getClassForType (type) {
  143. switch (type) {
  144. case DOMConsole.INPUT:
  145. return "ivprog-term-userInput";
  146. case DOMConsole.USER:
  147. return "ivprog-term-userText";
  148. case DOMConsole.INFO:
  149. return "ivprog-term-info";
  150. case DOMConsole.ERR:
  151. return "ivprog-term-error";
  152. }
  153. }
  154. dispose () {
  155. this.parent.off();
  156. this.input.off();
  157. this.input = null;
  158. this.parent.empty();
  159. if(this.cursorInterval != null) {
  160. clearInterval(this.cursorInterval);
  161. }
  162. this.inputCMD.off();
  163. }
  164. showInput () {
  165. this.needInput = true;
  166. this.inputDiv.show();
  167. this.inputCMD.click();
  168. this.inputCMD[0].scrollIntoView();
  169. }
  170. hideInput () {
  171. this.needInput = false;
  172. this.inputDiv.hide();
  173. clearInterval(this.cursorInterval);
  174. this.cursorInterval = null;
  175. }
  176. requestInput (callback, anyKey = false) {
  177. this.inputListeners.push(callback);
  178. this.anyKey = anyKey;
  179. this.showInput();
  180. }
  181. sendOutput (text) {
  182. const output = ""+text;
  183. output.split("\n").forEach(t => {
  184. t = t.replace(/\t/g,'&#9;');
  185. this.write(t)
  186. });
  187. }
  188. clear () {
  189. this.inputDiv.parent().children().not(this.inputDiv).remove();
  190. this.input.val("");
  191. this.inputSpan.text("");
  192. }
  193. }