terminal-ui.tag 4.3 KB

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