moving files added since the big move
164
plugins/cockpit/ui/cliView.css
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
|
||||
#cockpit {
|
||||
background: transparent;
|
||||
border: none; outline: none;
|
||||
font-family: consolas, courier, monospace;
|
||||
font-size: 120%;
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.cptOutput {
|
||||
border: 1px solid #AAA;
|
||||
-moz-border-radius-topleft: 10px;
|
||||
-moz-border-radius-topright: 10px;
|
||||
border-top-left-radius: 4px; border-top-right-radius: 4px;
|
||||
padding: 10px;
|
||||
margin: 0 15px;
|
||||
background: #DDD; color: #000;
|
||||
overflow: auto;
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#cockpit:focus ~ .cptOutput {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.cptCompletion {
|
||||
color: #999;
|
||||
padding: 0 0 5px 2px;
|
||||
position: absolute;
|
||||
z-index: -1000;
|
||||
font-family: consolas, courier, monospace;
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
.cptHints {
|
||||
color: #000;
|
||||
position: absolute;
|
||||
border: 1px solid rgba(230, 230, 230, 0.8);
|
||||
background: rgba(250, 250, 250, 0.8);
|
||||
-moz-border-radius-topleft: 10px;
|
||||
-moz-border-radius-topright: 10px;
|
||||
border-top-left-radius: 10px; border-top-right-radius: 10px;
|
||||
z-index: 1000;
|
||||
padding: 8px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cptHints ul { margin: 0; padding: 0 15px; }
|
||||
|
||||
#cockpit:focus ~ .cptHints {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#cockpit:focus ~ .cptHints.cptNoHints {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cptCompletion.VALID { background: #FFF; }
|
||||
.cptCompletion.INCOMPLETE { background: #DDD; }
|
||||
.cptCompletion.INVALID { background: #DDD; }
|
||||
|
||||
.cptCompletion span { color: #FFF; }
|
||||
.cptCompletion span.INCOMPLETE { color: #DDD; border-bottom: 2px dotted #F80; }
|
||||
.cptCompletion span.INVALID { color: #DDD; border-bottom: 2px dotted #F00; }
|
||||
|
||||
span.cptPrompt { color: #66F; font-weight: bold; }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.cptHints article {
|
||||
margin-left: 25px;
|
||||
padding: 8px;
|
||||
z-index: 1;
|
||||
color: @text;
|
||||
display: block;
|
||||
border: 2px @border_bg solid;
|
||||
border-bottom: 0;
|
||||
font-size: 90%;
|
||||
-moz-border-top-colors: @border_bg @border_fg;
|
||||
-moz-border-left-colors: @border_bg @border_fg;
|
||||
-moz-border-right-colors: @border_bg @bg;
|
||||
-moz-border-radius-topleft: 10px;
|
||||
-moz-border-radius-topright: 10px;
|
||||
border-top-left-radius: 10px; border-top-right-radius: 10px;
|
||||
background: @input_bg2;
|
||||
background: -moz-linear-gradient(top, @input_bg_light, @input_bg);
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(@input_bg_light), to(@input_bg));
|
||||
-webkit-box-shadow: rgba(0, 0, 0, 0.5) 0px 1px 10px 3px;
|
||||
-moz-box-shadow: rgba(0, 0, 0, 0.5) 0px 1px 10px 3px;
|
||||
max-width: 500px;
|
||||
}
|
||||
.cptHints article h1 { font-size: 110%; text-align: center; }
|
||||
.cptHints article h2 { font-size: 95%; }
|
||||
.cptHints article h3 { font-size: 90%; }
|
||||
.cptHints article table th,
|
||||
.cptHints article label { color: @hi_text; }
|
||||
.cptHints article h1,
|
||||
.cptHints article h2,
|
||||
.cptHints article h3 { margin: 2px 0 1px 0; color: @hi_text; }
|
||||
.cptHints article p,
|
||||
.cptHints article pre,
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Global visual styles */
|
||||
.cptBrackets { color: @hi_text; }
|
||||
.cptGt { color: @theme_text; font-weight: bold; font-size: 120%; }
|
||||
|
||||
/* Use absolute positioning to put all children 100%x100% */
|
||||
.cptStack {
|
||||
position: relative;
|
||||
}
|
||||
.cptStack > * {
|
||||
position: absolute;
|
||||
top: 0; height: 100%; bottom: 0; left: 0; width: 100%; right: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* The input area */
|
||||
.cptInput {
|
||||
border-top: 1px solid @border_bg;
|
||||
background: @input_bg;
|
||||
background: -moz-linear-gradient(top, @input_bg, @input_bg2);
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(@input_bg), to(@input_bg2));
|
||||
|
||||
position: absolute;
|
||||
height: 25px; right: 0; bottom: 0; left: 0;
|
||||
}
|
||||
|
||||
.cptKbd {
|
||||
position: absolute;
|
||||
top: 0; right: 0; bottom: 0; left: 40px;
|
||||
}
|
||||
|
||||
.cptOutput input.cptCliInput {
|
||||
color: @hi_text; font-size: 120%; font-family: @fonts;
|
||||
background: transparent;
|
||||
outline: none; border: 0;
|
||||
box-shadow: none; -moz-box-shadow: none; -webkit-box-shadow: none;
|
||||
padding: 4px 0 0 0;
|
||||
width: 100%;
|
||||
}
|
||||
.cptOutput input.cptCliInput:focus {
|
||||
outline: none; border: 0;
|
||||
box-shadow: none; -moz-box-shadow: none; -webkit-box-shadow: none;
|
||||
}
|
||||
|
||||
|
||||
369
plugins/cockpit/ui/cliView.js
Normal file
|
|
@ -0,0 +1,369 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Skywriter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Joe Walker (jwalker@mozilla.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
|
||||
var editorCss = require("text!cockpit/ui/cliView.css");
|
||||
var dom = require("pilot/dom");
|
||||
dom.importCssString(editorCss);
|
||||
|
||||
var canon = require("pilot/canon");
|
||||
var Status = require('pilot/types').Status;
|
||||
var keyutil = require('pilot/keyboard/keyutil');
|
||||
|
||||
var CliRequisition = require('cockpit/cli').CliRequisition;
|
||||
var Hint = require('cockpit/cli').Hint;
|
||||
var RequestView = require('cockpit/ui/requestView').RequestView;
|
||||
|
||||
var NO_HINT = new Hint(Status.VALID, '', 0, 0);
|
||||
|
||||
/**
|
||||
* On startup we need to:
|
||||
* 1. Add 3 sets of elements to the DOM for:
|
||||
* - command line output
|
||||
* - input hints
|
||||
* - completion
|
||||
* 2. Attach a set of events so the command line works
|
||||
*/
|
||||
exports.startup = function(data, reason) {
|
||||
var cli = new CliRequisition(data.env);
|
||||
var cliView = new CliView(cli, data.env);
|
||||
};
|
||||
|
||||
/**
|
||||
* A class to handle the simplest UI implementation
|
||||
*/
|
||||
function CliView(cli, env) {
|
||||
this.cli = cli;
|
||||
this.doc = document;
|
||||
this.win = this.doc.defaultView;
|
||||
|
||||
// TODO: we should have a better way to specify command lines???
|
||||
this.element = this.doc.getElementById('cockpit');
|
||||
if (!this.element) {
|
||||
console.log('No element with an id of cockpit. Bailing on cli');
|
||||
return;
|
||||
}
|
||||
|
||||
this.settings = env.settings;
|
||||
this.hintDirection = this.settings.getSetting('hintDirection');
|
||||
this.outputDirection = this.settings.getSetting('outputDirection');
|
||||
this.outputHeight = this.settings.getSetting('outputHeight');
|
||||
|
||||
// If the requisition tells us something has changed, we use this to know
|
||||
// if we should ignore it
|
||||
this.isUpdating = false;
|
||||
|
||||
this.createElements();
|
||||
this.update();
|
||||
}
|
||||
CliView.prototype = {
|
||||
/**
|
||||
* Create divs for completion, hints and output
|
||||
*/
|
||||
createElements: function() {
|
||||
var input = this.element;
|
||||
|
||||
this.completer = this.doc.createElement('div');
|
||||
this.completer.className = 'cptCompletion VALID';
|
||||
input.parentNode.insertBefore(this.completer, input.nextSibling);
|
||||
|
||||
this.hinter = this.doc.createElement('div');
|
||||
this.hinter.className = 'cptHints';
|
||||
input.parentNode.insertBefore(this.hinter, input.nextSibling);
|
||||
|
||||
this.output = this.doc.createElement('div');
|
||||
this.output.className = 'cptOutput';
|
||||
input.parentNode.insertBefore(this.output, input.nextSibling);
|
||||
|
||||
this.win.addEventListener('resize', this.resizer.bind(this), false);
|
||||
this.hintDirection.addEventListener('change', this.resizer.bind(this));
|
||||
this.outputDirection.addEventListener('change', this.resizer.bind(this));
|
||||
this.resizer();
|
||||
|
||||
var setMaxOutputHeight = function() {
|
||||
this.output.style.maxHeight = this.outputHeight.get() + 'px';
|
||||
}.bind(this);
|
||||
this.outputHeight.addEventListener('change', setMaxOutputHeight);
|
||||
setMaxOutputHeight();
|
||||
|
||||
canon.addEventListener('output', function(ev) {
|
||||
new RequestView(ev.request, this);
|
||||
}.bind(this));
|
||||
|
||||
keyutil.addKeyDownListener(input, this.onKeyDown.bind(this));
|
||||
input.addEventListener('keyup', this.onKeyUp.bind(this), true);
|
||||
// cursor position affects hint severity. TODO: shortcuts for speed
|
||||
input.addEventListener('mouseup', function(ev) {
|
||||
this.isUpdating = true;
|
||||
this.update();
|
||||
this.isUpdating = false;
|
||||
}.bind(this), false);
|
||||
|
||||
this.cli.addEventListener('argumentChange', this.onArgChange.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* We need to see the output of the latest command entered
|
||||
*/
|
||||
scrollOutputToBottom: function() {
|
||||
// Certain browsers have a bug such that scrollHeight is too small
|
||||
// when content does not fill the client area of the element
|
||||
var scrollHeight = Math.max(this.output.scrollHeight, this.output.clientHeight);
|
||||
this.output.scrollTop = scrollHeight - this.output.clientHeight;
|
||||
},
|
||||
|
||||
/**
|
||||
* To be called on window resize or any time we want to align the elements
|
||||
* with the input box.
|
||||
*/
|
||||
resizer: function() {
|
||||
var rect = this.element.getClientRects()[0];
|
||||
|
||||
this.completer.style.top = rect.top + 'px';
|
||||
this.completer.style.height = rect.height + 'px';
|
||||
this.completer.style.left = rect.left + 'px';
|
||||
this.completer.style.width = rect.width + 'px';
|
||||
|
||||
if (this.hintDirection.get() === 'below') {
|
||||
this.hinter.style.top = rect.bottom + 'px';
|
||||
this.hinter.style.bottom = 'auto';
|
||||
}
|
||||
else {
|
||||
this.hinter.style.top = 'auto';
|
||||
this.hinter.style.bottom = (this.win.innerHeight - rect.top) + 'px';
|
||||
}
|
||||
this.hinter.style.left = (rect.left + 30) + 'px';
|
||||
this.hinter.style.maxWidth = (rect.width - 110) + 'px';
|
||||
|
||||
if (this.outputDirection.get() === 'below') {
|
||||
this.output.style.top = rect.bottom + 'px';
|
||||
this.output.style.bottom = 'auto';
|
||||
}
|
||||
else {
|
||||
this.output.style.top = 'auto';
|
||||
this.output.style.bottom = (this.win.innerHeight - rect.top) + 'px';
|
||||
}
|
||||
this.output.style.left = rect.left + 'px';
|
||||
this.output.style.width = (rect.width - 80) + 'px';
|
||||
},
|
||||
|
||||
/**
|
||||
* Ensure that TAB isn't handled by the browser
|
||||
*/
|
||||
onKeyDown: function(ev) {
|
||||
var handled;
|
||||
// var handled = keyboardManager.processKeyEvent(ev, this, {
|
||||
// isCommandLine: true, isKeyUp: false
|
||||
// });
|
||||
if (ev.keyCode === keyutil.KeyHelper.KEY.TAB ||
|
||||
ev.keyCode === keyutil.KeyHelper.KEY.UP ||
|
||||
ev.keyCode === keyutil.KeyHelper.KEY.DOWN) {
|
||||
return true;
|
||||
}
|
||||
return handled;
|
||||
},
|
||||
|
||||
/**
|
||||
* The main keyboard processing loop
|
||||
*/
|
||||
onKeyUp: function(ev) {
|
||||
var handled;
|
||||
/*
|
||||
var handled = keyboardManager.processKeyEvent(ev, this, {
|
||||
isCommandLine: true, isKeyUp: true
|
||||
});
|
||||
*/
|
||||
|
||||
// RETURN does a special exec/highlight thing
|
||||
if (ev.keyCode === keyutil.KeyHelper.KEY.RETURN) {
|
||||
var worst = this.cli.getWorstHint();
|
||||
// Deny RETURN unless the command might work
|
||||
if (worst.status === Status.VALID) {
|
||||
this.cli.exec();
|
||||
this.element.value = '';
|
||||
}
|
||||
else {
|
||||
// If we've denied RETURN because the command was not VALID,
|
||||
// select the part of the command line that is causing problems
|
||||
// TODO: if there are 2 errors are we picking the right one?
|
||||
this.element.selectionStart = worst.start;
|
||||
this.element.selectionEnd = worst.end;
|
||||
}
|
||||
}
|
||||
|
||||
this.update();
|
||||
|
||||
// Special actions which delegate to the assignment
|
||||
var current = this.cli.getAssignmentAt(this.element.selectionStart);
|
||||
if (current) {
|
||||
// TAB does a special complete thing
|
||||
if (ev.keyCode === keyutil.KeyHelper.KEY.TAB) {
|
||||
current.complete();
|
||||
this.update();
|
||||
}
|
||||
|
||||
// UP/DOWN look for some history
|
||||
if (ev.keyCode === keyutil.KeyHelper.KEY.UP) {
|
||||
current.increment();
|
||||
this.update();
|
||||
}
|
||||
if (ev.keyCode === keyutil.KeyHelper.KEY.DOWN) {
|
||||
current.decrement();
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
|
||||
return handled;
|
||||
},
|
||||
|
||||
/**
|
||||
* Actually parse the input and make sure we're all up to date
|
||||
*/
|
||||
update: function() {
|
||||
this.isUpdating = true;
|
||||
var input = {
|
||||
typed: this.element.value,
|
||||
cursor: {
|
||||
start: this.element.selectionStart,
|
||||
end: this.element.selectionEnd
|
||||
}
|
||||
};
|
||||
this.cli.update(input);
|
||||
|
||||
var display = this.cli.getAssignmentAt(input.cursor.start).getHint();
|
||||
|
||||
// 1. Update the completer with prompt/error marker/TAB info
|
||||
this.completer.classList.remove(Status.VALID.toString());
|
||||
this.completer.classList.remove(Status.INCOMPLETE.toString());
|
||||
this.completer.classList.remove(Status.INVALID.toString());
|
||||
// TODO: borked implementation? This is modern browser only. Fix
|
||||
// dom.removeCssClass(completer, Status.VALID.toString());
|
||||
// dom.removeCssClass(completer, Status.INCOMPLETE.toString());
|
||||
// dom.removeCssClass(completer, Status.INVALID.toString());
|
||||
|
||||
var completion = '<span class="cptPrompt">></span> ';
|
||||
if (this.element.value.length > 0) {
|
||||
var scores = this.cli.getInputStatusMarkup();
|
||||
completion += this.markupStatusScore(scores);
|
||||
}
|
||||
|
||||
// Display the "-> prediction" at the end of the completer
|
||||
if (this.element.value.length > 0 &&
|
||||
display.predictions && display.predictions.length > 0) {
|
||||
var tab = display.predictions[0];
|
||||
completion += ' ⇥ ' + (tab.name ? tab.name : tab);
|
||||
}
|
||||
this.completer.innerHTML = completion;
|
||||
this.completer.classList.add(this.cli.getWorstHint().status.toString());
|
||||
// dom.addCssClass(input, this.cli.getWorstHint().status.toString());
|
||||
|
||||
// 2. Update the hint element
|
||||
var hint = '';
|
||||
if (this.element.value.length !== 0) {
|
||||
hint += display.message;
|
||||
if (display.predictions && display.predictions.length > 0) {
|
||||
hint += ': [ ';
|
||||
display.predictions.forEach(function(prediction) {
|
||||
hint += (prediction.name ? prediction.name : prediction);
|
||||
hint += ' | ';
|
||||
}, this);
|
||||
hint = hint.replace(/\| $/, ']');
|
||||
}
|
||||
}
|
||||
|
||||
this.hinter.innerHTML = hint;
|
||||
if (hint.length === 0) {
|
||||
this.hinter.classList.add('cptNoHints');
|
||||
}
|
||||
else {
|
||||
this.hinter.classList.remove('cptNoHints');
|
||||
}
|
||||
|
||||
this.isUpdating = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Markup an array of Status values with spans
|
||||
*/
|
||||
markupStatusScore: function(scores) {
|
||||
var completion = '';
|
||||
// Create mark-up
|
||||
var i = 0;
|
||||
var lastStatus = -1;
|
||||
while (true) {
|
||||
if (lastStatus !== scores[i]) {
|
||||
completion += '<span class=' + scores[i].toString() + '>';
|
||||
lastStatus = scores[i];
|
||||
}
|
||||
completion += this.element.value[i];
|
||||
i++;
|
||||
if (i === this.element.value.length) {
|
||||
completion += '</span>';
|
||||
break;
|
||||
}
|
||||
if (lastStatus !== scores[i]) {
|
||||
completion += '</span>';
|
||||
}
|
||||
}
|
||||
|
||||
return completion;
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the input element to reflect the changed argument
|
||||
*/
|
||||
onArgChange: function(ev) {
|
||||
if (this.isUpdating) {
|
||||
return;
|
||||
}
|
||||
|
||||
var prefix = this.element.value.substring(0, ev.argument.start);
|
||||
var suffix = this.element.value.substring(ev.argument.end);
|
||||
var insert = typeof ev.text === 'string' ? ev.text : ev.text.name;
|
||||
this.element.value = prefix + insert + suffix;
|
||||
// Fix the cursor.
|
||||
var insertEnd = (prefix + insert).length;
|
||||
this.element.selectionStart = insertEnd;
|
||||
this.element.selectionEnd = insertEnd;
|
||||
}
|
||||
};
|
||||
exports.CliView = CliView;
|
||||
|
||||
|
||||
});
|
||||
BIN
plugins/cockpit/ui/images/closer.png
Normal file
|
After Width: | Height: | Size: 669 B |
BIN
plugins/cockpit/ui/images/dot_clear.gif
Normal file
|
After Width: | Height: | Size: 42 B |
BIN
plugins/cockpit/ui/images/minus.png
Normal file
|
After Width: | Height: | Size: 604 B |
BIN
plugins/cockpit/ui/images/pinaction.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
plugins/cockpit/ui/images/pinin.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
plugins/cockpit/ui/images/pinout.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
plugins/cockpit/ui/images/pins.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
plugins/cockpit/ui/images/plus.png
Normal file
|
After Width: | Height: | Size: 635 B |
BIN
plugins/cockpit/ui/images/throbber.gif
Normal file
|
After Width: | Height: | Size: 11 KiB |
39
plugins/cockpit/ui/requestView.css
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
.cptRowIn {
|
||||
display: box; display: -moz-box; display: -webkit-box;
|
||||
box-orient: horizontal; -moz-box-orient: horizontal; -webkit-box-orient: horizontal;
|
||||
box-align: center; -moz-box-align: center; -webkit-box-align: center;
|
||||
color: #333;
|
||||
background-color: #EEE;
|
||||
width: 100%;
|
||||
font-family: consolas, courier, monospace;
|
||||
}
|
||||
.cptRowIn > * { padding-left: 2px; padding-right: 2px; }
|
||||
.cptRowIn > img { cursor: pointer; }
|
||||
.cptHover { display: none; }
|
||||
.cptRowIn:hover > .cptHover { display: block; }
|
||||
.cptRowIn:hover > .cptHover.cptHidden { display: none; }
|
||||
.cptOutTyped {
|
||||
box-flex: 1; -moz-box-flex: 1; -webkit-box-flex: 1;
|
||||
font-weight: bold; color: #000; font-size: 120%;
|
||||
}
|
||||
.cptRowOutput { padding-left: 10px; line-height: 1.2em; }
|
||||
.cptRowOutput strong,
|
||||
.cptRowOutput b,
|
||||
.cptRowOutput th,
|
||||
.cptRowOutput h1,
|
||||
.cptRowOutput h2,
|
||||
.cptRowOutput h3 { color: #000; }
|
||||
.cptRowOutput a { font-weight: bold; color: #666; text-decoration: none; }
|
||||
.cptRowOutput a: hover { text-decoration: underline; cursor: pointer; }
|
||||
.cptRowOutput input[type=password],
|
||||
.cptRowOutput input[type=text],
|
||||
.cptRowOutput textarea {
|
||||
color: #000; font-size: 120%;
|
||||
background: transparent; padding: 3px;
|
||||
border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px;
|
||||
}
|
||||
.cptRowOutput table,
|
||||
.cptRowOutput td,
|
||||
.cptRowOutput th { border: 0; padding: 0 2px; }
|
||||
.cptRowOutput .right { text-align: right; }
|
||||
28
plugins/cockpit/ui/requestView.html
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
<div class=cptRow>
|
||||
<!-- The div for the input (i.e. what was typed) -->
|
||||
<div class="cptRowIn" save="${rowin}"
|
||||
onclick="${copyToInput}"
|
||||
ondblclick="${executeRequest}">
|
||||
|
||||
<!-- What the user actually typed -->
|
||||
<div class="cptGt">> </div>
|
||||
<div class="cptOutTyped">${request.typed}</div>
|
||||
|
||||
<!-- The extra details that appear on hover -->
|
||||
<div class=cptHover save="${duration}"></div>
|
||||
<img class=cptHover onclick="${hideOutput}" save="${hide}"
|
||||
alt="Hide command output" _src="${imagePath}/minus.png"/>
|
||||
<img class="cptHover cptHidden" onclick="${showOutput}" save="${show}"
|
||||
alt="Show command output" _src="${imagePath}/plus.png"/>
|
||||
<img class=cptHover onclick="${remove}"
|
||||
alt="Remove this command from the history" _src="${imagePath}/closer.png"/>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- The div for the command output -->
|
||||
<div class="cptRowOut" save="${rowout}">
|
||||
<div class="cptRowOutput" save="${output}"></div>
|
||||
<img _src="${imagePath}/throbber.gif" save="${throb}"/>
|
||||
</div>
|
||||
</div>
|
||||
151
plugins/cockpit/ui/requestView.js
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Skywriter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Joe Walker (jwalker@mozilla.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
|
||||
var util = require('pilot/util');
|
||||
|
||||
var requestViewCss = require("text!cockpit/ui/requestView.css");
|
||||
var dom = require("pilot/dom");
|
||||
dom.importCssString(requestViewCss);
|
||||
|
||||
var requestViewHtml = require("text!cockpit/ui/requestView.html");
|
||||
var Templater = require("pilot/domtemplate").Templater;
|
||||
|
||||
/**
|
||||
* Pull the HTML into the DOM, but don't add it to the document
|
||||
*/
|
||||
var templates = document.createElement('div');
|
||||
templates.innerHTML = requestViewHtml;
|
||||
var row = templates.querySelector('.cptRow');
|
||||
|
||||
/**
|
||||
* Adds a row to the CLI output display
|
||||
*/
|
||||
function RequestView(request, cliView) {
|
||||
this.request = request;
|
||||
this.cliView = cliView;
|
||||
|
||||
this.imagePath = '/plugins/ace/plugins/cockpit/lib/ui/images';
|
||||
|
||||
// Elements attached to this by the templater. For info only
|
||||
this.rowin = null;
|
||||
this.rowout = null;
|
||||
this.output = null;
|
||||
this.hide = null;
|
||||
this.show = null;
|
||||
this.duration = null;
|
||||
this.throb = null;
|
||||
|
||||
new Templater().processNode(row.cloneNode(true), this);
|
||||
|
||||
this.cliView.output.appendChild(this.rowin);
|
||||
this.cliView.output.appendChild(this.rowout);
|
||||
|
||||
this.request.addEventListener('output', this.onRequestChange.bind(this));
|
||||
};
|
||||
|
||||
RequestView.prototype = {
|
||||
/**
|
||||
* A single click on an invocation line in the console copies the command to
|
||||
* the command line
|
||||
*/
|
||||
copyToInput: function() {
|
||||
this.cliView.element.value = this.request.typed;
|
||||
},
|
||||
|
||||
/**
|
||||
* A double click on an invocation line in the console executes the command
|
||||
*/
|
||||
executeRequest: function(ev) {
|
||||
this.cliView.cli.update({
|
||||
typed: this.request.typed,
|
||||
cursor: { start:0, end:0 }
|
||||
});
|
||||
this.cliView.cli.exec();
|
||||
},
|
||||
|
||||
hideOutput: function(ev) {
|
||||
this.output.style.display = 'none';
|
||||
util.addClass(this.hide, 'cmd_hidden');
|
||||
util.removeClass(this.show, 'cmd_hidden');
|
||||
|
||||
ev.stopPropagation();
|
||||
},
|
||||
|
||||
showOutput: function(ev) {
|
||||
this.output.style.display = 'block';
|
||||
util.removeClass(this.hide, 'cmd_hidden');
|
||||
util.addClass(this.show, 'cmd_hidden');
|
||||
|
||||
ev.stopPropagation();
|
||||
},
|
||||
|
||||
remove: function(ev) {
|
||||
this.cliView.output.removeChild(this.rowin);
|
||||
this.cliView.output.removeChild(this.rowout);
|
||||
ev.stopPropagation();
|
||||
},
|
||||
|
||||
onRequestChange: function(ev) {
|
||||
this.duration.innerHTML = this.request.duration ?
|
||||
'completed in ' + (this.request.duration / 1000) + ' sec ' :
|
||||
'';
|
||||
|
||||
this.output.innerHTML = '';
|
||||
this.request.outputs.forEach(function(output) {
|
||||
var node;
|
||||
if (typeof output == 'string') {
|
||||
node = document.createElement('p');
|
||||
node.innerHTML = output;
|
||||
} else {
|
||||
node = output;
|
||||
}
|
||||
this.output.appendChild(node);
|
||||
}, this);
|
||||
this.cliView.scrollOutputToBottom();
|
||||
|
||||
util.setClass(this.output, 'cmd_error', this.request.error);
|
||||
|
||||
this.throb.style.display = this.request.completed ? 'none' : 'block';
|
||||
}
|
||||
};
|
||||
exports.RequestView = RequestView;
|
||||
|
||||
|
||||
});
|
||||
85
plugins/cockpit/ui/settings.js
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Skywriter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Joe Walker (jwalker@mozilla.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
|
||||
var types = require("pilot/types");
|
||||
var SelectionType = require('pilot/types/basic').SelectionType;
|
||||
|
||||
var direction = new SelectionType({
|
||||
name: 'direction',
|
||||
data: [ 'above', 'below' ]
|
||||
});
|
||||
|
||||
var hintDirectionSetting = {
|
||||
name: "hintDirection",
|
||||
description: "Are hints shown above or below the command line?",
|
||||
type: "direction",
|
||||
defaultValue: "above"
|
||||
};
|
||||
|
||||
var outputDirectionSetting = {
|
||||
name: "outputDirection",
|
||||
description: "Is the output window shown above or below the command line?",
|
||||
type: "direction",
|
||||
defaultValue: "above"
|
||||
};
|
||||
|
||||
var outputHeightSetting = {
|
||||
name: "outputHeight",
|
||||
description: "What height should the output panel be?",
|
||||
type: "number",
|
||||
defaultValue: 300
|
||||
};
|
||||
|
||||
exports.startup = function(data, reason) {
|
||||
types.registerType(direction);
|
||||
data.env.settings.addSetting(hintDirectionSetting);
|
||||
data.env.settings.addSetting(outputDirectionSetting);
|
||||
data.env.settings.addSetting(outputHeightSetting);
|
||||
};
|
||||
|
||||
exports.shutdown = function(data, reason) {
|
||||
types.unregisterType(direction);
|
||||
data.env.settings.removeSetting(hintDirectionSetting);
|
||||
data.env.settings.removeSetting(outputDirectionSetting);
|
||||
data.env.settings.removeSetting(outputHeightSetting);
|
||||
};
|
||||
|
||||
|
||||
});
|
||||