|
|
@@ -1,87 +1,3 @@
|
|
|
-/**
|
|
|
- * # Terminal Riot Tag
|
|
|
- *
|
|
|
- * A pretend commandline interface capable of displaying output from a "shell"
|
|
|
- * Javascript class. Multiple tags can be used on a page, each will work
|
|
|
- * completely independently.
|
|
|
- *
|
|
|
- * ## Dependencies
|
|
|
- *
|
|
|
- * - Riot 2.3+ (http://riotjs.com/)
|
|
|
- *
|
|
|
- * ## Usage
|
|
|
- *
|
|
|
- * <terminal shell='myshellclass' welcome='text' prompt='text'></terminal>
|
|
|
- *
|
|
|
- * <script src='riot+compiler.min.js'></script>
|
|
|
- * <script src='myshell.js'></script>
|
|
|
- * <script src='terminal.tag' type='riot/tag'></script>
|
|
|
- * <script>riot.mount('terminal')</script>
|
|
|
- *
|
|
|
- * ## Configuring
|
|
|
- *
|
|
|
- * The terminal tag accepts 3 optional parameters:
|
|
|
- *
|
|
|
- * - `shell` - Text specifying the shell class to interact with.
|
|
|
- * - `welcome` - Text/HTML displayed when a terminal is first mounted.
|
|
|
- * - `prompt` - Text/HTML before the commandline input. Defaults to `'$ '`.
|
|
|
- *
|
|
|
- * With no shell logic, the terminal tag will simply print commands entered.
|
|
|
- *
|
|
|
- * Note: `welcome` and `prompt` can also be specified in the shell. Shell values
|
|
|
- * take priority over parameter values.
|
|
|
- *
|
|
|
- * ## Making A Shell Class
|
|
|
- *
|
|
|
- * A shell class should be defined before the tag is mounted by riot. It should
|
|
|
- * expect a single parameter (the terminal tag itself) which will be an
|
|
|
- * observable object.
|
|
|
- *
|
|
|
- * This observable will emit `'cmd_entered'` events containing input for
|
|
|
- * processing. Here is a minimal shell:
|
|
|
- *
|
|
|
- * // Contents of myshell.js
|
|
|
- * function myshellclass(events) {
|
|
|
- * this.prompt = ''
|
|
|
- * this.welcome = ''
|
|
|
- * events.on('cmd_entered', function(input) {
|
|
|
- * // Do processing
|
|
|
- * })
|
|
|
- * }
|
|
|
- *
|
|
|
- * ### Events
|
|
|
- *
|
|
|
- * The observable provides events to make things happen:
|
|
|
- *
|
|
|
- * events.trigger('disp_add', text) // Append `text` to the display
|
|
|
- * events.trigger('disp_set', text) // Display only `text`
|
|
|
- * events.trigger('disp_clear') // Clear the display
|
|
|
- * events.trigger('prompt_set', text) // Change the prompt to `text`
|
|
|
- * events.trigger('prompt_hide') // Hide the command prompt
|
|
|
- * events.trigger('prompt_show') // Show the command prompt
|
|
|
- * events.trigger('cmd_add', text) // Append `text` to the command line
|
|
|
- * events.trigger('cmd_set', text) // Set the command line to `text`
|
|
|
- * events.trigger('cli_hide') // Hide the command line and prompt
|
|
|
- * events.trigger('cli_show') // Show the command line and prompt
|
|
|
- *
|
|
|
- * There is also an event to swap between sets of displays and prompts:
|
|
|
- *
|
|
|
- * events.trigger('context_swap', name)
|
|
|
- *
|
|
|
- * The starting context name is `'default'`. Calling `'context_swap'` with:
|
|
|
- *
|
|
|
- * - a new name - initialises a new, empty set.
|
|
|
- * - an existing name - loads that named set.
|
|
|
- * - no name - returns to the `'default'` set.
|
|
|
- *
|
|
|
- * ### Terminal ID
|
|
|
- *
|
|
|
- * The observable also provides the id of the terminal tag via an `id` property.
|
|
|
- * This can be used, for example, for attaching handlers:
|
|
|
- *
|
|
|
- * document.getElementById(events.id).onkeypress = function() {}
|
|
|
- *
|
|
|
- */
|
|
|
<terminal id={ id } tabindex='1'>
|
|
|
<display welcome={ welcome } events={ this } />
|
|
|
<commandline prompt={ prompt } events={ this } />
|
|
|
@@ -106,18 +22,13 @@
|
|
|
<raw content={ content } />
|
|
|
</div>
|
|
|
|
|
|
- var ev = opts.events
|
|
|
- var self = this
|
|
|
+ var ev = opts.events, self = this
|
|
|
this.contexts = {}
|
|
|
this.output = this.contexts['default'] = []
|
|
|
|
|
|
- this.on('mount', function() {
|
|
|
- this.add(opts.welcome)
|
|
|
- })
|
|
|
+ this.on('mount', function() { this.add(opts.welcome) })
|
|
|
|
|
|
- ev.on('disp_add', function(text) {
|
|
|
- self.add(text)
|
|
|
- })
|
|
|
+ ev.on('disp_add', function(text) { self.add(text) })
|
|
|
|
|
|
ev.on('disp_set', function(text) {
|
|
|
if (text) {
|
|
|
@@ -126,9 +37,7 @@
|
|
|
}
|
|
|
})
|
|
|
|
|
|
- ev.on('disp_clear', function() {
|
|
|
- self.clear()
|
|
|
- })
|
|
|
+ ev.on('disp_clear', function() { self.clear() })
|
|
|
|
|
|
ev.on('context_swap', function(name) {
|
|
|
name = name || 'default'
|
|
|
@@ -140,7 +49,6 @@
|
|
|
|
|
|
add(text) {
|
|
|
if (text) {
|
|
|
- text = text.replace(/\r\n|\r|\n/g, '<br />')
|
|
|
this.output.push({ 'content': text })
|
|
|
this.update()
|
|
|
}
|
|
|
@@ -169,42 +77,29 @@
|
|
|
}
|
|
|
</style>
|
|
|
|
|
|
- var ev = opts.events
|
|
|
- var self = this
|
|
|
+ var ev = opts.events, self = this
|
|
|
this.contexts = {}
|
|
|
this.current = 'default'
|
|
|
- this.visible = true
|
|
|
+ this.contexts[this.current] = {}
|
|
|
+ this.visible = this.prompt_visible = true
|
|
|
this.prompt = opts.prompt || '$ '
|
|
|
- this.prompt_visible = true
|
|
|
|
|
|
- this.on('mount', function() {
|
|
|
- this.command.focus()
|
|
|
- })
|
|
|
+ this.on('mount', function() { this.command.focus() })
|
|
|
|
|
|
ev.on('prompt_set', function(text) {
|
|
|
self.prompt = text
|
|
|
self.tags.lhs.write(text)
|
|
|
})
|
|
|
|
|
|
- ev.on('prompt_hide', function() {
|
|
|
- self.update({ prompt_visible: false })
|
|
|
- })
|
|
|
+ ev.on('prompt_hide', function() { self.update({ prompt_visible: false }) })
|
|
|
|
|
|
- ev.on('prompt_show', function() {
|
|
|
- self.update({ prompt_visible: true })
|
|
|
- })
|
|
|
+ ev.on('prompt_show', function() { self.update({ prompt_visible: true }) })
|
|
|
|
|
|
- ev.on('cmd_add', function(text) {
|
|
|
- self.command.value += text
|
|
|
- })
|
|
|
+ ev.on('cmd_add', function(text) { self.command.value += text })
|
|
|
|
|
|
- ev.on('cmd_set', function(text) {
|
|
|
- self.command.value = text
|
|
|
- })
|
|
|
+ ev.on('cmd_set', function(text) { self.command.value = text })
|
|
|
|
|
|
- ev.on('cli_hide', function() {
|
|
|
- self.update({ visible: false })
|
|
|
- })
|
|
|
+ ev.on('cli_hide', function() { self.update({ visible: false }) })
|
|
|
|
|
|
ev.on('cli_show', function() {
|
|
|
self.update({ visible: true })
|
|
|
@@ -213,19 +108,15 @@
|
|
|
|
|
|
ev.on('context_swap', function(name) {
|
|
|
name = name || 'default'
|
|
|
+ // Initialise a new context
|
|
|
if (!(name in self.contexts)) {
|
|
|
self.contexts[name] = { visible: true, prompt: '', prompt_visible: true }
|
|
|
}
|
|
|
- // Save current values.
|
|
|
- self.contexts[self.current] = {
|
|
|
- visible: self.visible,
|
|
|
- prompt: self.prompt,
|
|
|
- prompt_visible: self.prompt_visible
|
|
|
- }
|
|
|
- // Load next context.
|
|
|
- self.visible = self.contexts[name].visible
|
|
|
- self.prompt = self.contexts[name].prompt
|
|
|
- self.prompt_visible = self.contexts[name].prompt_visible
|
|
|
+ // Save current values and load target context
|
|
|
+ ['visible', 'prompt', 'prompt_visible'].forEach(function(p) {
|
|
|
+ self.contexts[self.current][p] = self[p]
|
|
|
+ self[p] = self.contexts[name][p]
|
|
|
+ })
|
|
|
// Update the display.
|
|
|
self.current = name
|
|
|
self.tags.lhs.write(self.prompt)
|
|
|
@@ -240,8 +131,9 @@
|
|
|
ev.trigger('disp_add', prompt + command + '\n')
|
|
|
ev.trigger('cmd_entered', command)
|
|
|
this.command.value = ''
|
|
|
+ // Refocus to scroll display and keep input in view.
|
|
|
this.command.blur()
|
|
|
- this.command.focus() // Refocus to scroll display and keep input in view.
|
|
|
+ this.command.focus()
|
|
|
}
|
|
|
|
|
|
encode(text) {
|
|
|
@@ -257,12 +149,8 @@
|
|
|
</style>
|
|
|
|
|
|
// Set initial html using `content` option, and...
|
|
|
- this.on('mount', function() {
|
|
|
- this.write(opts.content)
|
|
|
- })
|
|
|
+ this.on('mount', function() { this.write(opts.content) })
|
|
|
|
|
|
// Call `write()` manually to update the html.
|
|
|
- write(text) {
|
|
|
- this.root.innerHTML = text
|
|
|
- }
|
|
|
+ write(text) { this.root.innerHTML = text }
|
|
|
</raw>
|