Permalink
Browse files

Bug 720641 (gtgcli): Encapsulate Output object

Didn't want to do this yet, but it's more elegant than the hack to fix
a bug where clicking 'Got It' in the Firefox intro failed to remove the
output properly, and it removes code
- Encapsulate the outputObject literal into an instance of 'Output'
- Move view.populateWithOutputData and toString to Output
- Add onClose and onChange events to Output
- Use these events in output_terminal
- intro now uses Output directly, and can call close()
- ffdisplay adds maybeShowIntro to proxy to intro
  • Loading branch information...
1 parent a45b5ac commit a0b092b4260e9f67f82aac9d0a300dfd6d77427f @joewalker committed Apr 11, 2012
View
@@ -8,7 +8,6 @@ define(function(require, exports, module) {
var util = require('gcli/util');
-var l10n = require('gcli/l10n');
var view = require('gcli/ui/view');
var canon = require('gcli/canon');
@@ -1002,55 +1001,41 @@ Requisition.prototype.exec = function(input) {
typed = typed.replace(/\s*}\s*$/, '');
}
- var outputObject = {
+ var output = new Output({
command: command,
args: args,
typed: typed,
canonical: this.toCanonicalString(),
- completed: false,
- start: new Date()
- };
-
- if (!hidden) {
- this.commandOutputManager.onOutput({ output: outputObject });
- }
-
- var onComplete = function(output, error) {
- outputObject.end = new Date();
- outputObject.duration = outputObject.end.getTime() - outputObject.start.getTime();
- outputObject.error = error;
- outputObject.output = output;
- outputObject.completed = true;
+ hidden: hidden
+ });
- if (!hidden) {
- this.commandOutputManager.onOutput({ output: outputObject });
- }
- }.bind(this);
+ this.commandOutputManager.onOutput({ output: output });
try {
var context = exports.createExecutionContext(this);
var reply = command.exec(args, context);
if (reply != null && reply.isPromise) {
reply.then(
- function(data) { onComplete(data, false); },
- function(error) { onComplete(error, true); });
+ function(data) { output.complete(data); },
+ function(error) { output.error = true; output.complete(error); });
- outputObject.promise = reply;
+ output.promise = reply;
// Add progress to our promise and add a handler for it here
// See bug 659300
}
else {
- onComplete(reply, false);
+ output.complete(reply);
}
}
catch (ex) {
console.error(ex);
- onComplete(ex, true);
+ output.error = true;
+ output.complete(ex);
}
this.update('');
- return outputObject;
+ return output;
};
/**
@@ -1492,6 +1477,100 @@ Requisition.prototype._assign = function(args) {
exports.Requisition = Requisition;
/**
+ * A simple object to hold information about the output of a command
+ */
+function Output(options) {
+ options = options || {};
+ this.command = options.command || '';
+ this.args = options.args || {};
+ this.typed = options.typed || '';
+ this.canonical = options.canonical || '';
+ this.hidden = options.hidden === true ? true : false;
+
+ this.data = undefined;
+ this.completed = false;
+ this.error = false;
+ this.start = new Date();
+
+ this.onClose = util.createEvent('Output.onClose');
+ this.onChange = util.createEvent('Output.onChange');
+}
+
+/**
+ * Called when there is data to display
+ * @param data
+ */
+Output.prototype.complete = function(data) {
+ this.data = data;
+
+ this.end = new Date();
+ this.duration = this.end.getTime() - this.start.getTime();
+ this.completed = true;
+
+ this.onChange({ output: this });
+};
+
+/**
+ * Convert to a DOM element for display.
+ * @param element The DOM node to which the data should be written. Existing
+ * content of 'element' will be removed before 'outputData' is added.
+ */
+Output.prototype.toDom = function(element) {
+ util.clearElement(element);
+ var document = element.ownerDocument;
+
+ var output = this.data;
+ if (output == null) {
+ return;
+ }
+
+ var node;
+ if (typeof HTMLElement !== 'undefined' && output instanceof HTMLElement) {
+ node = output;
+ }
+ else if (output.isView) {
+ node = output.toDom(document);
+ }
+ else {
+ if (this.command.returnType === 'terminal') {
+ node = util.createElement(document, 'textarea');
+ node.classList.add('gcli-row-terminal');
+ node.readOnly = true;
+ }
+ else {
+ node = util.createElement(document, 'p');
+ }
+
+ util.setContents(node, output.toString());
+ }
+
+ element.appendChild(node);
+};
+
+/**
+ * Convert an this object to a string so GCLI can be used in traditional
+ * character based terminals.
+ */
+Output.prototype.toString = function(document) {
+ var output = this.data;
+ if (output == null) {
+ return '';
+ }
+
+ if (typeof HTMLElement !== 'undefined' && output instanceof HTMLElement) {
+ return output.textContent;
+ }
+
+ if (output.isView) {
+ return output.toDom(document).textContent;
+ }
+
+ return output.toString();
+};
+
+exports.Output = Output;
+
+/**
* Functions and data related to the execution of a command
*/
exports.createExecutionContext = function(requisition) {
View
@@ -1,5 +1,5 @@
-<div save="${hider}">
+<div>
<p>
GCLI is an experiment to create a highly usable <strong>graphical command
line</strong> for developers. It's not a JavaScript
View
@@ -8,8 +8,8 @@ define(function(require, exports, module) {
var settings = require('gcli/settings');
var l10n = require('gcli/l10n');
- var util = require('gcli/util');
var view = require('gcli/ui/view');
+ var Output = require('gcli/cli').Output;
/**
* Record if the user has clicked on 'Got It!'
@@ -41,24 +41,20 @@ define(function(require, exports, module) {
return;
}
- var output = view.createView({
+ var output = new Output();
+ commandOutputManager.onOutput({ output: output });
+
+ var viewData = view.createView({
html: require('text!gcli/ui/intro.html'),
data: {
showHideButton: true,
onGotIt: function(ev) {
hideIntro.value = true;
- this.hider.style.display = 'none';
+ output.onClose();
}
}
});
- commandOutputManager.onOutput({ output: {
- typed: '',
- canonical: '',
- completed: true,
- error: false,
- output: output
- } });
+ output.complete(viewData);
};
-
});
@@ -1,68 +0,0 @@
-/*
- * Copyright 2009-2011 Mozilla Foundation and contributors
- * Licensed under the New BSD license. See LICENSE.txt or:
- * http://opensource.org/licenses/BSD-3-Clause
- */
-
-define(function(require, exports, module) {
-
-var util = require('gcli/util');
-var canon = require('gcli/canon');
-var view = require('gcli/ui/view');
-var outputViewCss = require('text!gcli/ui/output_view.css');
-
-
-/**
- * A wrapper for a set of rows|command outputs.
- * Register with the canon to be notified when commands have output to be
- * displayed.
- * @param options Object containing user customization properties, including:
- * - commandOutputManager
- * @param components Object that links to other UI components. GCLI provided:
- * - element: Root element to populate
- * - requisition (optional): A click/double-click to an input row causes the
- * command to be sent to the input/executed if we know the requisition use
- */
-function OutputSingle(options, components) {
- this.requisition = components.requisition;
-
- this.element = components.element;
- this.element.classList.add('gcli-row-out');
- this.element.setAttribute('aria-live', 'assertive');
-
- this.commandOutputManager = options.commandOutputManager ||
- canon.commandOutputManager;
- this.commandOutputManager.onOutput.add(this.outputChanged, this);
-
- if (outputViewCss != null) {
- var doc = this.element.ownerDocument;
- this.style = util.importCss(outputViewCss, doc, 'gcli-output-view');
- }
-}
-
-/**
- * Avoid memory leaks
- */
-OutputSingle.prototype.destroy = function() {
- if (this.style) {
- this.style.parentNode.removeChild(this.style);
- delete this.style;
- }
-
- this.commandOutputManager.onOutput.remove(this.outputChanged, this);
- delete this.commandOutputManager;
-
- delete this.element;
-};
-
-/**
- * Monitor for new command executions
- */
-OutputSingle.prototype.outputChanged = function(ev) {
- view.populateWithOutputData(ev.output, this.element);
-};
-
-exports.OutputSingle = OutputSingle;
-
-
-});
@@ -10,7 +10,6 @@ var util = require('gcli/util');
var canon = require('gcli/canon');
var domtemplate = require('gcli/ui/domtemplate');
-var view = require('gcli/ui/view');
var outputViewCss = require('text!gcli/ui/output_view.css');
var outputViewHtml = require('text!gcli/ui/output_terminal.html');
@@ -65,10 +64,11 @@ OutputTerminal.prototype.destroy = function() {
* Monitor for new command executions
*/
OutputTerminal.prototype.outputted = function(ev) {
- if (!ev.output.view) {
- ev.output.view = new OutputView(ev.output, this);
+ if (ev.output.hidden) {
+ return;
}
- ev.output.view.onChange(ev);
+
+ ev.output.view = new OutputView(ev.output, this);
};
/**
@@ -106,8 +106,24 @@ function OutputView(outputData, outputTerminal) {
this.outputTerminal.element.appendChild(this.elems.rowin);
this.outputTerminal.element.appendChild(this.elems.rowout);
+
+ this.outputData.onClose.add(this.closed, this);
+ this.outputData.onChange.add(this.changed, this);
}
+OutputView.prototype.destroy = function() {
+ this.outputData.onChange.remove(this.changed, this);
+ this.outputData.onClose.remove(this.closed, this);
+
+ this.outputTerminal.element.removeChild(this.elems.rowin);
+ this.outputTerminal.element.removeChild(this.elems.rowout);
+
+ delete this.outputData;
+ delete this.outputTerminal;
+ delete this.url;
+ delete this.elems;
+};
+
/**
* Only display a prompt if there is a command, otherwise, leave blank
*/
@@ -153,14 +169,11 @@ OutputView.prototype.showOutput = function(ev) {
ev.stopPropagation();
};
-OutputView.prototype.remove = function(ev) {
- this.outputTerminal.element.removeChild(this.elems.rowin);
- this.outputTerminal.element.removeChild(this.elems.rowout);
-
- ev.stopPropagation();
+OutputView.prototype.closed = function(ev) {
+ this.destroy();
};
-OutputView.prototype.onChange = function(ev) {
+OutputView.prototype.changed = function(ev) {
var document = this.elems.rowout.ownerDocument;
var duration = this.outputData.duration != null ?
'completed in ' + (this.outputData.duration / 1000) + ' sec ' :
@@ -175,7 +188,7 @@ OutputView.prototype.onChange = function(ev) {
this.elems.prompt.classList.add('gcli-row-error');
}
- view.populateWithOutputData(this.outputData, this.elems.rowout);
+ this.outputData.toDom(this.elems.rowout);
// We need to see the output of the latest command entered
// Certain browsers have a bug such that scrollHeight is too small
Oops, something went wrong.

0 comments on commit a0b092b

Please sign in to comment.