terminal-ui.tag 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. <terminal-ui id={ id } tabindex='1'>
  2. <display-buffer welcome={ welcome } events={ this } />
  3. <command-line prompt={ prompt } events={ this } />
  4. <style>
  5. terminal-ui { outline: none; }
  6. terminal-ui * { padding: 0; margin: 0; line-height: normal; font-size: 100%; }
  7. </style>
  8. /**
  9. * Create a new shell with the class name given to the terminal-ui tag.
  10. * The terminal-ui tag object passes events between the shell and the other tags.
  11. */
  12. var shell = window[opts.shell] ? new window[opts.shell](this) : {}
  13. this.welcome = shell.welcome || opts.welcome
  14. this.prompt = shell.prompt || opts.prompt
  15. this.id = 'term-' + Math.floor(Math.random() * 10000)
  16. </terminal-ui>
  17. <display-buffer>
  18. <div each={ output }>
  19. <raw-html content={ content } />
  20. </div>
  21. var ev = opts.events, self = this
  22. this.contexts = {}
  23. this.output = this.contexts['default'] = []
  24. this.on('mount', function() { this.add(opts.welcome) })
  25. ev.on('disp_add', function(text) { self.add(text) })
  26. ev.on('disp_set', function(text) {
  27. if (text) {
  28. self.clear()
  29. self.add(text)
  30. }
  31. })
  32. ev.on('disp_clear', function() { self.clear() })
  33. ev.on('context_swap', function(name) {
  34. name = name || 'default'
  35. if (!(name in self.contexts)) {
  36. self.contexts[name] = []
  37. }
  38. self.update({ output: self.contexts[name] })
  39. })
  40. add(text) {
  41. if (text) {
  42. this.output.push({ 'content': text })
  43. this.update()
  44. }
  45. }
  46. clear() {
  47. this.output.length = 0
  48. this.update()
  49. }
  50. </display-buffer>
  51. <command-line>
  52. <form autocomplete='off' onsubmit={ process } show={ visible }>
  53. <raw-html name='lhs' content={ prompt } show={ prompt_visible }>
  54. </raw-html><input type='text' name='command' />
  55. </form>
  56. <style>
  57. command-line input[name='command'],
  58. command-line input[name='command']:hover,
  59. command-line input[name='command']:focus {
  60. padding: 0; margin: 0; line-height: normal; font-size: 100%;
  61. background-color: transparent; border: none; outline: none;
  62. height: auto; width: 70%;
  63. display: inline;
  64. }
  65. </style>
  66. var ev = opts.events, self = this
  67. this.contexts = {}
  68. this.current = 'default'
  69. this.contexts[this.current] = {}
  70. this.visible = this.prompt_visible = true
  71. this.prompt = opts.prompt || '$ '
  72. this.on('mount', function() { this.command.focus() })
  73. ev.on('prompt_set', function(text) {
  74. self.prompt = text
  75. self.tags.lhs.write(text)
  76. })
  77. ev.on('prompt_hide', function() { self.update({ prompt_visible: false }) })
  78. ev.on('prompt_show', function() { self.update({ prompt_visible: true }) })
  79. ev.on('cmd_add', function(text) { self.command.value += text })
  80. ev.on('cmd_set', function(text) { self.command.value = text })
  81. ev.on('cli_hide', function() { self.update({ visible: false }) })
  82. ev.on('cli_show', function() {
  83. self.update({ visible: true })
  84. self.command.focus()
  85. })
  86. ev.on('context_swap', function(name) {
  87. name = name || 'default'
  88. // Initialise a new context
  89. if (!(name in self.contexts)) {
  90. self.contexts[name] = { visible: true, prompt: '', prompt_visible: true }
  91. }
  92. // Save current values and load target context
  93. ['visible', 'prompt', 'prompt_visible'].forEach(function(p) {
  94. self.contexts[self.current][p] = self[p]
  95. self[p] = self.contexts[name][p]
  96. })
  97. // Update the display.
  98. self.current = name
  99. self.tags.lhs.write(self.prompt)
  100. if (self.visible) {
  101. self.command.focus()
  102. }
  103. })
  104. process() {
  105. var prompt = this.prompt_visible ? this.prompt : ''
  106. var command = this.encode(this.command.value)
  107. ev.trigger('disp_add', prompt + command + '\n')
  108. ev.trigger('cmd_entered', command)
  109. this.command.value = ''
  110. // Refocus to scroll display and keep input in view.
  111. this.command.blur()
  112. this.command.focus()
  113. }
  114. encode(text) {
  115. return text.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;')
  116. }
  117. </command-line>
  118. <raw-html>
  119. <span></span>
  120. <style>
  121. raw-html { white-space: pre-wrap }
  122. </style>
  123. // Set initial html using `content` option, and...
  124. this.on('mount', function() { this.write(opts.content) })
  125. // Call `write()` manually to update the html.
  126. write(text) { this.root.innerHTML = text }
  127. </raw-html>