In addition to these types, Jetpack also accepts range, member, password - * that we are thinking of adding. - * - *
This module probably should not be accessed directly, but instead used - * through types.js - */ - -/** - * 'text' is the default if no type is given. - */ -var text = new Type(); - -text.stringify = function(value) { - return value; -}; - -text.parse = function(value) { - if (typeof value != 'string') { - throw new Error('non-string passed to text.parse()'); - } - return new Conversion(value); -}; - -text.name = 'text'; - -/** - * We don't currently plan to distinguish between integers and floats - */ -var number = new Type(); - -number.stringify = function(value) { - if (!value) { - return null; - } - return '' + value; -}; - -number.parse = function(value) { - if (typeof value != 'string') { - throw new Error('non-string passed to number.parse()'); - } - - if (value.replace(/\s/g, '').length === 0) { - return new Conversion(null, Status.INCOMPLETE, ''); - } - - var reply = new Conversion(parseInt(value, 10)); - if (isNaN(reply.value)) { - reply.status = Status.INVALID; - reply.message = 'Can\'t convert "' + value + '" to a number.'; - } - - return reply; -}; - -number.decrement = function(value) { - return value - 1; -}; - -number.increment = function(value) { - return value + 1; -}; - -number.name = 'number'; - -/** - * One of a known set of options - */ -function SelectionType(typeSpec) { - if (!Array.isArray(typeSpec.data) && typeof typeSpec.data !== 'function') { - throw new Error('instances of SelectionType need typeSpec.data to be an array or function that returns an array:' + JSON.stringify(typeSpec)); - } - Object.keys(typeSpec).forEach(function(key) { - this[key] = typeSpec[key]; - }, this); -}; - -SelectionType.prototype = new Type(); - -SelectionType.prototype.stringify = function(value) { - return value; -}; - -SelectionType.prototype.parse = function(str) { - if (typeof str != 'string') { - throw new Error('non-string passed to parse()'); - } - if (!this.data) { - throw new Error('Missing data on selection type extension.'); - } - var data = (typeof(this.data) === 'function') ? this.data() : this.data; - - // The matchedValue could be the boolean value false - var hasMatched = false; - var matchedValue; - var completions = []; - data.forEach(function(option) { - if (str == option) { - matchedValue = this.fromString(option); - hasMatched = true; - } - else if (option.indexOf(str) === 0) { - completions.push(this.fromString(option)); - } - }, this); - - if (hasMatched) { - return new Conversion(matchedValue); - } - else { - // This is something of a hack it basically allows us to tell the - // setting type to forget its last setting hack. - if (this.noMatch) { - this.noMatch(); - } - - if (completions.length > 0) { - var msg = 'Possibilities' + - (str.length === 0 ? '' : ' for \'' + str + '\''); - return new Conversion(null, Status.INCOMPLETE, msg, completions); - } - else { - var msg = 'Can\'t use \'' + str + '\'.'; - return new Conversion(null, Status.INVALID, msg, completions); - } - } -}; - -SelectionType.prototype.fromString = function(str) { - return str; -}; - -SelectionType.prototype.decrement = function(value) { - var data = (typeof this.data === 'function') ? this.data() : this.data; - var index; - if (value == null) { - index = data.length - 1; - } - else { - var name = this.stringify(value); - var index = data.indexOf(name); - index = (index === 0 ? data.length - 1 : index - 1); - } - return this.fromString(data[index]); -}; - -SelectionType.prototype.increment = function(value) { - var data = (typeof this.data === 'function') ? this.data() : this.data; - var index; - if (value == null) { - index = 0; - } - else { - var name = this.stringify(value); - var index = data.indexOf(name); - index = (index === data.length - 1 ? 0 : index + 1); - } - return this.fromString(data[index]); -}; - -SelectionType.prototype.name = 'selection'; - -/** - * SelectionType is a base class for other types - */ -exports.SelectionType = SelectionType; - -/** - * true/false values - */ -var bool = new SelectionType({ - name: 'bool', - data: [ 'true', 'false' ], - stringify: function(value) { - return '' + value; - }, - fromString: function(str) { - return str === 'true' ? true : false; - } -}); - - -/** - * A we don't know right now, but hope to soon. - */ -function DeferredType(typeSpec) { - if (typeof typeSpec.defer !== 'function') { - throw new Error('Instances of DeferredType need typeSpec.defer to be a function that returns a type'); - } - Object.keys(typeSpec).forEach(function(key) { - this[key] = typeSpec[key]; - }, this); -}; - -DeferredType.prototype = new Type(); - -DeferredType.prototype.stringify = function(value) { - return this.defer().stringify(value); -}; - -DeferredType.prototype.parse = function(value) { - return this.defer().parse(value); -}; - -DeferredType.prototype.decrement = function(value) { - var deferred = this.defer(); - return (deferred.decrement ? deferred.decrement(value) : undefined); -}; - -DeferredType.prototype.increment = function(value) { - var deferred = this.defer(); - return (deferred.increment ? deferred.increment(value) : undefined); -}; - -DeferredType.prototype.name = 'deferred'; - -/** - * DeferredType is a base class for other types - */ -exports.DeferredType = DeferredType; - - -/** - * A set of objects of the same type - */ -function ArrayType(typeSpec) { - if (typeSpec instanceof Type) { - this.subtype = typeSpec; - } - else if (typeof typeSpec === 'string') { - this.subtype = types.getType(typeSpec); - if (this.subtype == null) { - throw new Error('Unknown array subtype: ' + typeSpec); - } - } - else { - throw new Error('Can\' handle array subtype'); - } -}; - -ArrayType.prototype = new Type(); - -ArrayType.prototype.stringify = function(values) { - // TODO: Check for strings with spaces and add quotes - return values.join(' '); -}; - -ArrayType.prototype.parse = function(value) { - return this.defer().parse(value); -}; - -ArrayType.prototype.name = 'array'; - -/** - * Registration and de-registration. - */ -var isStarted = false; -exports.startup = function() { - if (isStarted) { - return; - } - isStarted = true; - types.registerType(text); - types.registerType(number); - types.registerType(bool); - types.registerType(SelectionType); - types.registerType(DeferredType); - types.registerType(ArrayType); -}; - -exports.shutdown = function() { - isStarted = false; - types.unregisterType(text); - types.unregisterType(number); - types.unregisterType(bool); - types.unregisterType(SelectionType); - types.unregisterType(DeferredType); - types.unregisterType(ArrayType); -}; - - -}); -/* ***** 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('pilot/types', ['require', 'exports', 'module' ], function(require, exports, module) { - -/** - * Some types can detect validity, that is to say they can distinguish between - * valid and invalid values. - * TODO: Change these constants to be numbers for more performance? - */ -var Status = { - /** - * The conversion process worked without any problem, and the value is - * valid. There are a number of failure states, so the best way to check - * for failure is (x !== Status.VALID) - */ - VALID: { - toString: function() { return 'VALID'; }, - valueOf: function() { return 0; } - }, - - /** - * A conversion process failed, however it was noted that the string - * provided to 'parse()' could be VALID by the addition of more characters, - * so the typing may not be actually incorrect yet, just unfinished. - * @see Status.INVALID - */ - INCOMPLETE: { - toString: function() { return 'INCOMPLETE'; }, - valueOf: function() { return 1; } - }, - - /** - * The conversion process did not work, the value should be null and a - * reason for failure should have been provided. In addition some completion - * values may be available. - * @see Status.INCOMPLETE - */ - INVALID: { - toString: function() { return 'INVALID'; }, - valueOf: function() { return 2; } - }, - - /** - * A combined status is the worser of the provided statuses - */ - combine: function(statuses) { - var combined = Status.VALID; - for (var i = 0; i < statuses.length; i++) { - if (statuses[i].valueOf() > combined.valueOf()) { - combined = statuses[i]; - } - } - return combined; - } -}; -exports.Status = Status; - -/** - * The type.parse() method returns a Conversion to inform the user about not - * only the result of a Conversion but also about what went wrong. - * We could use an exception, and throw if the conversion failed, but that - * seems to violate the idea that exceptions should be exceptional. Typos are - * not. Also in order to store both a status and a message we'd still need - * some sort of exception type... - */ -function Conversion(value, status, message, predictions) { - /** - * The result of the conversion process. Will be null if status != VALID - */ - this.value = value; - - /** - * The status of the conversion. - * @see Status - */ - this.status = status || Status.VALID; - - /** - * A message to go with the conversion. This could be present for any status - * including VALID in the case where we want to note a warning for example. - * I18N: On the one hand this nasty and un-internationalized, however with - * a command line it is hard to know where to start. - */ - this.message = message; - - /** - * A array of strings which are the systems best guess at better inputs than - * the one presented. - * We generally expect there to be about 7 predictions (to match human list - * comprehension ability) however it is valid to provide up to about 20, - * or less. It is the job of the predictor to decide a smart cut-off. - * For example if there are 4 very good matches and 4 very poor ones, - * probably only the 4 very good matches should be presented. - */ - this.predictions = predictions || []; -} -exports.Conversion = Conversion; - -/** - * Most of our types are 'static' e.g. there is only one type of 'text', however - * some types like 'selection' and 'deferred' are customizable. The basic - * Type type isn't useful, but does provide documentation about what types do. - */ -function Type() { -}; -Type.prototype = { - /** - * Convert the given value to a string representation. - * Where possible, there should be round-tripping between values and their - * string representations. - */ - stringify: function(value) { throw new Error("not implemented"); }, - - /** - * Convert the given str to an instance of this type. - * Where possible, there should be round-tripping between values and their - * string representations. - * @return Conversion - */ - parse: function(str) { throw new Error("not implemented"); }, - - /** - * The plug-in system, and other things need to know what this type is - * called. The name alone is not enough to fully specify a type. Types like - * 'selection' and 'deferred' need extra data, however this function returns - * only the name, not the extra data. - *
In old bespin, equality was based on the name. This may turn out to be - * important in Ace too. - */ - name: undefined, - - /** - * If there is some concept of a higher value, return it, - * otherwise return undefined. - */ - increment: function(value) { - return undefined; - }, - - /** - * If there is some concept of a lower value, return it, - * otherwise return undefined. - */ - decrement: function(value) { - return undefined; - }, - - /** - * There is interesting information (like predictions) in a conversion of - * nothing, the output of this can sometimes be customized. - * @return Conversion - */ - getDefault: function() { - return this.parse(''); - } -}; -exports.Type = Type; - -/** - * Private registry of types - * Invariant: types[name] = type.name - */ -var types = {}; - -/** - * Add a new type to the list available to the system. - * You can pass 2 things to this function - either an instance of Type, in - * which case we return this instance when #getType() is called with a 'name' - * that matches type.name. - * Also you can pass in a constructor (i.e. function) in which case when - * #getType() is called with a 'name' that matches Type.prototype.name we will - * pass the typeSpec into this constructor. See #reconstituteType(). - */ -exports.registerType = function(type) { - if (typeof type === 'object') { - if (type instanceof Type) { - if (!type.name) { - throw new Error('All registered types must have a name'); - } - types[type.name] = type; - } - else { - throw new Error('Can\'t registerType using: ' + type); - } - } - else if (typeof type === 'function') { - if (!type.prototype.name) { - throw new Error('All registered types must have a name'); - } - types[type.prototype.name] = type; - } - else { - throw new Error('Unknown type: ' + type); - } -}; - -exports.registerTypes = function registerTypes(types) { - Object.keys(types).forEach(function (name) { - var type = types[name]; - type.name = name; - exports.registerType(type); - }); -}; - -/** - * Remove a type from the list available to the system - */ -exports.deregisterType = function(type) { - delete types[type.name]; -}; - -/** - * See description of #exports.registerType() - */ -function reconstituteType(name, typeSpec) { - if (name.substr(-2) === '[]') { // i.e. endsWith('[]') - var subtypeName = name.slice(0, -2); - return new types['array'](subtypeName); - } - - var type = types[name]; - if (typeof type === 'function') { - type = new type(typeSpec); - } - return type; -} - -/** - * Find a type, previously registered using #registerType() - */ -exports.getType = function(typeSpec) { - if (typeof typeSpec === 'string') { - return reconstituteType(typeSpec); - } - - if (typeof typeSpec === 'object') { - if (!typeSpec.name) { - throw new Error('Missing \'name\' member to typeSpec'); - } - return reconstituteType(typeSpec.name, typeSpec); - } - - throw new Error('Can\'t extract type from ' + typeSpec); -}; - - -}); -/* ***** 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) - * Kevin Dangoor (kdangoor@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('pilot/types/command', ['require', 'exports', 'module' , 'pilot/canon', 'pilot/types/basic', 'pilot/types'], function(require, exports, module) { - -var canon = require("pilot/canon"); -var SelectionType = require("pilot/types/basic").SelectionType; -var types = require("pilot/types"); - - -/** - * Select from the available commands - */ -var command = new SelectionType({ - name: 'command', - data: function() { - return canon.getCommandNames(); - }, - stringify: function(command) { - return command.name; - }, - fromString: function(str) { - return canon.getCommand(str); - } -}); - - -/** - * Registration and de-registration. - */ -exports.startup = function() { - types.registerType(command); -}; - -exports.shutdown = function() { - types.unregisterType(command); -}; - - -}); -/* ***** 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('pilot/canon', ['require', 'exports', 'module' , 'pilot/console', 'pilot/stacktrace', 'pilot/oop', 'pilot/useragent', 'pilot/keys', 'pilot/event_emitter', 'pilot/typecheck', 'pilot/catalog', 'pilot/types', 'pilot/lang'], function(require, exports, module) { - -var console = require('pilot/console'); -var Trace = require('pilot/stacktrace').Trace; -var oop = require('pilot/oop'); -var useragent = require('pilot/useragent'); -var keyUtil = require('pilot/keys'); -var EventEmitter = require('pilot/event_emitter').EventEmitter; -var typecheck = require('pilot/typecheck'); -var catalog = require('pilot/catalog'); -var Status = require('pilot/types').Status; -var types = require('pilot/types'); -var lang = require('pilot/lang'); - -/* -// TODO: this doesn't belong here - or maybe anywhere? -var dimensionsChangedExtensionSpec = { - name: 'dimensionsChanged', - description: 'A dimensionsChanged is a way to be notified of ' + - 'changes to the dimension of Skywriter' -}; -exports.startup = function(data, reason) { - catalog.addExtensionSpec(commandExtensionSpec); -}; -exports.shutdown = function(data, reason) { - catalog.removeExtensionSpec(commandExtensionSpec); -}; -*/ - -var commandExtensionSpec = { - name: 'command', - description: 'A command is a bit of functionality with optional ' + - 'typed arguments which can do something small like moving ' + - 'the cursor around the screen, or large like cloning a ' + - 'project from VCS.', - indexOn: 'name' -}; - -exports.startup = function(data, reason) { - // TODO: this is probably all kinds of evil, but we need something working - catalog.addExtensionSpec(commandExtensionSpec); -}; - -exports.shutdown = function(data, reason) { - catalog.removeExtensionSpec(commandExtensionSpec); -}; - -/** - * Manage a list of commands in the current canon - */ - -/** - * A Command is a discrete action optionally with a set of ways to customize - * how it happens. This is here for documentation purposes. - * TODO: Document better - */ -var thingCommand = { - name: 'thing', - description: 'thing is an example command', - params: [{ - name: 'param1', - description: 'an example parameter', - type: 'text', - defaultValue: null - }], - exec: function(env, args, request) { - thing(); - } -}; - -/** - * A lookup hash of our registered commands - */ -var commands = {}; - -/** - * A lookup has for command key bindings that use a string as sender. - */ -var commmandKeyBinding = {}; - -/** - * Array with command key bindings that use a function to determ the sender. - */ -var commandKeyBindingFunc = { }; - -function splitSafe(s, separator, limit, bLowerCase) { - return (bLowerCase && s.toLowerCase() || s) - .replace(/(?:^\s+|\n|\s+$)/g, "") - .split(new RegExp("[\\s ]*" + separator + "[\\s ]*", "g"), limit || 999); -} - -function parseKeys(keys, val, ret) { - var key, - hashId = 0, - parts = splitSafe(keys, "\\-", null, true), - i = 0, - l = parts.length; - - for (; i < l; ++i) { - if (keyUtil.KEY_MODS[parts[i]]) - hashId = hashId | keyUtil.KEY_MODS[parts[i]]; - else - key = parts[i] || "-"; //when empty, the splitSafe removed a '-' - } - - if (ret == null) { - return { - key: key, - hashId: hashId - } - } else { - (ret[hashId] || (ret[hashId] = {}))[key] = val; - } -} - -var platform = useragent.isMac ? "mac" : "win"; -function buildKeyHash(command) { - var binding = command.bindKey, - key = binding[platform], - ckb = commmandKeyBinding, - ckbf = commandKeyBindingFunc - - if (!binding.sender) { - throw new Error('All key bindings must have a sender'); - } - if (!binding.mac && binding.mac !== null) { - throw new Error('All key bindings must have a mac key binding'); - } - if (!binding.win && binding.win !== null) { - throw new Error('All key bindings must have a windows key binding'); - } - if(!binding[platform]) { - // No keymapping for this platform. - return; - } - if (typeof binding.sender == 'string') { - var targets = splitSafe(binding.sender, "\\|", null, true); - targets.forEach(function(target) { - if (!ckb[target]) { - ckb[target] = { }; - } - key.split("|").forEach(function(keyPart) { - parseKeys(keyPart, command, ckb[target]); - }); - }); - } else if (typecheck.isFunction(binding.sender)) { - var val = { - command: command, - sender: binding.sender - }; - - keyData = parseKeys(key); - if (!ckbf[keyData.hashId]) { - ckbf[keyData.hashId] = { }; - } - if (!ckbf[keyData.hashId][keyData.key]) { - ckbf[keyData.hashId][keyData.key] = [ val ]; - } else { - ckbf[keyData.hashId][keyData.key].push(val); - } - } else { - throw new Error('Key binding must have a sender that is a string or function'); - } -} - -function findKeyCommand(env, sender, hashId, textOrKey) { - // Convert keyCode to the string representation. - if (typecheck.isNumber(textOrKey)) { - textOrKey = keyUtil.keyCodeToString(textOrKey); - } - - // Check bindings with functions as sender first. - var bindFuncs = (commandKeyBindingFunc[hashId] || {})[textOrKey] || []; - for (var i = 0; i < bindFuncs.length; i++) { - if (bindFuncs[i].sender(env, sender, hashId, textOrKey)) { - return bindFuncs[i].command; - } - } - - var ckbr = commmandKeyBinding[sender]; - return ckbr && ckbr[hashId] && ckbr[hashId][textOrKey]; -} - -function execKeyCommand(env, sender, hashId, textOrKey) { - var command = findKeyCommand(env, sender, hashId, textOrKey); - if (command) { - return exec(command, env, sender, { }); - } else { - return false; - } -} - -/** - * A sorted list of command names, we regularly want them in order, so pre-sort - */ -var commandNames = []; - -/** - * This registration method isn't like other Ace registration methods because - * it doesn't return a decorated command because there is no functional - * decoration to be done. - * TODO: Are we sure that in the future there will be no such decoration? - */ -function addCommand(command) { - if (!command.name) { - throw new Error('All registered commands must have a name'); - } - if (command.params == null) { - command.params = []; - } - if (!Array.isArray(command.params)) { - throw new Error('command.params must be an array in ' + command.name); - } - // Replace the type - command.params.forEach(function(param) { - if (!param.name) { - throw new Error('In ' + command.name + ': all params must have a name'); - } - upgradeType(command.name, param); - }, this); - commands[command.name] = command; - - if (command.bindKey) { - buildKeyHash(command); - } - - commandNames.push(command.name); - commandNames.sort(); -}; - -function upgradeType(name, param) { - var lookup = param.type; - param.type = types.getType(lookup); - if (param.type == null) { - throw new Error('In ' + name + '/' + param.name + - ': can\'t find type for: ' + JSON.stringify(lookup)); - } -} - -function removeCommand(command) { - var name = (typeof command === 'string' ? command : command.name); - command = commands[name]; - delete commands[name]; - lang.arrayRemove(commandNames, name); - - // exaustive search is a little bit brute force but since removeCommand is - // not a performance critical operation this should be OK - var ckb = commmandKeyBinding; - for (var k1 in ckb) { - for (var k2 in ckb[k1]) { - for (var k3 in ckb[k1][k2]) { - if (ckb[k1][k2][k3] == command) - delete ckb[k1][k2][k3]; - } - } - } - - var ckbf = commandKeyBindingFunc; - for (var k1 in ckbf) { - for (var k2 in ckbf[k1]) { - ckbf[k1][k2].forEach(function(cmd, i) { - if (cmd.command == command) { - ckbf[k1][k2].splice(i, 1); - } - }) - } - } -}; - -function getCommand(name) { - return commands[name]; -}; - -function getCommandNames() { - return commandNames; -}; - -/** - * Default ArgumentProvider that is used if no ArgumentProvider is provided - * by the command's sender. - */ -function defaultArgsProvider(request, callback) { - var args = request.args, - params = request.command.params; - - for (var i = 0; i < params.length; i++) { - var param = params[i]; - - // If the parameter is already valid, then don't ask for it anymore. - if (request.getParamStatus(param) != Status.VALID || - // Ask for optional parameters as well. - param.defaultValue === null) - { - var paramPrompt = param.description; - if (param.defaultValue === null) { - paramPrompt += " (optional)"; - } - var value = prompt(paramPrompt, param.defaultValue || ""); - // No value but required -> nope. - if (!value) { - callback(); - return; - } else { - args[param.name] = value; - } - } - } - callback(); -} - -/** - * Entry point for keyboard accelerators or anything else that wants to execute - * a command. A new request object is created and a check performed, if the - * passed in arguments are VALID/INVALID or INCOMPLETE. If they are INCOMPLETE - * the ArgumentProvider on the sender is called or otherwise the default - * ArgumentProvider to get the still required arguments. - * If they are valid (or valid after the ArgumentProvider is done), the command - * is executed. - * - * @param command Either a command, or the name of one - * @param env Current environment to execute the command in - * @param sender String that should be the same as the senderObject stored on - * the environment in env[sender] - * @param args Arguments for the command - * @param typed (Optional) - */ -function exec(command, env, sender, args, typed) { - if (typeof command === 'string') { - command = commands[command]; - } - if (!command) { - // TODO: Should we complain more than returning false? - return false; - } - - var request = new Request({ - sender: sender, - command: command, - args: args || {}, - typed: typed - }); - - /** - * Executes the command and ensures request.done is called on the request in - * case it's not marked to be done already or async. - */ - function execute() { - command.exec(env, request.args, request); - - // If the request isn't asnync and isn't done, then make it done. - if (!request.isAsync && !request.isDone) { - request.done(); - } - } - - - if (request.getStatus() == Status.INVALID) { - console.error("Canon.exec: Invalid parameter(s) passed to " + - command.name); - return false; - } - // If the request isn't complete yet, try to complete it. - else if (request.getStatus() == Status.INCOMPLETE) { - // Check if the sender has a ArgsProvider, otherwise use the default - // build in one. - var argsProvider; - var senderObj = env[sender]; - if (!senderObj || !senderObj.getArgsProvider || - !(argsProvider = senderObj.getArgsProvider())) - { - argsProvider = defaultArgsProvider; - } - - // Ask the paramProvider to complete the request. - argsProvider(request, function() { - if (request.getStatus() == Status.VALID) { - execute(); - } - }); - return true; - } else { - execute(); - return true; - } -}; - -exports.removeCommand = removeCommand; -exports.addCommand = addCommand; -exports.getCommand = getCommand; -exports.getCommandNames = getCommandNames; -exports.findKeyCommand = findKeyCommand; -exports.exec = exec; -exports.execKeyCommand = execKeyCommand; -exports.upgradeType = upgradeType; - - -/** - * We publish a 'output' event whenever new command begins output - * TODO: make this more obvious - */ -oop.implement(exports, EventEmitter); - - -/** - * Current requirements are around displaying the command line, and provision - * of a 'history' command and cursor up|down navigation of history. - *
Future requirements could include: - *
The execute() command doesn't really live here, except as part of that - * last future requirement, and because it doesn't really have anywhere else to - * live. - */ - -/** - * The array of requests that wish to announce their presence - */ -var requests = []; - -/** - * How many requests do we store? - */ -var maxRequestLength = 100; - -/** - * To create an invocation, you need to do something like this (all the ctor - * args are optional): - *
- * var request = new Request({ - * command: command, - * args: args, - * typed: typed - * }); - *- * @constructor - */ -function Request(options) { - options = options || {}; - - // Will be used in the keyboard case and the cli case - this.command = options.command; - - // Will be used only in the cli case - this.args = options.args; - this.typed = options.typed; - - // Have we been initialized? - this._begunOutput = false; - - this.start = new Date(); - this.end = null; - this.completed = false; - this.error = false; -}; - -oop.implement(Request.prototype, EventEmitter); - -/** - * Return the status of a parameter on the request object. - */ -Request.prototype.getParamStatus = function(param) { - var args = this.args || {}; - - // Check if there is already a value for this parameter. - if (param.name in args) { - // If there is no value set and then the value is VALID if it's not - // required or INCOMPLETE if not set yet. - if (args[param.name] == null) { - if (param.defaultValue === null) { - return Status.VALID; - } else { - return Status.INCOMPLETE; - } - } - - // Check if the parameter value is valid. - var reply, - // The passed in value when parsing a type is a string. - argsValue = args[param.name].toString(); - - // Type.parse can throw errors. - try { - reply = param.type.parse(argsValue); - } catch (e) { - return Status.INVALID; - } - - if (reply.status != Status.VALID) { - return reply.status; - } - } - // Check if the param is marked as required. - else if (param.defaultValue === undefined) { - // The parameter is not set on the args object but it's required, - // which means, things are invalid. - return Status.INCOMPLETE; - } - - return Status.VALID; -} - -/** - * Return the status of a parameter name on the request object. - */ -Request.prototype.getParamNameStatus = function(paramName) { - var params = this.command.params || []; - - for (var i = 0; i < params.length; i++) { - if (params[i].name == paramName) { - return this.getParamStatus(params[i]); - } - } - - throw "Parameter '" + paramName + - "' not defined on command '" + this.command.name + "'"; -} - -/** - * Checks if all required arguments are set on the request such that it can - * get executed. - */ -Request.prototype.getStatus = function() { - var args = this.args || {}, - params = this.command.params; - - // If there are not parameters, then it's valid. - if (!params || params.length == 0) { - return Status.VALID; - } - - var status = []; - for (var i = 0; i < params.length; i++) { - status.push(this.getParamStatus(params[i])); - } - - return Status.combine(status); -} - -/** - * Lazy init to register with the history should only be done on output. - * init() is expensive, and won't be used in the majority of cases - */ -Request.prototype._beginOutput = function() { - this._begunOutput = true; - this.outputs = []; - - requests.push(this); - // This could probably be optimized with some maths, but 99.99% of the - // time we will only be off by one, and I'm feeling lazy. - while (requests.length > maxRequestLength) { - requests.shiftObject(); - } - - exports._dispatchEvent('output', { requests: requests, request: this }); -}; - -/** - * Sugar for: - *
request.error = true; request.done(output);- */ -Request.prototype.doneWithError = function(content) { - this.error = true; - this.done(content); -}; - -/** - * Declares that this function will not be automatically done when - * the command exits - */ -Request.prototype.async = function() { - this.isAsync = true; - if (!this._begunOutput) { - this._beginOutput(); - } -}; - -/** - * Complete the currently executing command with successful output. - * @param output Either DOM node, an SproutCore element or something that - * can be used in the content of a DIV to create a DOM node. - */ -Request.prototype.output = function(content) { - if (!this._begunOutput) { - this._beginOutput(); - } - - if (typeof content !== 'string' && !(content instanceof Node)) { - content = content.toString(); - } - - this.outputs.push(content); - this.isDone = true; - this._dispatchEvent('output', {}); - - return this; -}; - -/** - * All commands that do output must call this to indicate that the command - * has finished execution. - */ -Request.prototype.done = function(content) { - this.completed = true; - this.end = new Date(); - this.duration = this.end.getTime() - this.start.getTime(); - - if (content) { - this.output(content); - } - - // Ensure to finish the request only once. - if (!this.isDone) { - this.isDone = true; - this._dispatchEvent('output', {}); - } -}; -exports.Request = Request; - - -}); -/* ***** 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) - * Patrick Walton (pwalton@mozilla.com) - * Julian Viereck (jviereck@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('pilot/console', ['require', 'exports', 'module' ], function(require, exports, module) { - -/** - * This object represents a "safe console" object that forwards debugging - * messages appropriately without creating a dependency on Firebug in Firefox. - */ - -var noop = function() {}; - -// These are the functions that are available in Chrome 4/5, Safari 4 -// and Firefox 3.6. Don't add to this list without checking browser support -var NAMES = [ - "assert", "count", "debug", "dir", "dirxml", "error", "group", "groupEnd", - "info", "log", "profile", "profileEnd", "time", "timeEnd", "trace", "warn" -]; - -if (typeof(window) === 'undefined') { - // We're in a web worker. Forward to the main thread so the messages - // will show up. - NAMES.forEach(function(name) { - exports[name] = function() { - var args = Array.prototype.slice.call(arguments); - var msg = { op: 'log', method: name, args: args }; - postMessage(JSON.stringify(msg)); - }; - }); -} else { - // For each of the console functions, copy them if they exist, stub if not - NAMES.forEach(function(name) { - if (window.console && window.console[name]) { - exports[name] = Function.prototype.bind.call(window.console[name], window.console); - } else { - exports[name] = noop; - } - }); -} - -}); -define('pilot/stacktrace', ['require', 'exports', 'module' , 'pilot/useragent', 'pilot/console'], function(require, exports, module) { - -var ua = require("pilot/useragent"); -var console = require('pilot/console'); - -// Changed to suit the specific needs of running within Skywriter - -// Domain Public by Eric Wendelin http://eriwen.com/ (2008) -// Luke Smith http://lucassmith.name/ (2008) -// Loic Dachary
key
setting to it's default
- */
- resetValue: function() {
- this.set(this.defaultValue);
- },
- toString: function () {
- return this.name;
- }
-};
-oop.implement(Setting.prototype, EventEmitter);
-
-
-/**
- * A base class for all the various methods of storing settings.
- * Usage: - *
- * // Create manually, or require 'settings' from the container. - * // This is the manual version: - * var settings = plugins.catalog.getObject('settings'); - * // Add a new setting - * settings.addSetting({ name:'foo', ... }); - * // Display the default value - * alert(settings.get('foo')); - * // Alter the value, which also publishes the change etc. - * settings.set('foo', 'bar'); - * // Reset the value to the default - * settings.resetValue('foo'); - *- * @constructor - */ -function Settings(persister) { - // Storage for deactivated values - this._deactivated = {}; - - // Storage for the active settings - this._settings = {}; - // We often want sorted setting names. Cache - this._settingNames = []; - - if (persister) { - this.setPersister(persister); - } -}; - -Settings.prototype = { - /** - * Function to add to the list of available settings. - *
Example usage: - *
- * var settings = plugins.catalog.getObject('settings'); - * settings.addSetting({ - * name: 'tabsize', // For use in settings.get('X') - * type: 'number', // To allow value checking. - * defaultValue: 4 // Default value for use when none is directly set - * }); - *- * @param {object} settingSpec Object containing name/type/defaultValue members. - */ - addSetting: function(settingSpec) { - var setting = new Setting(settingSpec, this); - this._settings[setting.name] = setting; - this._settingNames.push(setting.name); - this._settingNames.sort(); - }, - - addSettings: function addSettings(settings) { - Object.keys(settings).forEach(function (name) { - var setting = settings[name]; - if (!('name' in setting)) setting.name = name; - this.addSetting(setting); - }, this); - }, - - removeSetting: function(setting) { - var name = (typeof setting === 'string' ? setting : setting.name); - setting = this._settings[name]; - delete this._settings[name]; - util.arrayRemove(this._settingNames, name); - settings.removeAllListeners('change'); - }, - - removeSettings: function removeSettings(settings) { - Object.keys(settings).forEach(function(name) { - var setting = settings[name]; - if (!('name' in setting)) setting.name = name; - this.removeSettings(setting); - }, this); - }, - - getSettingNames: function() { - return this._settingNames; - }, - - getSetting: function(name) { - return this._settings[name]; - }, - - /** - * A Persister is able to store settings. It is an object that defines - * two functions: - * loadInitialValues(settings) and persistValue(settings, key, value). - */ - setPersister: function(persister) { - this._persister = persister; - if (persister) { - persister.loadInitialValues(this); - } - }, - - resetAll: function() { - this.getSettingNames().forEach(function(key) { - this.resetValue(key); - }, this); - }, - - /** - * Retrieve a list of the known settings and their values - */ - _list: function() { - var reply = []; - this.getSettingNames().forEach(function(setting) { - reply.push({ - 'key': setting, - 'value': this.getSetting(setting).get() - }); - }, this); - return reply; - }, - - /** - * Prime the local cache with the defaults. - */ - _loadDefaultValues: function() { - this._loadFromObject(this._getDefaultValues()); - }, - - /** - * Utility to load settings from an object - */ - _loadFromObject: function(data) { - // We iterate over data rather than keys so we don't forget values - // which don't have a setting yet. - for (var key in data) { - if (data.hasOwnProperty(key)) { - var setting = this._settings[key]; - if (setting) { - var value = setting.type.parse(data[key]); - this.set(key, value); - } else { - this.set(key, data[key]); - } - } - } - }, - - /** - * Utility to grab all the settings and export them into an object - */ - _saveToObject: function() { - return this.getSettingNames().map(function(key) { - return this._settings[key].type.stringify(this.get(key)); - }.bind(this)); - }, - - /** - * The default initial settings - */ - _getDefaultValues: function() { - return this.getSettingNames().map(function(key) { - return this._settings[key].spec.defaultValue; - }.bind(this)); - } -}; -exports.settings = new Settings(); - -/** - * Save the settings in a cookie - * This code has not been tested since reboot - * @constructor - */ -function CookiePersister() { -}; - -CookiePersister.prototype = { - loadInitialValues: function(settings) { - settings._loadDefaultValues(); - var data = cookie.get('settings'); - settings._loadFromObject(JSON.parse(data)); - }, - - persistValue: function(settings, key, value) { - try { - var stringData = JSON.stringify(settings._saveToObject()); - cookie.set('settings', stringData); - } catch (ex) { - console.error('Unable to JSONify the settings! ' + ex); - return; - } - } -}; - -exports.CookiePersister = CookiePersister; - -}); -/* ***** 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): - * Skywriter Team (skywriter@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('pilot/commands/settings', ['require', 'exports', 'module' , 'pilot/canon'], function(require, exports, module) { - - -var setCommandSpec = { - name: 'set', - params: [ - { - name: 'setting', - type: 'setting', - description: 'The name of the setting to display or alter', - defaultValue: null - }, - { - name: 'value', - type: 'settingValue', - description: 'The new value for the chosen setting', - defaultValue: null - } - ], - description: 'define and show settings', - exec: function(env, args, request) { - var html; - if (!args.setting) { - // 'set' by itself lists all the settings - var names = env.settings.getSettingNames(); - html = ''; - // first sort the settingsList based on the name - names.sort(function(name1, name2) { - return name1.localeCompare(name2); - }); - - names.forEach(function(name) { - var setting = env.settings.getSetting(name); - var url = 'https://wiki.mozilla.org/Labs/Skywriter/Settings#' + - setting.name; - html += '' + - setting.name + - ' = ' + - setting.value + - '
' + command.description + '
'); - } - else if (args.search) { - if (args.search == 'hidden') { // sneaky, sneaky. - args.search = ''; - showHidden = true; - } - output.push('' + command.name + ' | '); - output.push('' + command.description + ' | '); - output.push('
---|
"+e.description+"
")):b.search?(b.search=="hidden"&&(b.search="",f=!0),d.push("'+e.name+" | "),d.push(""+e.description+" | "),d.push("")}d.push("
---|
We also record validity information where applicable. - *
For values, null and undefined have distinct definitions. null means
- * that a value has been provided, undefined means that it has not.
- * Thus, null is a valid default value, and common because it identifies an
- * parameter that is optional. undefined means there is no value from
- * the command line.
- * @constructor
- */
-function Assignment(param, requisition) {
- this.param = param;
- this.requisition = requisition;
- this.setValue(param.defaultValue);
-};
-Assignment.prototype = {
- /**
- * The parameter that we are assigning to
- * @readonly
- */
- param: undefined,
-
- /**
- * Report on the status of the last parse() conversion.
- * @see types.Conversion
- */
- conversion: undefined,
-
- /**
- * The current value in a type as specified by param.type
- */
- value: undefined,
-
- /**
- * The string version of the current value
- */
- arg: undefined,
-
- /**
- * The current value (i.e. not the string representation)
- * Use setValue() to mutate
- */
- value: undefined,
- setValue: function(value) {
- if (this.value === value) {
- return;
- }
-
- if (value === undefined) {
- this.value = this.param.defaultValue;
- this.conversion = this.param.getDefault ?
- this.param.getDefault() :
- this.param.type.getDefault();
- this.arg = undefined;
- } else {
- this.value = value;
- this.conversion = undefined;
- var text = (value == null) ? '' : this.param.type.stringify(value);
- if (this.arg) {
- this.arg.setText(text);
- }
- }
-
- this.requisition._assignmentChanged(this);
- },
-
- /**
- * The textual representation of the current value
- * Use setValue() to mutate
- */
- arg: undefined,
- setArgument: function(arg) {
- if (this.arg === arg) {
- return;
- }
- this.arg = arg;
- this.conversion = this.param.type.parse(arg.text);
- this.conversion.arg = arg; // TODO: make this automatic?
- this.value = this.conversion.value;
- this.requisition._assignmentChanged(this);
- },
-
- /**
- * Create a list of the hints associated with this parameter assignment.
- * Generally there will be only one hint generated because we're currently
- * only displaying one hint at a time, ordering by distance from cursor
- * and severity. Since distance from cursor will be the same for all hints
- * from this assignment all but the most severe will ever be used. It might
- * make sense with more experience to alter this to function to be getHint()
- */
- getHint: function() {
- // Allow the parameter to provide documentation
- if (this.param.getCustomHint && this.value && this.arg) {
- var hint = this.param.getCustomHint(this.value, this.arg);
- if (hint) {
- return hint;
- }
- }
-
- // If there is no argument, use the cursor position
- var message = '' + this.param.name + ': ';
- if (this.param.description) {
- // TODO: This should be a short description - do we need to trim?
- message += this.param.description.trim();
-
- // Ensure the help text ends with '. '
- if (message.charAt(message.length - 1) !== '.') {
- message += '.';
- }
- if (message.charAt(message.length - 1) !== ' ') {
- message += ' ';
- }
- }
- var status = Status.VALID;
- var start = this.arg ? this.arg.start : Argument.AT_CURSOR;
- var end = this.arg ? this.arg.end : Argument.AT_CURSOR;
- var predictions;
-
- // Non-valid conversions will have useful information to pass on
- if (this.conversion) {
- status = this.conversion.status;
- if (this.conversion.message) {
- message += this.conversion.message;
- }
- predictions = this.conversion.predictions;
- }
-
- // Hint if the param is required, but not provided
- var argProvided = this.arg && this.arg.text !== '';
- var dataProvided = this.value !== undefined || argProvided;
- if (this.param.defaultValue === undefined && !dataProvided) {
- status = Status.INVALID;
- message += 'Required<\strong>';
- }
-
- return new Hint(status, message, start, end, predictions);
- },
-
- /**
- * Basically setValue(conversion.predictions[0]) done in a safe
- * way.
- */
- complete: function() {
- if (this.conversion && this.conversion.predictions &&
- this.conversion.predictions.length > 0) {
- this.setValue(this.conversion.predictions[0]);
- }
- },
-
- /**
- * If the cursor is at 'position', do we have sufficient data to start
- * displaying the next hint. This is both complex and important.
- * For example, if the user has just typed: Note that the input for 2 and 4 is identical, only the configuration
- * has changed, so hint display is environmental.
- *
- * This function works out if the cursor is before the end of this
- * assignment (assuming that we've asked the same thing of the previous
- * assignment) and then attempts to work out if we should use the hint from
- * the next assignment even though technically the cursor is still inside
- * this one due to the rules above.
- */
- isPositionCaptured: function(position) {
- if (!this.arg) {
- return false;
- }
-
- // Note we don't check if position >= this.arg.start because that's
- // implied by the fact that we're asking the assignments in turn, and
- // we want to avoid thing falling between the cracks, but we do need
- // to check that the argument does have a position
- if (this.arg.start === -1) {
- return false;
- }
-
- // We're clearly done if the position is past the end of the text
- if (position > this.arg.end) {
- return false;
- }
-
- // If we're AT the end, the position is captured if either the status
- // is not valid or if there are other valid options including current
- if (position === this.arg.end) {
- return this.conversion.status !== Status.VALID ||
- this.conversion.predictions.length !== 0;
- }
-
- // Otherwise we're clearly inside
- return true;
- },
-
- /**
- * Replace the current value with the lower value if such a concept
- * exists.
- */
- decrement: function() {
- var replacement = this.param.type.decrement(this.value);
- if (replacement != null) {
- this.setValue(replacement);
- }
- },
-
- /**
- * Replace the current value with the higher value if such a concept
- * exists.
- */
- increment: function() {
- var replacement = this.param.type.increment(this.value);
- if (replacement != null) {
- this.setValue(replacement);
- }
- },
-
- /**
- * Helper when we're rebuilding command lines.
- */
- toString: function() {
- return this.arg ? this.arg.toString() : '';
- }
-};
-exports.Assignment = Assignment;
-
-
-/**
- * This is a special parameter to reflect the command itself.
- */
-var commandParam = {
- name: '__command',
- type: 'command',
- description: 'The command to execute',
-
- /**
- * Provide some documentation for a command.
- */
- getCustomHint: function(command, arg) {
- var docs = [];
- docs.push(' > ');
- docs.push(command.name);
- if (command.params && command.params.length > 0) {
- command.params.forEach(function(param) {
- if (param.defaultValue === undefined) {
- docs.push(' [' + param.name + ']');
- }
- else {
- docs.push(' [' + param.name + ']');
- }
- }, this);
- }
- docs.push(' The 'output' of the update is held in 2 objects: input.hints which is an
- * array of hints to display to the user. In the future this will become a
- * single value.
- * The other output value is input.requisition which gives access to an
- * args object for use in executing the final command.
- *
- * The majority of the functions in this class are called in sequence by the
- * constructor. Their task is to add to hints fill out the requisition.
- * The general sequence is: This takes #_command.params and #_unparsedArgs and creates a map of
- * param names to 'assignment' objects, which have the following properties:
- * "+(e&&(e.length>80?e.slice(0,77)+"...":e).entityify())+" Implied global: "+n.join(", ")+" Unused variable: "+n.join(", ")+" JSON: bad. JSON: good.
- *
- *
');
-
- docs.push(command.description ? command.description : '(No description)');
- docs.push('
');
-
- if (command.params && command.params.length > 0) {
- docs.push('');
- command.params.forEach(function(param) {
- docs.push('
');
- }
-
- return new Hint(Status.VALID, docs.join(''), arg);
- }
-};
-
-/**
- * A Requisition collects the information needed to execute a command.
- * There is no point in a requisition for parameter-less commands because there
- * is no information to collect. A Requisition is a collection of assignments
- * of values to parameters, each handled by an instance of Assignment.
- * CliRequisition adds functions for parsing input from a command line to this
- * class.
- * Events
- * We publish the following events:
- *
- *
- *
- * @param typed {string} The instruction as typed by the user so far
- * @param options {object} A list of optional named parameters. Can be any of:
- * flags: Flags for us to check against the predicates specified with the
- * commands. Defaulted to keyboard.buildFlags({ });
- * if not specified.
- * @constructor
- */
-function CliRequisition(env, options) {
- Requisition.call(this, env);
-
- if (options && options.flags) {
- /**
- * TODO: We were using a default of keyboard.buildFlags({ });
- * This allowed us to have commands that only existed in certain contexts
- * - i.e. Javascript specific commands.
- */
- this.flags = options.flags;
- }
-}
-oop.inherits(CliRequisition, Requisition);
-(function() {
- /**
- * Called by the UI when ever the user interacts with a command line input
- * @param input A structure that details the state of the input field.
- * It should look something like: { typed:a, cursor: { start:b, end:c } }
- * Where a is the contents of the input field, and b and c are the start
- * and end of the cursor/selection respectively.
- */
- CliRequisition.prototype.update = function(input) {
- this.input = input;
- this._hints = [];
-
- var args = this._tokenize(input.typed);
- this._split(args);
-
- if (this.commandAssignment.value) {
- this._assign(args);
- }
-
- this._updateHints();
- };
-
- /**
- * Return an array of Status scores so we can create a marked up
- * version of the command line input.
- */
- CliRequisition.prototype.getInputStatusMarkup = function() {
- // 'scores' is an array which tells us what chars are errors
- // Initialize with everything VALID
- var scores = this.toString().split('').map(function(ch) {
- return Status.VALID;
- });
- // For all chars in all hints, check and upgrade the score
- this._hints.forEach(function(hint) {
- for (var i = hint.start; i <= hint.end; i++) {
- if (hint.status > scores[i]) {
- scores[i] = hint.status;
- }
- }
- }, this);
- return scores;
- };
-
- /**
- * Reconstitute the input from the args
- */
- CliRequisition.prototype.toString = function() {
- return this.getAssignments(true).map(function(assignment) {
- return assignment.toString();
- }, this).join('');
- };
-
- var superUpdateHints = CliRequisition.prototype._updateHints;
- /**
- * Marks up hints in a number of ways:
- * - Makes INCOMPLETE hints that are not near the cursor INVALID since
- * they can't be completed by typing
- * - Finds the most severe hint, and annotates the array with it
- * - Finds the hint to display, and also annotates the array with it
- * TODO: I'm wondering if array annotation is evil and we should replace
- * this with an object. Need to find out more.
- */
- CliRequisition.prototype._updateHints = function() {
- superUpdateHints.call(this);
-
- // Not knowing about cursor positioning, the requisition and assignments
- // can't know this, but anything they mark as INCOMPLETE is actually
- // INVALID unless the cursor is actually inside that argument.
- var c = this.input.cursor;
- this._hints.forEach(function(hint) {
- var startInHint = c.start >= hint.start && c.start <= hint.end;
- var endInHint = c.end >= hint.start && c.end <= hint.end;
- var inHint = startInHint || endInHint;
- if (!inHint && hint.status === Status.INCOMPLETE) {
- hint.status = Status.INVALID;
- }
- }, this);
-
- Hint.sort(this._hints);
- };
-
- /**
- * Accessor for the hints array.
- * While we could just use the hints property, using getHints() is
- * preferred for symmetry with Requisition where it needs a function due to
- * lack of an atomic update system.
- */
- CliRequisition.prototype.getHints = function() {
- return this._hints;
- };
-
- /**
- * Look through the arguments attached to our assignments for the assignment
- * at the given position.
- */
- CliRequisition.prototype.getAssignmentAt = function(position) {
- var assignments = this.getAssignments(true);
- for (var i = 0; i < assignments.length; i++) {
- var assignment = assignments[i];
- if (!assignment.arg) {
- // There is no argument in this assignment, we've fallen off
- // the end of the obvious answers - it must be this one.
- return assignment;
- }
- if (assignment.isPositionCaptured(position)) {
- return assignment;
- }
- }
-
- return assignment;
- };
-
- /**
- * Split up the input taking into account ' and "
- */
- CliRequisition.prototype._tokenize = function(typed) {
- // For blank input, place a dummy empty argument into the list
- if (typed == null || typed.length === 0) {
- return [ new Argument(this, '', 0, 0, '', '') ];
- }
-
- var OUTSIDE = 1; // The last character was whitespace
- var IN_SIMPLE = 2; // The last character was part of a parameter
- var IN_SINGLE_Q = 3; // We're inside a single quote: '
- var IN_DOUBLE_Q = 4; // We're inside double quotes: "
-
- var mode = OUTSIDE;
-
- // First we un-escape. This list was taken from:
- // https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Core_Language_Features#Unicode
- // We are generally converting to their real values except for \', \"
- // and '\ ' which we are converting to unicode private characters so we
- // can distinguish them from ', " and ' ', which have special meaning.
- // They need swapping back post-split - see unescape2()
- typed = typed
- .replace(/\\\\/g, '\\')
- .replace(/\\b/g, '\b')
- .replace(/\\f/g, '\f')
- .replace(/\\n/g, '\n')
- .replace(/\\r/g, '\r')
- .replace(/\\t/g, '\t')
- .replace(/\\v/g, '\v')
- .replace(/\\n/g, '\n')
- .replace(/\\r/g, '\r')
- .replace(/\\ /g, '\uF000')
- .replace(/\\'/g, '\uF001')
- .replace(/\\"/g, '\uF002');
-
- function unescape2(str) {
- return str
- .replace(/\uF000/g, ' ')
- .replace(/\uF001/g, '\'')
- .replace(/\uF002/g, '"');
- }
-
- var i = 0;
- var start = 0; // Where did this section start?
- var prefix = '';
- var args = [];
-
- while (true) {
- if (i >= typed.length) {
- // There is nothing else to read - tidy up
- if (mode !== OUTSIDE) {
- var str = unescape2(typed.substring(start, i));
- args.push(new Argument(this, str, start, i, prefix, ''));
- }
- else {
- if (i !== start) {
- // There's a bunch of whitespace at the end of the
- // command add it to the last argument's suffix,
- // creating an empty argument if needed.
- var extra = typed.substring(start, i);
- var lastArg = args[args.length - 1];
- if (!lastArg) {
- lastArg = new Argument(this, '', i, i, extra, '');
- args.push(lastArg);
- }
- else {
- lastArg.suffix += extra;
- }
- }
- }
- break;
- }
-
- var c = typed[i];
- switch (mode) {
- case OUTSIDE:
- if (c === '\'') {
- prefix = typed.substring(start, i + 1);
- mode = IN_SINGLE_Q;
- start = i + 1;
- }
- else if (c === '"') {
- prefix = typed.substring(start, i + 1);
- mode = IN_DOUBLE_Q;
- start = i + 1;
- }
- else if (/ /.test(c)) {
- // Still whitespace, do nothing
- }
- else {
- prefix = typed.substring(start, i);
- mode = IN_SIMPLE;
- start = i;
- }
- break;
-
- case IN_SIMPLE:
- // There is an edge case of xx'xx which we are assuming to
- // be a single parameter (and same with ")
- if (c === ' ') {
- var str = unescape2(typed.substring(start, i));
- args.push(new Argument(this, str,
- start, i, prefix, ''));
- mode = OUTSIDE;
- start = i;
- prefix = '';
- }
- break;
-
- case IN_SINGLE_Q:
- if (c === '\'') {
- var str = unescape2(typed.substring(start, i));
- args.push(new Argument(this, str,
- start - 1, i + 1, prefix, c));
- mode = OUTSIDE;
- start = i + 1;
- prefix = '';
- }
- break;
-
- case IN_DOUBLE_Q:
- if (c === '"') {
- var str = unescape2(typed.substring(start, i));
- args.push(new Argument(this, str,
- start - 1, i + 1, prefix, c));
- mode = OUTSIDE;
- start = i + 1;
- prefix = '';
- }
- break;
- }
-
- i++;
- }
-
- return args;
- };
-
- /**
- * Looks in the canon for a command extension that matches what has been
- * typed at the command line.
- */
- CliRequisition.prototype._split = function(args) {
- var argsUsed = 1;
- var arg;
-
- while (argsUsed <= args.length) {
- var arg = Argument.merge(args, 0, argsUsed);
- this.commandAssignment.setArgument(arg);
-
- if (!this.commandAssignment.value) {
- // Not found. break with value == null
- break;
- }
-
- /*
- // Previously we needed a way to hide commands depending context.
- // We have not resurrected that feature yet.
- if (!keyboard.flagsMatch(command.predicates, this.flags)) {
- // If the predicates say 'no match' then go LA LA LA
- command = null;
- break;
- }
- */
-
- if (this.commandAssignment.value.exec) {
- // Valid command, break with command valid
- for (var i = 0; i < argsUsed; i++) {
- args.shift();
- }
- break;
- }
-
- argsUsed++;
- }
- };
-
- /**
- * Work out which arguments are applicable to which parameters.
- *
- *
- */
- CliRequisition.prototype._assign = function(args) {
- if (args.length === 0) {
- this.setDefaultValues();
- return;
- }
-
- // Create an error if the command does not take parameters, but we have
- // been given them ...
- if (this.assignmentCount === 0) {
- // TODO: previously we were doing some extra work to avoid this if
- // we determined that we had args that were all whitespace, but
- // probably given our tighter tokenize() this won't be an issue?
- this._hints.push(new Hint(Status.INVALID,
- this.commandAssignment.value.name +
- ' does not take any parameters',
- Argument.merge(args)));
- return;
- }
-
- // Special case: if there is only 1 parameter, and that's of type
- // text we put all the params into the first param
- if (this.assignmentCount === 1) {
- var assignment = this.getAssignment(0);
- if (assignment.param.type.name === 'text') {
- assignment.setArgument(Argument.merge(args));
- return;
- }
- }
-
- var assignments = this.cloneAssignments();
- var names = this.getParameterNames();
-
- // Extract all the named parameters
- var used = [];
- assignments.forEach(function(assignment) {
- var namedArgText = '--' + assignment.name;
-
- var i = 0;
- while (true) {
- var arg = args[i];
- if (namedArgText !== arg.text) {
- i++;
- if (i >= args.length) {
- break;
- }
- continue;
- }
-
- // boolean parameters don't have values, default to false
- if (assignment.param.type.name === 'boolean') {
- assignment.setValue(true);
- }
- else {
- if (i + 1 < args.length) {
- // Missing value portion of this named param
- this._hints.push(new Hint(Status.INCOMPLETE,
- 'Missing value for: ' + namedArgText,
- args[i]));
- }
- else {
- args.splice(i + 1, 1);
- assignment.setArgument(args[i + 1]);
- }
- }
-
- lang.arrayRemove(names, assignment.name);
- args.splice(i, 1);
- // We don't need to i++ if we splice
- }
- }, this);
-
- // What's left are positional parameters assign in order
- names.forEach(function(name) {
- var assignment = this.getAssignment(name);
- if (args.length === 0) {
- // No more values
- assignment.setValue(undefined); // i.e. default
- }
- else {
- var arg = args[0];
- args.splice(0, 1);
- assignment.setArgument(arg);
- }
- }, this);
-
- if (args.length > 0) {
- var remaining = Argument.merge(args);
- this._hints.push(new Hint(Status.INVALID,
- 'Input \'' + remaining.text + '\' makes no sense.',
- remaining));
- }
- };
-
-})();
-exports.CliRequisition = CliRequisition;
-
-
-});
-/* ***** 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('cockpit/ui/settings', ['require', 'exports', 'module' , 'pilot/types', 'pilot/types/basic'], 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);
-};
-
-
-});
-/* ***** 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('cockpit/ui/cli_view', ['require', 'exports', 'module' , 'text!cockpit/ui/cli_view.css', 'pilot/event', 'pilot/dom', 'pilot/keys', 'pilot/canon', 'pilot/types', 'cockpit/cli', 'cockpit/ui/request_view'], function(require, exports, module) {
-
-
-var editorCss = require("text!cockpit/ui/cli_view.css");
-var event = require("pilot/event");
-var dom = require("pilot/dom");
-
-dom.importCssString(editorCss);
-
-var event = require("pilot/event");
-var keys = require("pilot/keys");
-var canon = require("pilot/canon");
-var Status = require('pilot/types').Status;
-
-var CliRequisition = require('cockpit/cli').CliRequisition;
-var Hint = require('cockpit/cli').Hint;
-var RequestView = require('cockpit/ui/request_view').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);
- data.env.cli = cli;
-};
-
-/**
- * A class to handle the simplest UI implementation
- */
-function CliView(cli, env) {
- cli.cliView = this;
- this.cli = cli;
- this.doc = document;
- this.win = dom.getParentWindow(this.doc);
- this.env = env;
-
- // TODO: we should have a better way to specify command lines???
- this.element = this.doc.getElementById('cockpitInput');
- 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.element.spellcheck = false;
-
- this.output = this.doc.getElementById('cockpitOutput');
- this.popupOutput = (this.output == null);
- if (!this.output) {
- this.output = this.doc.createElement('div');
- this.output.id = 'cockpitOutput';
- this.output.className = 'cptOutput';
- input.parentNode.insertBefore(this.output, input.nextSibling);
-
- var setMaxOutputHeight = function() {
- this.output.style.maxHeight = this.outputHeight.get() + 'px';
- }.bind(this);
- this.outputHeight.addEventListener('change', setMaxOutputHeight);
- setMaxOutputHeight();
- }
-
- this.completer = this.doc.createElement('div');
- this.completer.className = 'cptCompletion VALID';
-
- this.completer.style.color = dom.computedStyle(input, "color");
- this.completer.style.fontSize = dom.computedStyle(input, "fontSize");
- this.completer.style.fontFamily = dom.computedStyle(input, "fontFamily");
- this.completer.style.fontWeight = dom.computedStyle(input, "fontWeight");
- this.completer.style.fontStyle = dom.computedStyle(input, "fontStyle");
- input.parentNode.insertBefore(this.completer, input.nextSibling);
-
- // Transfer background styling to the completer.
- this.completer.style.backgroundColor = input.style.backgroundColor;
- input.style.backgroundColor = 'transparent';
-
- this.hinter = this.doc.createElement('div');
- this.hinter.className = 'cptHints';
- input.parentNode.insertBefore(this.hinter, input.nextSibling);
-
- var resizer = this.resizer.bind(this);
- event.addListener(this.win, 'resize', resizer);
- this.hintDirection.addEventListener('change', resizer);
- this.outputDirection.addEventListener('change', resizer);
- resizer();
-
- canon.addEventListener('output', function(ev) {
- new RequestView(ev.request, this);
- }.bind(this));
- event.addCommandKeyListener(input, this.onCommandKey.bind(this));
- event.addListener(input, 'keyup', this.onKeyUp.bind(this));
-
- // cursor position affects hint severity. TODO: shortcuts for speed
- event.addListener(input, 'mouseup', function(ev) {
- this.isUpdating = true;
- this.update();
- this.isUpdating = false;
- }.bind(this));
-
- this.cli.addEventListener('argumentChange', this.onArgChange.bind(this));
-
- event.addListener(input, "focus", function() {
- dom.addCssClass(this.output, "cptFocusPopup");
- dom.addCssClass(this.hinter, "cptFocusPopup");
- }.bind(this));
-
- function hideOutput() {
- dom.removeCssClass(this.output, "cptFocusPopup");
- dom.removeCssClass(this.hinter, "cptFocusPopup");
- };
- event.addListener(input, "blur", hideOutput.bind(this));
- hideOutput.call(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';
- var height = rect.bottom - rect.top;
- this.completer.style.height = height + 'px';
- this.completer.style.lineHeight = height + 'px';
- this.completer.style.left = rect.left + 'px';
- var width = rect.right - rect.left;
- this.completer.style.width = 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.doc.documentElement.clientHeight - rect.top) + 'px';
- }
- this.hinter.style.left = (rect.left + 30) + 'px';
- this.hinter.style.maxWidth = (width - 110) + 'px';
-
- if (this.popupOutput) {
- 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.doc.documentElement.clientHeight - rect.top) + 'px';
- }
- this.output.style.left = rect.left + 'px';
- this.output.style.width = (width - 80) + 'px';
- }
- },
-
- /**
- * Ensure that TAB isn't handled by the browser
- */
-onCommandKey: function(ev, hashId, keyCode) {
- var stopEvent;
- if (keyCode === keys.TAB ||
- keyCode === keys.UP ||
- keyCode === keys.DOWN) {
- stopEvent = true;
- } else if (hashId != 0 || keyCode != 0) {
- stopEvent = canon.execKeyCommand(this.env, 'cli', hashId, keyCode);
- }
- stopEvent && event.stopEvent(ev);
- },
-
- /**
- * 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 === keys.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?
- dom.setSelectionStart(this.element, worst.start);
- dom.setSelectionEnd(this.element, worst.end);
- }
- }
-
- this.update();
-
- // Special actions which delegate to the assignment
- var current = this.cli.getAssignmentAt(dom.getSelectionStart(this.element));
- if (current) {
- // TAB does a special complete thing
- if (ev.keyCode === keys.TAB) {
- current.complete();
- this.update();
- }
-
- // UP/DOWN look for some history
- if (ev.keyCode === keys.UP) {
- current.increment();
- this.update();
- }
- if (ev.keyCode === keys.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: dom.getSelectionStart(this.element),
- end: dom.getSelectionEnd(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
- dom.removeCssClass(this.completer, Status.VALID.toString());
- dom.removeCssClass(this.completer, Status.INCOMPLETE.toString());
- dom.removeCssClass(this.completer, Status.INVALID.toString());
-
- var completion = '> ';
- 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;
- dom.addCssClass(this.completer, 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) {
- dom.addCssClass(this.hinter, 'cptNoPopup');
- }
- else {
- dom.removeCssClass(this.hinter, 'cptNoPopup');
- }
-
- 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 += '';
- lastStatus = scores[i];
- }
- completion += this.element.value[i];
- i++;
- if (i === this.element.value.length) {
- completion += '';
- break;
- }
- if (lastStatus !== scores[i]) {
- completion += '';
- }
- }
-
- 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;
-
-
-});
-/* ***** 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('cockpit/ui/request_view', ['require', 'exports', 'module' , 'pilot/dom', 'pilot/event', 'text!cockpit/ui/request_view.html', 'pilot/domtemplate', 'text!cockpit/ui/request_view.css'], function(require, exports, module) {
-
-var dom = require("pilot/dom");
-var event = require("pilot/event");
-var requestViewHtml = require("text!cockpit/ui/request_view.html");
-var Templater = require("pilot/domtemplate").Templater;
-
-var requestViewCss = require("text!cockpit/ui/request_view.css");
-dom.importCssString(requestViewCss);
-
-/**
- * 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');
-
-/**
- * Work out the path for images.
- * TODO: This should probably live in some utility area somewhere
- */
-function imageUrl(path) {
- var dataUrl;
- try {
- dataUrl = require('text!cockpit/ui/' + path);
- } catch (e) { }
- if (dataUrl) {
- return dataUrl;
- }
-
- var filename = module.id.split('/').pop() + '.js';
- var imagePath;
-
- if (module.uri.substr(-filename.length) !== filename) {
- console.error('Can\'t work out path from module.uri/module.id');
- return path;
- }
-
- if (module.uri) {
- var end = module.uri.length - filename.length - 1;
- return module.uri.substr(0, end) + "/" + path;
- }
-
- return filename + path;
-}
-
-
-/**
- * Adds a row to the CLI output display
- */
-function RequestView(request, cliView) {
- this.request = request;
- this.cliView = cliView;
- this.imageUrl = imageUrl;
-
- // 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';
- dom.addCssClass(this.hide, 'cmd_hidden');
- dom.removeCssClass(this.show, 'cmd_hidden');
-
- event.stopPropagation(ev);
- },
-
- showOutput: function(ev) {
- this.output.style.display = 'block';
- dom.removeCssClass(this.hide, 'cmd_hidden');
- dom.addCssClass(this.show, 'cmd_hidden');
-
- event.stopPropagation(ev);
- },
-
- remove: function(ev) {
- this.cliView.output.removeChild(this.rowin);
- this.cliView.output.removeChild(this.rowout);
- event.stopPropagation(ev);
- },
-
- 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();
-
- dom.setCssClass(this.output, 'cmd_error', this.request.error);
-
- this.throb.style.display = this.request.completed ? 'none' : 'block';
- }
-};
-exports.RequestView = RequestView;
-
-
-});
-/* ***** 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 DomTemplate.
- *
- * 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) (original author)
- *
- * 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('pilot/domtemplate', ['require', 'exports', 'module' ], function(require, exports, module) {
-
-
-// WARNING: do not 'use_strict' without reading the notes in envEval;
-
-/**
- * A templater that allows one to quickly template DOM nodes.
- */
-function Templater() {
- this.scope = [];
-};
-
-/**
- * Recursive function to walk the tree processing the attributes as it goes.
- * @param node the node to process. If you pass a string in instead of a DOM
- * element, it is assumed to be an id for use with document.getElementById()
- * @param data the data to use for node processing.
- */
-Templater.prototype.processNode = function(node, data) {
- if (typeof node === 'string') {
- node = document.getElementById(node);
- }
- if (data === null || data === undefined) {
- data = {};
- }
- this.scope.push(node.nodeName + (node.id ? '#' + node.id : ''));
- try {
- // Process attributes
- if (node.attributes && node.attributes.length) {
- // We need to handle 'foreach' and 'if' first because they might stop
- // some types of processing from happening, and foreach must come first
- // because it defines new data on which 'if' might depend.
- if (node.hasAttribute('foreach')) {
- this.processForEach(node, data);
- return;
- }
- if (node.hasAttribute('if')) {
- if (!this.processIf(node, data)) {
- return;
- }
- }
- // Only make the node available once we know it's not going away
- data.__element = node;
- // It's good to clean up the attributes when we've processed them,
- // but if we do it straight away, we mess up the array index
- var attrs = Array.prototype.slice.call(node.attributes);
- for (var i = 0; i < attrs.length; i++) {
- var value = attrs[i].value;
- var name = attrs[i].name;
- this.scope.push(name);
- try {
- if (name === 'save') {
- // Save attributes are a setter using the node
- value = this.stripBraces(value);
- this.property(value, data, node);
- node.removeAttribute('save');
- } else if (name.substring(0, 2) === 'on') {
- // Event registration relies on property doing a bind
- value = this.stripBraces(value);
- var func = this.property(value, data);
- if (typeof func !== 'function') {
- this.handleError('Expected ' + value +
- ' to resolve to a function, but got ' + typeof func);
- }
- node.removeAttribute(name);
- var capture = node.hasAttribute('capture' + name.substring(2));
- node.addEventListener(name.substring(2), func, capture);
- if (capture) {
- node.removeAttribute('capture' + name.substring(2));
- }
- } else {
- // Replace references in all other attributes
- var self = this;
- var newValue = value.replace(/\$\{[^}]*\}/g, function(path) {
- return self.envEval(path.slice(2, -1), data, value);
- });
- // Remove '_' prefix of attribute names so the DOM won't try
- // to use them before we've processed the template
- if (name.charAt(0) === '_') {
- node.removeAttribute(name);
- node.setAttribute(name.substring(1), newValue);
- } else if (value !== newValue) {
- attrs[i].value = newValue;
- }
- }
- } finally {
- this.scope.pop();
- }
- }
- }
-
- // Loop through our children calling processNode. First clone them, so the
- // set of nodes that we visit will be unaffected by additions or removals.
- var childNodes = Array.prototype.slice.call(node.childNodes);
- for (var j = 0; j < childNodes.length; j++) {
- this.processNode(childNodes[j], data);
- }
-
- if (node.nodeType === Node.TEXT_NODE) {
- this.processTextNode(node, data);
- }
- } finally {
- this.scope.pop();
- }
-};
-
-/**
- * Handle
- *
- * @param path An array of strings indicating the path through the data, or
- * a string to be cut into an array using split('.')
- * @param data An object to look in for the path argument
- * @param newValue (optional) If defined, this value will replace the
- * original value for the data at the path specified.
- * @return The value pointed to by path before any
- * newValue is applied.
- */
-Templater.prototype.property = function(path, data, newValue) {
- this.scope.push(path);
- try {
- if (typeof path === 'string') {
- path = path.split('.');
- }
- var value = data[path[0]];
- if (path.length === 1) {
- if (newValue !== undefined) {
- data[path[0]] = newValue;
- }
- if (typeof value === 'function') {
- return function() {
- return value.apply(data, arguments);
- };
- }
- return value;
- }
- if (!value) {
- this.handleError('Can\'t find path=' + path);
- return null;
- }
- return this.property(path.slice(1), value, newValue);
- } finally {
- this.scope.pop();
- }
-};
-
-/**
- * Like eval, but that creates a context of the variables in env in
- * which the script is evaluated.
- * WARNING: This script uses 'with' which is generally regarded to be evil.
- * The alternative is to create a Function at runtime that takes X parameters
- * according to the X keys in the env object, and then call that function using
- * the values in the env object. This is likely to be slow, but workable.
- * @param script The string to be evaluated.
- * @param env The environment in which to eval the script.
- * @param context Optional debugging string in case of failure
- * @return The return value of the script, or the error message if the script
- * execution failed.
- */
-Templater.prototype.envEval = function(script, env, context) {
- with (env) {
- try {
- this.scope.push(context);
- return eval(script);
- } catch (ex) {
- this.handleError('Template error evaluating \'' + script + '\'', ex);
- return script;
- } finally {
- this.scope.pop();
- }
- }
-};
-
-/**
- * A generic way of reporting errors, for easy overloading in different
- * environments.
- * @param message the error message to report.
- * @param ex optional associated exception.
- */
-Templater.prototype.handleError = function(message, ex) {
- this.logError(message);
- this.logError('In: ' + this.scope.join(' > '));
- if (ex) {
- this.logError(ex);
- }
-};
-
-
-/**
- * A generic way of reporting errors, for easy overloading in different
- * environments.
- * @param message the error message to report.
- */
-Templater.prototype.logError = function(message) {
- window.console && window.console.log && console.log(message);
-};
-
-exports.Templater = Templater;
-
-
-});
-/* ***** 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):
- * Skywriter Team (skywriter@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('cockpit/commands/basic', ['require', 'exports', 'module' , 'pilot/canon'], function(require, exports, module) {
-
-
-var canon = require('pilot/canon');
-
-/**
- * '!' command
- */
-var bangCommandSpec = {
- name: 'sh',
- description: 'Execute a system command (requires server support)',
- params: [
- {
- name: 'command',
- type: 'text',
- description: 'The string to send to the os shell.'
- }
- ],
- exec: function(env, args, request) {
- var req = new XMLHttpRequest();
- req.open('GET', '/exec?args=' + args.command, true);
- req.onreadystatechange = function(ev) {
- if (req.readyState == 4) {
- if (req.status == 200) {
- request.done('' + req.responseText + '
');
- }
- }
- };
- req.send(null);
- }
-};
-
-var canon = require('pilot/canon');
-
-exports.startup = function(data, reason) {
- canon.addCommand(bangCommandSpec);
-};
-
-exports.shutdown = function(data, reason) {
- canon.removeCommand(bangCommandSpec);
-};
-
-
-});
-define("text!cockpit/ui/cli_view.css", [], "" +
- "#cockpitInput { padding-left: 16px; }" +
- "" +
- ".cptOutput { overflow: auto; position: absolute; z-index: 999; display: none; }" +
- "" +
- ".cptCompletion { padding: 0; position: absolute; z-index: -1000; }" +
- ".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 {" +
- " 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;" +
- "}" +
- "" +
- ".cptFocusPopup { display: block; }" +
- ".cptFocusPopup.cptNoPopup { display: none; }" +
- "" +
- ".cptHints ul { margin: 0; padding: 0 15px; }" +
- "" +
- ".cptGt { font-weight: bold; font-size: 120%; }" +
- "");
-
-define("text!cockpit/ui/request_view.css", [], "" +
- ".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; }" +
- "");
-
-define("text!cockpit/ui/request_view.html", [], "" +
- "" +
- "
" +
- "
" +
- "" +
- "
" +
- "
"),c.push(a.description?a.description:"(No description)"),c.push("
"),a.params&&a.params.length>0&&(c.push(""),a.params.forEach(function(a){c.push("
"));return new l(i.VALID,c.join(""),b)}};q.prototype={commandAssignment:undefined,assignmentCount:undefined,_assignments:undefined,_hints:undefined,_assignmentChanged:function(a){a.param.name==="__command"&&(this._assignments={},a.value&&a.value.params.forEach(function(a){this._assignments[a.name]=new o(a,this)},this),this.assignmentCount=Object.keys(this._assignments).length,this._dispatchEvent("commandChange",{command:a.value}))},getAssignment:function(a){var b=typeof a=="string"?a:Object.keys(this._assignments)[a];return this._assignments[b]},getParameterNames:function(){return Object.keys(this._assignments)},cloneAssignments:function(){return Object.keys(this._assignments).map(function(a){return this._assignments[a]},this)},_updateHints:function(){this.getAssignments(!0).forEach(function(a){this._hints.push(a.getHint())},this),l.sort(this._hints)},getWorstHint:function(){return this._hints[0]},getArgsObject:function(){var a={};this.getAssignments().forEach(function(b){a[b.param.name]=b.value},this);return a},getAssignments:function(a){var b=[];a===!0&&b.push(this.commandAssignment),Object.keys(this._assignments).forEach(function(a){b.push(this.getAssignment(a))},this);return b},setDefaultValues:function(){this.getAssignments().forEach(function(a){a.setValue(undefined)},this)},exec:function(){k.exec(this.commandAssignment.value,this.env,"cli",this.getArgsObject(),this.toCanonicalString())},toCanonicalString:function(){var a=[];a.push(this.commandAssignment.value.name),Object.keys(this._assignments).forEach(function(b){var c=this._assignments[b],d=c.param.type;c.value!==c.param.defaultValue&&(a.push(" "),a.push(d.stringify(c.value)))},this);return a.join("")}},f.implement(q.prototype,g),b.Requisition=q,f.inherits(r,q),function(){r.prototype.update=function(a){this.input=a,this._hints=[];var b=this._tokenize(a.typed);this._split(b),this.commandAssignment.value&&this._assign(b),this._updateHints()},r.prototype.getInputStatusMarkup=function(){var a=this.toString().split("").map(function(a){return i.VALID});this._hints.forEach(function(b){for(var c=b.start;c<=b.end;c++)b.status>a[c]&&(a[c]=b.status)},this);return a},r.prototype.toString=function(){return this.getAssignments(!0).map(function(a){return a.toString()},this).join("")};var a=r.prototype._updateHints;r.prototype._updateHints=function(){a.call(this);var b=this.input.cursor;this._hints.forEach(function(a){var c=b.start>=a.start&&b.start<=a.end,d=b.end>=a.start&&b.end<=a.end,e=c||d;!e&&a.status===i.INCOMPLETE&&(a.status=i.INVALID)},this),l.sort(this._hints)},r.prototype.getHints=function(){return this._hints},r.prototype.getAssignmentAt=function(a){var b=this.getAssignments(!0);for(var c=0;c"+d.responseText+"
")},d.send(null)}},d=a("pilot/canon");b.startup=function(a,b){d.addCommand(e)},b.shutdown=function(a,b){d.removeCommand(e)}}),define("text!cockpit/ui/cli_view.css",[],"#cockpitInput { padding-left: 16px; }.cptOutput { overflow: auto; position: absolute; z-index: 999; display: none; }.cptCompletion { padding: 0; position: absolute; z-index: -1000; }.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 { 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;}.cptFocusPopup { display: block; }.cptFocusPopup.cptNoPopup { display: none; }.cptHints ul { margin: 0; padding: 0 15px; }.cptGt { font-weight: bold; font-size: 120%; }"),define("text!cockpit/ui/request_view.css",[],".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; }"),define("text!cockpit/ui/request_view.html",[],'
|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/,R=/^[^\n\S]+/,k=/^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/,g=/^[-=]>/,D=/^(?:\n[^\n\S]*)+/,O=/^'[^\\']*(?:\\.[^\\']*)*'/,u=/^`[^\\`]*(?:\\.[^\\`]*)*`/,J=/^\/(?![\s=])[^[\/\n\\]*(?:(?:\\[\s\S]|\[[^\]\n\\]*(?:\\[\s\S][^\]\n\\]*)*])[^[\/\n\\]*)*\/[imgy]{0,4}(?!\w)/,q=/^\/{3}([\s\S]+?)\/{3}([imgy]{0,4})(?!\w)/,r=/\s+(?:#.*)?/g,C=/\n/g,p=/\n+([^\n\S]*)/g,o=/\*\//,d=/^\s*@?([$A-Za-z_][$\w\x7f-\uffff]*|['"].*['"])[^\n\S]*?[:=][^:=>]/,y=/^\s*(?:,|\??\.(?![.\d])|::)/,P=/\s+$/,G=/^(?:[-+*&|\/%=<>!.\\][<>=&|]*|and|or|is(?:nt)?|n(?:ot|ew)|delete|typeof|instanceof)$/,m=["-=","+=","/=","*=","%=","||=","&&=","?=","<<=",">>=",">>>=","&=","^=","|="],Q=["!","~","NEW","TYPEOF","DELETE","DO"],z=["&&","||","&","|","^"],N=["<<",">>",">>>"],l=["==","!=","<",">","<=",">="],B=["*","/","%"],K=["IN","OF","INSTANCEOF"],e=["TRUE","FALSE","NULL","UNDEFINED"],E=["NUMBER","REGEX","BOOL","++","--","]"],F=E.concat(")","}","THIS","IDENTIFIER","STRING"),f=["IDENTIFIER","STRING","REGEX",")","]","}","?","::","@","THIS","SUPER"],t=f.concat("NUMBER","BOOL"),x=["INDENT","OUTDENT","TERMINATOR"]}),define("ace/mode/coffee/rewriter",["require","exports","module"],function(a,b,c){var d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v=Array.prototype.indexOf||function(a){for(var b=0,c=this.length;b
"+b.unused[h]["function"]+"
";m.push("
",b.urls,"
"),b.json&&!f?m.push("/*members ",j=10;for(h=0;h
")}m.push("
"),k=" ",j=1),j+=l.length+2,b.member[i]===1&&(l=""+l+""),h