merge
3
.gitmodules
vendored
|
|
@ -19,3 +19,6 @@
|
|||
[submodule "support/node-htmlparser"]
|
||||
path = support/node-htmlparser
|
||||
url = git://github.com/tautologistics/node-htmlparser.git
|
||||
[submodule "support/cockpit"]
|
||||
path = support/cockpit
|
||||
url = git://github.com/joewalker/cockpit.git
|
||||
|
|
|
|||
61
demo/boot.js
|
|
@ -35,17 +35,36 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
setupPlugins(function(plugin_manager, settings) {
|
||||
var data = { env: { settings: settings } };
|
||||
plugin_manager.catalog.startupPlugins(data, plugin_manager.REASONS.APP_STARTUP).then(function() {
|
||||
var demo_startup = require("demo_startup");
|
||||
demo_startup.launch(data.env);
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: Yuck! A global function
|
||||
var setupPlugins = function(config, callback) {
|
||||
config = config || {};
|
||||
var setupPlugins = function(callback) {
|
||||
var config = {
|
||||
pluginDirs: {
|
||||
"../demo": {
|
||||
singleFiles: ["demo_startup"]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (!config.pluginDirs) {
|
||||
config.pluginDirs = {};
|
||||
}
|
||||
// config.pluginDirs["../lib"] = {
|
||||
// packages: ["ace"]
|
||||
// };
|
||||
config.pluginDirs["../plugins"] = {
|
||||
packages: ["pilot", "cockpit"]
|
||||
config.pluginDirs["../support/cockpit/support/pilot/lib"] = {
|
||||
packages: [ "pilot" ]
|
||||
};
|
||||
config.pluginDirs["../support/cockpit/lib"] = {
|
||||
packages: [ "cockpit" ]
|
||||
};
|
||||
|
||||
var knownPlugins = [];
|
||||
|
|
@ -99,7 +118,7 @@ var setupPlugins = function(config, callback) {
|
|||
main: "index",
|
||||
lib: "."
|
||||
});
|
||||
knownPlugins.push(packages[i]);
|
||||
knownPlugins.push(packages[i] + "/index");
|
||||
}
|
||||
}
|
||||
if (dirInfo.singleFiles) {
|
||||
|
|
@ -125,3 +144,35 @@ var setupPlugins = function(config, callback) {
|
|||
});
|
||||
});
|
||||
};
|
||||
*/
|
||||
|
||||
var config = {
|
||||
packagePaths: {
|
||||
"../lib": [
|
||||
{ name:"ace", lib: "." }
|
||||
],
|
||||
"../support/cockpit/lib": [
|
||||
{ name: "cockpit", main: "index", lib: "." }
|
||||
],
|
||||
"../support/cockpit/support/pilot/lib": [
|
||||
{ name: "pilot", main: "index", lib: "." }
|
||||
]
|
||||
},
|
||||
paths: { demo_startup: "../demo/demo_startup" }
|
||||
};
|
||||
|
||||
var deps = [ "pilot/fixoldbrowsers", "pilot/plugin_manager", "pilot/settings",
|
||||
"pilot/environment", "demo_startup" ];
|
||||
|
||||
require(config, deps, function() {
|
||||
var catalog = require("pilot/plugin_manager").catalog;
|
||||
var REASON_START = require("pilot/plugin_manager").REASONS.APP_STARTUP;
|
||||
var settings = require("pilot/settings").settings;
|
||||
|
||||
catalog.registerPlugins([ "pilot/index", "cockpit/index" ]).then(function() {
|
||||
var env = require("pilot/environment").create();
|
||||
catalog.startupPlugins({ env:env }, REASON_START).then(function() {
|
||||
require("demo_startup").launch(env);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
45
editor.html
|
|
@ -46,10 +46,24 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
#cockpit {
|
||||
#cockpitInput {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
|
||||
border: none; outline: none;
|
||||
font-family: consolas, courier, monospace;
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
#cockpitOutput {
|
||||
padding: 10px;
|
||||
margin: 0 15px;
|
||||
border: 1px solid #AAA;
|
||||
-moz-border-radius-topleft: 10px;
|
||||
-moz-border-radius-topright: 10px;
|
||||
border-top-left-radius: 4px; border-top-right-radius: 4px;
|
||||
background: #DDD; color: #000;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
|
@ -177,31 +191,10 @@ echo $output;
|
|||
|
||||
?></script>
|
||||
|
||||
<input id="cockpitInput" type="text"/>
|
||||
<input id="cockpitInput" type="text"/>
|
||||
|
||||
|
||||
<script>
|
||||
require = {
|
||||
//urlArgs: "bust=" + (new Date()).getTime()
|
||||
};
|
||||
</script>
|
||||
<script src="demo/require.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="demo/boot.js" type="text/javascript"></script>
|
||||
<script>
|
||||
setupPlugins({
|
||||
pluginDirs: {
|
||||
"../demo": {
|
||||
singleFiles: ["demo_startup"]
|
||||
}
|
||||
}
|
||||
}, function(plugin_manager, settings) {
|
||||
var data = { env: { settings: settings } };
|
||||
plugin_manager.catalog.startupPlugins(data, plugin_manager.REASONS.APP_STARTUP).then(function() {
|
||||
var demo_startup = require("demo_startup");
|
||||
demo_startup.launch(data.env);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<script src="demo/require.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="demo/boot.js" type="text/javascript"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -1,59 +0,0 @@
|
|||
/* ***** 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):
|
||||
* 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(function(require, exports, module) {
|
||||
|
||||
exports.startup = function(data, reason) {
|
||||
|
||||
require('cockpit/cli').startup(data, reason);
|
||||
window.testCli = require('cockpit/test/testCli');
|
||||
|
||||
require('cockpit/ui/settings').startup(data, reason);
|
||||
require('cockpit/ui/cliView').startup(data, reason);
|
||||
};
|
||||
|
||||
/*
|
||||
exports.shutdown(data, reason) {
|
||||
deps.forEach(function(dep) {
|
||||
var module = require(dep);
|
||||
if (typeof module.shutdown === "function") {
|
||||
module.shutdown(data, reason);
|
||||
}
|
||||
});
|
||||
};
|
||||
*/
|
||||
});
|
||||
|
|
@ -1,317 +0,0 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Skywriter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Joe Walker (jwalker@mozilla.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var test = {
|
||||
|
||||
success: function(message) {
|
||||
console.log(message);
|
||||
},
|
||||
|
||||
fail: function(message) {
|
||||
test._recordThrow("fail", arguments);
|
||||
},
|
||||
|
||||
assertTrue: function(value) {
|
||||
if (!value) {
|
||||
test._recordThrow("assertTrue", arguments);
|
||||
}
|
||||
},
|
||||
|
||||
verifyTrue: function(value) {
|
||||
if (!value) {
|
||||
test._recordTrace("verifyTrue", arguments);
|
||||
}
|
||||
},
|
||||
|
||||
assertFalse: function(value) {
|
||||
if (value) {
|
||||
test._recordThrow("assertFalse", arguments);
|
||||
}
|
||||
},
|
||||
|
||||
verifyFalse: function(value) {
|
||||
if (value) {
|
||||
test._recordTrace("verifyFalse", arguments);
|
||||
}
|
||||
},
|
||||
|
||||
assertNull: function(value) {
|
||||
if (value !== null) {
|
||||
test._recordThrow("assertNull", arguments);
|
||||
}
|
||||
},
|
||||
|
||||
verifyNull: function(value) {
|
||||
if (value !== null) {
|
||||
test._recordTrace("verifyNull", arguments);
|
||||
}
|
||||
},
|
||||
|
||||
assertNotNull: function(value) {
|
||||
if (value === null) {
|
||||
test._recordThrow("assertNotNull", arguments);
|
||||
}
|
||||
},
|
||||
|
||||
verifyNotNull: function(value) {
|
||||
if (value === null) {
|
||||
test._recordTrace("verifyNotNull", arguments);
|
||||
}
|
||||
},
|
||||
|
||||
assertUndefined: function(value) {
|
||||
if (value !== undefined) {
|
||||
test._recordThrow("assertUndefined", arguments);
|
||||
}
|
||||
},
|
||||
|
||||
verifyUndefined: function(value) {
|
||||
if (value !== undefined) {
|
||||
test._recordTrace("verifyUndefined", arguments);
|
||||
}
|
||||
},
|
||||
|
||||
assertNotUndefined: function(value) {
|
||||
if (value === undefined) {
|
||||
test._recordThrow("assertNotUndefined", arguments);
|
||||
}
|
||||
},
|
||||
|
||||
verifyNotUndefined: function(value) {
|
||||
if (value === undefined) {
|
||||
test._recordTrace("verifyNotUndefined", arguments);
|
||||
}
|
||||
},
|
||||
|
||||
assertNaN: function(value) {
|
||||
if (!isNaN(value)) {
|
||||
test._recordThrow("assertNaN", arguments);
|
||||
}
|
||||
},
|
||||
|
||||
verifyNaN: function(value) {
|
||||
if (!isNaN(value)) {
|
||||
test._recordTrace("verifyNaN", arguments);
|
||||
}
|
||||
},
|
||||
|
||||
assertNotNaN: function(value) {
|
||||
if (isNaN(value)) {
|
||||
test._recordThrow("assertNotNaN", arguments);
|
||||
}
|
||||
},
|
||||
|
||||
verifyNotNaN: function(value) {
|
||||
if (isNaN(value)) {
|
||||
test._recordTrace("verifyNotNaN", arguments);
|
||||
}
|
||||
},
|
||||
|
||||
assertEqual: function(expected, actual) {
|
||||
if (!test._isEqual(expected, actual)) {
|
||||
test._recordThrow("assertEqual", arguments);
|
||||
}
|
||||
},
|
||||
|
||||
verifyEqual: function(expected, actual) {
|
||||
if (!test._isEqual(expected, actual)) {
|
||||
test._recordTrace("verifyEqual", arguments);
|
||||
}
|
||||
},
|
||||
|
||||
assertNotEqual: function(expected, actual) {
|
||||
if (test._isEqual(expected, actual)) {
|
||||
test._recordThrow("assertNotEqual", arguments);
|
||||
}
|
||||
},
|
||||
|
||||
verifyNotEqual: function(expected, actual) {
|
||||
if (test._isEqual(expected, actual)) {
|
||||
test._recordTrace("verifyNotEqual", arguments);
|
||||
}
|
||||
},
|
||||
|
||||
assertSame: function(expected, actual) {
|
||||
if (expected !== actual) {
|
||||
test._recordThrow("assertSame", arguments);
|
||||
}
|
||||
},
|
||||
|
||||
verifySame: function(expected, actual) {
|
||||
if (expected !== actual) {
|
||||
test._recordTrace("verifySame", arguments);
|
||||
}
|
||||
},
|
||||
|
||||
assertNotSame: function(expected, actual) {
|
||||
if (expected !== actual) {
|
||||
test._recordThrow("assertNotSame", arguments);
|
||||
}
|
||||
},
|
||||
|
||||
verifyNotSame: function(expected, actual) {
|
||||
if (expected !== actual) {
|
||||
test._recordTrace("verifyNotSame", arguments);
|
||||
}
|
||||
},
|
||||
|
||||
_recordTrace: function() {
|
||||
test._record.apply(this, arguments);
|
||||
console.trace();
|
||||
},
|
||||
|
||||
_recordThrow: function() {
|
||||
test._record.apply(this, arguments);
|
||||
throw new Error();
|
||||
},
|
||||
|
||||
_record: function() {
|
||||
console.error(arguments);
|
||||
var message = arguments[0] + "(";
|
||||
var data = arguments[1];
|
||||
if (typeof data == "string") {
|
||||
message += data;
|
||||
}
|
||||
else {
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
if (i != 0){message += ", ";}
|
||||
message += data[i];
|
||||
}
|
||||
}
|
||||
message += ")";
|
||||
console.log(message);
|
||||
},
|
||||
|
||||
_isEqual: function(expected, actual, depth) {
|
||||
if (!depth){depth = 0;}
|
||||
// Rather than failing we assume that it works!
|
||||
if (depth > 10) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (expected == null) {
|
||||
if (actual != null) {
|
||||
console.log("expected: null, actual non-null: ", actual);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (typeof(expected) == "number" && isNaN(expected)) {
|
||||
if (!(typeof(actual) == "number" && isNaN(actual))) {
|
||||
console.log("expected: NaN, actual non-NaN: ", actual);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (actual == null) {
|
||||
if (expected != null) {
|
||||
console.log("actual: null, expected non-null: ", expected);
|
||||
return false;
|
||||
}
|
||||
return true; // we wont get here of course ...
|
||||
}
|
||||
|
||||
if (typeof expected == "object") {
|
||||
if (!(typeof actual == "object")) {
|
||||
console.log("expected object, actual not an object");
|
||||
return false;
|
||||
}
|
||||
|
||||
var actualLength = 0;
|
||||
for (var prop in actual) {
|
||||
if (typeof actual[prop] != "function" ||
|
||||
typeof expected[prop] != "function") {
|
||||
var nest = test._isEqual(actual[prop], expected[prop], depth + 1);
|
||||
if (typeof nest != "boolean" || !nest) {
|
||||
console.log("element '" + prop + "' does not match: " + nest);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
actualLength++;
|
||||
}
|
||||
|
||||
// need to check length too
|
||||
var expectedLength = 0;
|
||||
for (prop in expected) expectedLength++;
|
||||
if (actualLength != expectedLength) {
|
||||
console.log("expected object size = " + expectedLength +
|
||||
", actual object size = " + actualLength);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (actual != expected) {
|
||||
console.log("expected = " + expected + " (type=" + typeof expected + "), " +
|
||||
"actual = " + actual + " (type=" + typeof actual + ")");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (expected instanceof Array) {
|
||||
if (!(actual instanceof Array)) {
|
||||
console.log("expected array, actual not an array");
|
||||
return false;
|
||||
}
|
||||
if (actual.length != expected.length) {
|
||||
console.log("expected array length = " + expected.length +
|
||||
", actual array length = " + actual.length);
|
||||
return false;
|
||||
}
|
||||
for (var i = 0; i < actual.length; i++) {
|
||||
var inner = test._isEqual(actual[i], expected[i], depth + 1);
|
||||
if (typeof inner != "boolean" || !inner) {
|
||||
console.log("element " + i + " does not match: " + inner);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
exports.test = test;
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -1,359 +0,0 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Skywriter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Joe Walker (jwalker@mozilla.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
|
||||
var test = require('cockpit/test/assert').test;
|
||||
var Status = require('pilot/types').Status;
|
||||
var settings = require('pilot/settings').settings;
|
||||
var tokenize = require('cockpit/cli')._tokenize;
|
||||
var split = require('cockpit/cli')._split;
|
||||
var CliRequisition = require('cockpit/cli').CliRequisition;
|
||||
|
||||
|
||||
exports.testAll = function() {
|
||||
exports.testTokenize();
|
||||
exports.testSplit();
|
||||
exports.testCli();
|
||||
return "testAll Completed";
|
||||
};
|
||||
|
||||
exports.testTokenize = function() {
|
||||
var args;
|
||||
var cli = new CliRequisition();
|
||||
|
||||
args = cli._tokenize('');
|
||||
test.verifyEqual(1, args.length);
|
||||
test.verifyEqual('', args[0].text);
|
||||
test.verifyEqual(0, args[0].start);
|
||||
test.verifyEqual(0, args[0].end);
|
||||
test.verifyEqual('', args[0].priorSpace);
|
||||
|
||||
args = cli._tokenize('s');
|
||||
test.verifyEqual(1, args.length);
|
||||
test.verifyEqual('s', args[0].text);
|
||||
test.verifyEqual(0, args[0].start);
|
||||
test.verifyEqual(1, args[0].end);
|
||||
test.verifyEqual('', args[0].priorSpace);
|
||||
|
||||
args = cli._tokenize(' ');
|
||||
test.verifyEqual(1, args.length);
|
||||
test.verifyEqual('', args[0].text);
|
||||
test.verifyEqual(1, args[0].start);
|
||||
test.verifyEqual(1, args[0].end);
|
||||
test.verifyEqual(' ', args[0].priorSpace);
|
||||
|
||||
args = cli._tokenize('s s');
|
||||
test.verifyEqual(2, args.length);
|
||||
test.verifyEqual('s', args[0].text);
|
||||
test.verifyEqual(0, args[0].start);
|
||||
test.verifyEqual(1, args[0].end);
|
||||
test.verifyEqual('', args[0].priorSpace);
|
||||
test.verifyEqual('s', args[1].text);
|
||||
test.verifyEqual(2, args[1].start);
|
||||
test.verifyEqual(3, args[1].end);
|
||||
test.verifyEqual(' ', args[1].priorSpace);
|
||||
|
||||
args = cli._tokenize(' 1234 \'12 34\'');
|
||||
test.verifyEqual(2, args.length);
|
||||
test.verifyEqual('1234', args[0].text);
|
||||
test.verifyEqual(1, args[0].start);
|
||||
test.verifyEqual(5, args[0].end);
|
||||
test.verifyEqual(' ', args[0].priorSpace);
|
||||
test.verifyEqual('12 34', args[1].text);
|
||||
test.verifyEqual(8, args[1].start);
|
||||
test.verifyEqual(13, args[1].end);
|
||||
test.verifyEqual(' ', args[1].priorSpace);
|
||||
|
||||
args = cli._tokenize('12\'34 "12 34" \\'); // 12'34 "12 34" \
|
||||
test.verifyEqual(3, args.length);
|
||||
test.verifyEqual('12\'34', args[0].text);
|
||||
test.verifyEqual(0, args[0].start);
|
||||
test.verifyEqual(5, args[0].end);
|
||||
test.verifyEqual('', args[0].priorSpace);
|
||||
test.verifyEqual('12 34', args[1].text);
|
||||
test.verifyEqual(7, args[1].start);
|
||||
test.verifyEqual(12, args[1].end);
|
||||
test.verifyEqual(' ', args[1].priorSpace);
|
||||
test.verifyEqual('\\', args[2].text);
|
||||
test.verifyEqual(14, args[2].start);
|
||||
test.verifyEqual(15, args[2].end);
|
||||
test.verifyEqual(' ', args[2].priorSpace);
|
||||
|
||||
args = cli._tokenize('a\\ b \\t\\n\\r \\\'x\\\" \'d'); // a_b \t\n\r \'x\" 'd
|
||||
test.verifyEqual(4, args.length);
|
||||
test.verifyEqual('a b', args[0].text);
|
||||
test.verifyEqual(0, args[0].start);
|
||||
test.verifyEqual(3, args[0].end);
|
||||
test.verifyEqual('', args[0].priorSpace);
|
||||
test.verifyEqual('\t\n\r', args[1].text);
|
||||
test.verifyEqual(4, args[1].start);
|
||||
test.verifyEqual(7, args[1].end);
|
||||
test.verifyEqual(' ', args[1].priorSpace);
|
||||
test.verifyEqual('\'x"', args[2].text);
|
||||
test.verifyEqual(8, args[2].start);
|
||||
test.verifyEqual(11, args[2].end);
|
||||
test.verifyEqual(' ', args[2].priorSpace);
|
||||
test.verifyEqual('d', args[3].text);
|
||||
test.verifyEqual(13, args[3].start);
|
||||
test.verifyEqual(14, args[3].end);
|
||||
test.verifyEqual(' ', args[3].priorSpace);
|
||||
|
||||
return "testTokenize Completed";
|
||||
};
|
||||
|
||||
exports.testSplit = function() {
|
||||
var args;
|
||||
var cli = new CliRequisition();
|
||||
|
||||
args = cli._tokenize('s');
|
||||
cli._split(args);
|
||||
test.verifyEqual(1, args.length);
|
||||
test.verifyEqual('s', args[0].text);
|
||||
test.verifyNull(cli.commandAssignment.value);
|
||||
|
||||
args = cli._tokenize('set');
|
||||
cli._split(args);
|
||||
test.verifyEqual([], args);
|
||||
test.verifyEqual('set', cli.commandAssignment.value.name);
|
||||
|
||||
args = cli._tokenize('set a b');
|
||||
cli._split(args);
|
||||
test.verifyEqual('set', cli.commandAssignment.value.name);
|
||||
test.verifyEqual(2, args.length);
|
||||
test.verifyEqual('a', args[0].text);
|
||||
test.verifyEqual('b', args[1].text);
|
||||
|
||||
// TODO: add tests for sub commands
|
||||
return "testSplit Completed";
|
||||
};
|
||||
|
||||
exports.testCli = function() {
|
||||
var settingAssignment;
|
||||
var valueAssignment;
|
||||
var cli = new CliRequisition();
|
||||
var debug = true;
|
||||
var worst;
|
||||
var display;
|
||||
var statuses;
|
||||
|
||||
function update(input) {
|
||||
cli.update(input);
|
||||
|
||||
if (debug) {
|
||||
console.log('####### TEST: typed="' + input.typed +
|
||||
'" cur=' + input.cursor.start +
|
||||
' cli=', cli);
|
||||
}
|
||||
|
||||
worst = cli.getWorstHint();
|
||||
display = cli.getAssignmentAt(input.cursor.start).getHint();
|
||||
statuses = cli.getInputStatusMarkup().map(function(status) {
|
||||
return status.valueOf();
|
||||
}).join('');
|
||||
|
||||
if (cli.commandAssignment.value && cli.commandAssignment.value.name === 'set') {
|
||||
settingAssignment = cli.getAssignment('setting');
|
||||
valueAssignment = cli.getAssignment('value');
|
||||
}
|
||||
else {
|
||||
settingAssignment = undefined;
|
||||
valueAssignment = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function verifyPredictionsContains(name, predictions) {
|
||||
return predictions.every(function(prediction) {
|
||||
return name === prediction || name === prediction.name;
|
||||
}, this);
|
||||
}
|
||||
|
||||
var historyLengthSetting = settings.getSetting('historyLength');
|
||||
|
||||
update({ typed: '', cursor: { start: 0, end: 0 } });
|
||||
test.verifyEqual('', statuses);
|
||||
test.verifyEqual(1, cli._hints.length);
|
||||
test.verifyEqual(Status.INCOMPLETE, display.status);
|
||||
test.verifyEqual(0, display.start);
|
||||
test.verifyEqual(0, display.end);
|
||||
test.verifyEqual(display, worst);
|
||||
test.verifyNull(cli.commandAssignment.value);
|
||||
|
||||
update({ typed: ' ', cursor: { start: 1, end: 1 } });
|
||||
test.verifyEqual('0', statuses);
|
||||
test.verifyEqual(1, cli._hints.length);
|
||||
test.verifyEqual(Status.INCOMPLETE, display.status);
|
||||
test.verifyEqual(1, display.start);
|
||||
test.verifyEqual(1, display.end);
|
||||
test.verifyEqual(display, worst);
|
||||
test.verifyNull(cli.commandAssignment.value);
|
||||
|
||||
update({ typed: ' ', cursor: { start: 0, end: 0 } });
|
||||
test.verifyEqual('0', statuses);
|
||||
test.verifyEqual(1, cli._hints.length);
|
||||
test.verifyEqual(Status.INCOMPLETE, display.status);
|
||||
test.verifyEqual(1, display.start);
|
||||
test.verifyEqual(1, display.end);
|
||||
test.verifyEqual(display, worst);
|
||||
test.verifyNull(cli.commandAssignment.value);
|
||||
|
||||
update({ typed: 's', cursor: { start: 1, end: 1 } });
|
||||
test.verifyEqual('1', statuses);
|
||||
test.verifyEqual(1, cli._hints.length);
|
||||
test.verifyEqual(Status.INCOMPLETE, display.status);
|
||||
test.verifyEqual(0, display.start);
|
||||
test.verifyEqual(1, display.end);
|
||||
test.verifyEqual(display, worst);
|
||||
test.verifyTrue(display.predictions.length > 0);
|
||||
// This is slightly fragile because it depends on the configuration
|
||||
// TODO: Mock, but first we need a way to have a clear canon.
|
||||
test.verifyTrue(display.predictions.length < 20);
|
||||
verifyPredictionsContains('set', display.predictions);
|
||||
test.verifyNull(cli.commandAssignment.value);
|
||||
|
||||
update({ typed: 'set', cursor: { start: 3, end: 3 } });
|
||||
test.verifyEqual('000', statuses);
|
||||
test.verifyEqual(1, cli._hints.length);
|
||||
test.verifyEqual(Status.VALID, display.status);
|
||||
test.verifyEqual(0, display.start);
|
||||
test.verifyEqual(3, display.end);
|
||||
test.verifyEqual('set', cli.commandAssignment.value.name);
|
||||
|
||||
update({ typed: 'set ', cursor: { start: 4, end: 4 } });
|
||||
test.verifyEqual('0000', statuses);
|
||||
test.verifyEqual(2, cli._hints.length);
|
||||
test.verifyEqual(Status.VALID, display.status);
|
||||
test.verifyEqual(4, display.start);
|
||||
test.verifyEqual(4, display.end);
|
||||
test.verifyEqual(display, worst);
|
||||
test.verifyEqual('set', cli.commandAssignment.value.name);
|
||||
|
||||
update({ typed: 'set ', cursor: { start: 2, end: 2 } });
|
||||
test.verifyEqual('0000', statuses);
|
||||
test.verifyEqual(2, cli._hints.length);
|
||||
test.verifyEqual(Status.VALID, display.status);
|
||||
test.verifyEqual(0, display.start);
|
||||
test.verifyEqual(3, display.end);
|
||||
test.verifyEqual('set', cli.commandAssignment.value.name);
|
||||
|
||||
update({ typed: 'set h', cursor: { start: 5, end: 5 } });
|
||||
test.verifyEqual('00001', statuses);
|
||||
test.verifyEqual(2, cli._hints.length);
|
||||
test.verifyEqual(Status.INCOMPLETE, display.status);
|
||||
test.verifyEqual(4, display.start);
|
||||
test.verifyEqual(5, display.end);
|
||||
test.verifyTrue(display.predictions.length > 0);
|
||||
verifyPredictionsContains('historyLength', display.predictions);
|
||||
test.verifyEqual('set', cli.commandAssignment.value.name);
|
||||
test.verifyEqual('h', settingAssignment.arg.text);
|
||||
test.verifyEqual(undefined, settingAssignment.value);
|
||||
|
||||
update({ typed: 'set historyLengt', cursor: { start: 16, end: 16 } });
|
||||
test.verifyEqual('0000111111111111', statuses);
|
||||
test.verifyEqual(2, cli._hints.length);
|
||||
test.verifyEqual(Status.INCOMPLETE, display.status);
|
||||
test.verifyEqual(4, display.start);
|
||||
test.verifyEqual(16, display.end);
|
||||
test.verifyEqual(1, display.predictions.length);
|
||||
verifyPredictionsContains('historyLength', display.predictions);
|
||||
test.verifyEqual('set', cli.commandAssignment.value.name);
|
||||
test.verifyEqual('historyLengt', settingAssignment.arg.text);
|
||||
test.verifyEqual(undefined, settingAssignment.value);
|
||||
|
||||
update({ typed: 'set historyLengt', cursor: { start: 1, end: 1 } });
|
||||
test.verifyEqual('0000222222222222', statuses);
|
||||
test.verifyEqual(2, cli._hints.length);
|
||||
test.verifyEqual(Status.VALID, display.status);
|
||||
test.verifyEqual(0, display.start);
|
||||
test.verifyEqual(3, display.end);
|
||||
test.verifyEqual(Status.INVALID, worst.status);
|
||||
test.verifyEqual(4, worst.start);
|
||||
test.verifyEqual(16, worst.end);
|
||||
test.verifyEqual(1, worst.predictions.length);
|
||||
verifyPredictionsContains('historyLength', worst.predictions);
|
||||
test.verifyEqual('set', cli.commandAssignment.value.name);
|
||||
test.verifyEqual('historyLengt', settingAssignment.arg.text);
|
||||
test.verifyEqual(undefined, settingAssignment.value);
|
||||
|
||||
update({ typed: 'set historyLengt ', cursor: { start: 17, end: 17 } });
|
||||
// TODO: would '00002222222222220' be better?
|
||||
test.verifyEqual('00002222222222222', statuses);
|
||||
test.verifyEqual(3, cli._hints.length);
|
||||
test.verifyEqual(Status.VALID, display.status);
|
||||
test.verifyEqual(17, display.start);
|
||||
test.verifyEqual(17, display.end);
|
||||
test.verifyEqual(Status.INVALID, worst.status);
|
||||
test.verifyEqual(4, worst.start);
|
||||
test.verifyEqual(16, worst.end);
|
||||
test.verifyEqual(1, worst.predictions.length);
|
||||
verifyPredictionsContains('historyLength', worst.predictions);
|
||||
test.verifyEqual('set', cli.commandAssignment.value.name);
|
||||
test.verifyEqual('historyLengt', settingAssignment.arg.text);
|
||||
test.verifyEqual(undefined, settingAssignment.value);
|
||||
|
||||
update({ typed: 'set historyLength', cursor: { start: 17, end: 17 } });
|
||||
test.verifyEqual('00000000000000000', statuses);
|
||||
test.verifyEqual(2, cli._hints.length);
|
||||
test.verifyEqual('set', cli.commandAssignment.value.name);
|
||||
test.verifyEqual('historyLength', settingAssignment.arg.text);
|
||||
test.verifyEqual(historyLengthSetting, settingAssignment.value);
|
||||
|
||||
update({ typed: 'set historyLength ', cursor: { start: 18, end: 18 } });
|
||||
test.verifyEqual('000000000000000000', statuses);
|
||||
test.verifyEqual(3, cli._hints.length);
|
||||
test.verifyEqual('set', cli.commandAssignment.value.name);
|
||||
test.verifyEqual('historyLength', settingAssignment.arg.text);
|
||||
test.verifyEqual(historyLengthSetting, settingAssignment.value);
|
||||
|
||||
update({ typed: 'set historyLength 6', cursor: { start: 19, end: 19 } });
|
||||
test.verifyEqual('0000000000000000000', statuses);
|
||||
test.verifyEqual(3, cli._hints.length);
|
||||
test.verifyEqual('set', cli.commandAssignment.value.name);
|
||||
test.verifyEqual('historyLength', settingAssignment.arg.text);
|
||||
test.verifyEqual(historyLengthSetting, settingAssignment.value);
|
||||
test.verifyEqual('6', valueAssignment.arg.text);
|
||||
test.verifyEqual(6, valueAssignment.value);
|
||||
test.verifyEqual('number', typeof valueAssignment.value);
|
||||
|
||||
// TODO: Add test to see that a command without mandatory param causes INVALID
|
||||
|
||||
return "testCli Completed";
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Skywriter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Joe Walker (jwalker@mozilla.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
});
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
|
||||
#cockpit {
|
||||
background: transparent;
|
||||
border: none; outline: none;
|
||||
font-family: consolas, courier, monospace;
|
||||
font-size: 120%;
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.cptOutput {
|
||||
border: 1px solid #AAA;
|
||||
-moz-border-radius-topleft: 10px;
|
||||
-moz-border-radius-topright: 10px;
|
||||
border-top-left-radius: 4px; border-top-right-radius: 4px;
|
||||
padding: 10px;
|
||||
margin: 0 15px;
|
||||
background: #DDD; color: #000;
|
||||
overflow: auto;
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#cockpit:focus ~ .cptOutput {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.cptCompletion {
|
||||
color: #999;
|
||||
padding: 0 0 5px 2px;
|
||||
position: absolute;
|
||||
z-index: -1000;
|
||||
font-family: consolas, courier, monospace;
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
.cptHints {
|
||||
color: #000;
|
||||
position: absolute;
|
||||
border: 1px solid rgba(230, 230, 230, 0.8);
|
||||
background: rgba(250, 250, 250, 0.8);
|
||||
-moz-border-radius-topleft: 10px;
|
||||
-moz-border-radius-topright: 10px;
|
||||
border-top-left-radius: 10px; border-top-right-radius: 10px;
|
||||
z-index: 1000;
|
||||
padding: 8px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cptHints ul { margin: 0; padding: 0 15px; }
|
||||
|
||||
#cockpit:focus ~ .cptHints {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#cockpit:focus ~ .cptHints.cptNoHints {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cptCompletion.VALID { background: #FFF; }
|
||||
.cptCompletion.INCOMPLETE { background: #DDD; }
|
||||
.cptCompletion.INVALID { background: #DDD; }
|
||||
|
||||
.cptCompletion span { color: #FFF; }
|
||||
.cptCompletion span.INCOMPLETE { color: #DDD; border-bottom: 2px dotted #F80; }
|
||||
.cptCompletion span.INVALID { color: #DDD; border-bottom: 2px dotted #F00; }
|
||||
|
||||
span.cptPrompt { color: #66F; font-weight: bold; }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.cptHints article {
|
||||
margin-left: 25px;
|
||||
padding: 8px;
|
||||
z-index: 1;
|
||||
color: @text;
|
||||
display: block;
|
||||
border: 2px @border_bg solid;
|
||||
border-bottom: 0;
|
||||
font-size: 90%;
|
||||
-moz-border-top-colors: @border_bg @border_fg;
|
||||
-moz-border-left-colors: @border_bg @border_fg;
|
||||
-moz-border-right-colors: @border_bg @bg;
|
||||
-moz-border-radius-topleft: 10px;
|
||||
-moz-border-radius-topright: 10px;
|
||||
border-top-left-radius: 10px; border-top-right-radius: 10px;
|
||||
background: @input_bg2;
|
||||
background: -moz-linear-gradient(top, @input_bg_light, @input_bg);
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(@input_bg_light), to(@input_bg));
|
||||
-webkit-box-shadow: rgba(0, 0, 0, 0.5) 0px 1px 10px 3px;
|
||||
-moz-box-shadow: rgba(0, 0, 0, 0.5) 0px 1px 10px 3px;
|
||||
max-width: 500px;
|
||||
}
|
||||
.cptHints article h1 { font-size: 110%; text-align: center; }
|
||||
.cptHints article h2 { font-size: 95%; }
|
||||
.cptHints article h3 { font-size: 90%; }
|
||||
.cptHints article table th,
|
||||
.cptHints article label { color: @hi_text; }
|
||||
.cptHints article h1,
|
||||
.cptHints article h2,
|
||||
.cptHints article h3 { margin: 2px 0 1px 0; color: @hi_text; }
|
||||
.cptHints article p,
|
||||
.cptHints article pre,
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Global visual styles */
|
||||
.cptBrackets { color: @hi_text; }
|
||||
.cptGt { color: @theme_text; font-weight: bold; font-size: 120%; }
|
||||
|
||||
/* Use absolute positioning to put all children 100%x100% */
|
||||
.cptStack {
|
||||
position: relative;
|
||||
}
|
||||
.cptStack > * {
|
||||
position: absolute;
|
||||
top: 0; height: 100%; bottom: 0; left: 0; width: 100%; right: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* The input area */
|
||||
.cptInput {
|
||||
border-top: 1px solid @border_bg;
|
||||
background: @input_bg;
|
||||
background: -moz-linear-gradient(top, @input_bg, @input_bg2);
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(@input_bg), to(@input_bg2));
|
||||
|
||||
position: absolute;
|
||||
height: 25px; right: 0; bottom: 0; left: 0;
|
||||
}
|
||||
|
||||
.cptKbd {
|
||||
position: absolute;
|
||||
top: 0; right: 0; bottom: 0; left: 40px;
|
||||
}
|
||||
|
||||
.cptOutput input.cptCliInput {
|
||||
color: @hi_text; font-size: 120%; font-family: @fonts;
|
||||
background: transparent;
|
||||
outline: none; border: 0;
|
||||
box-shadow: none; -moz-box-shadow: none; -webkit-box-shadow: none;
|
||||
padding: 4px 0 0 0;
|
||||
width: 100%;
|
||||
}
|
||||
.cptOutput input.cptCliInput:focus {
|
||||
outline: none; border: 0;
|
||||
box-shadow: none; -moz-box-shadow: none; -webkit-box-shadow: none;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,369 +0,0 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Skywriter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Joe Walker (jwalker@mozilla.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
|
||||
var editorCss = require("text!cockpit/ui/cliView.css");
|
||||
var dom = require("pilot/dom");
|
||||
dom.importCssString(editorCss);
|
||||
|
||||
var canon = require("pilot/canon");
|
||||
var Status = require('pilot/types').Status;
|
||||
var keyutil = require('pilot/keyboard/keyutil');
|
||||
|
||||
var CliRequisition = require('cockpit/cli').CliRequisition;
|
||||
var Hint = require('cockpit/cli').Hint;
|
||||
var RequestView = require('cockpit/ui/requestView').RequestView;
|
||||
|
||||
var NO_HINT = new Hint(Status.VALID, '', 0, 0);
|
||||
|
||||
/**
|
||||
* On startup we need to:
|
||||
* 1. Add 3 sets of elements to the DOM for:
|
||||
* - command line output
|
||||
* - input hints
|
||||
* - completion
|
||||
* 2. Attach a set of events so the command line works
|
||||
*/
|
||||
exports.startup = function(data, reason) {
|
||||
var cli = new CliRequisition(data.env);
|
||||
var cliView = new CliView(cli, data.env);
|
||||
};
|
||||
|
||||
/**
|
||||
* A class to handle the simplest UI implementation
|
||||
*/
|
||||
function CliView(cli, env) {
|
||||
this.cli = cli;
|
||||
this.doc = document;
|
||||
this.win = this.doc.defaultView;
|
||||
|
||||
// TODO: we should have a better way to specify command lines???
|
||||
this.element = this.doc.getElementById('cockpit');
|
||||
if (!this.element) {
|
||||
console.log('No element with an id of cockpit. Bailing on cli');
|
||||
return;
|
||||
}
|
||||
|
||||
this.settings = env.settings;
|
||||
this.hintDirection = this.settings.getSetting('hintDirection');
|
||||
this.outputDirection = this.settings.getSetting('outputDirection');
|
||||
this.outputHeight = this.settings.getSetting('outputHeight');
|
||||
|
||||
// If the requisition tells us something has changed, we use this to know
|
||||
// if we should ignore it
|
||||
this.isUpdating = false;
|
||||
|
||||
this.createElements();
|
||||
this.update();
|
||||
}
|
||||
CliView.prototype = {
|
||||
/**
|
||||
* Create divs for completion, hints and output
|
||||
*/
|
||||
createElements: function() {
|
||||
var input = this.element;
|
||||
|
||||
this.completer = this.doc.createElement('div');
|
||||
this.completer.className = 'cptCompletion VALID';
|
||||
input.parentNode.insertBefore(this.completer, input.nextSibling);
|
||||
|
||||
this.hinter = this.doc.createElement('div');
|
||||
this.hinter.className = 'cptHints';
|
||||
input.parentNode.insertBefore(this.hinter, input.nextSibling);
|
||||
|
||||
this.output = this.doc.createElement('div');
|
||||
this.output.className = 'cptOutput';
|
||||
input.parentNode.insertBefore(this.output, input.nextSibling);
|
||||
|
||||
this.win.addEventListener('resize', this.resizer.bind(this), false);
|
||||
this.hintDirection.addEventListener('change', this.resizer.bind(this));
|
||||
this.outputDirection.addEventListener('change', this.resizer.bind(this));
|
||||
this.resizer();
|
||||
|
||||
var setMaxOutputHeight = function() {
|
||||
this.output.style.maxHeight = this.outputHeight.get() + 'px';
|
||||
}.bind(this);
|
||||
this.outputHeight.addEventListener('change', setMaxOutputHeight);
|
||||
setMaxOutputHeight();
|
||||
|
||||
canon.addEventListener('output', function(ev) {
|
||||
new RequestView(ev.request, this);
|
||||
}.bind(this));
|
||||
|
||||
keyutil.addKeyDownListener(input, this.onKeyDown.bind(this));
|
||||
input.addEventListener('keyup', this.onKeyUp.bind(this), true);
|
||||
// cursor position affects hint severity. TODO: shortcuts for speed
|
||||
input.addEventListener('mouseup', function(ev) {
|
||||
this.isUpdating = true;
|
||||
this.update();
|
||||
this.isUpdating = false;
|
||||
}.bind(this), false);
|
||||
|
||||
this.cli.addEventListener('argumentChange', this.onArgChange.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* We need to see the output of the latest command entered
|
||||
*/
|
||||
scrollOutputToBottom: function() {
|
||||
// Certain browsers have a bug such that scrollHeight is too small
|
||||
// when content does not fill the client area of the element
|
||||
var scrollHeight = Math.max(this.output.scrollHeight, this.output.clientHeight);
|
||||
this.output.scrollTop = scrollHeight - this.output.clientHeight;
|
||||
},
|
||||
|
||||
/**
|
||||
* To be called on window resize or any time we want to align the elements
|
||||
* with the input box.
|
||||
*/
|
||||
resizer: function() {
|
||||
var rect = this.element.getClientRects()[0];
|
||||
|
||||
this.completer.style.top = rect.top + 'px';
|
||||
this.completer.style.height = rect.height + 'px';
|
||||
this.completer.style.left = rect.left + 'px';
|
||||
this.completer.style.width = rect.width + 'px';
|
||||
|
||||
if (this.hintDirection.get() === 'below') {
|
||||
this.hinter.style.top = rect.bottom + 'px';
|
||||
this.hinter.style.bottom = 'auto';
|
||||
}
|
||||
else {
|
||||
this.hinter.style.top = 'auto';
|
||||
this.hinter.style.bottom = (this.win.innerHeight - rect.top) + 'px';
|
||||
}
|
||||
this.hinter.style.left = (rect.left + 30) + 'px';
|
||||
this.hinter.style.maxWidth = (rect.width - 110) + 'px';
|
||||
|
||||
if (this.outputDirection.get() === 'below') {
|
||||
this.output.style.top = rect.bottom + 'px';
|
||||
this.output.style.bottom = 'auto';
|
||||
}
|
||||
else {
|
||||
this.output.style.top = 'auto';
|
||||
this.output.style.bottom = (this.win.innerHeight - rect.top) + 'px';
|
||||
}
|
||||
this.output.style.left = rect.left + 'px';
|
||||
this.output.style.width = (rect.width - 80) + 'px';
|
||||
},
|
||||
|
||||
/**
|
||||
* Ensure that TAB isn't handled by the browser
|
||||
*/
|
||||
onKeyDown: function(ev) {
|
||||
var handled;
|
||||
// var handled = keyboardManager.processKeyEvent(ev, this, {
|
||||
// isCommandLine: true, isKeyUp: false
|
||||
// });
|
||||
if (ev.keyCode === keyutil.KeyHelper.KEY.TAB ||
|
||||
ev.keyCode === keyutil.KeyHelper.KEY.UP ||
|
||||
ev.keyCode === keyutil.KeyHelper.KEY.DOWN) {
|
||||
return true;
|
||||
}
|
||||
return handled;
|
||||
},
|
||||
|
||||
/**
|
||||
* The main keyboard processing loop
|
||||
*/
|
||||
onKeyUp: function(ev) {
|
||||
var handled;
|
||||
/*
|
||||
var handled = keyboardManager.processKeyEvent(ev, this, {
|
||||
isCommandLine: true, isKeyUp: true
|
||||
});
|
||||
*/
|
||||
|
||||
// RETURN does a special exec/highlight thing
|
||||
if (ev.keyCode === keyutil.KeyHelper.KEY.RETURN) {
|
||||
var worst = this.cli.getWorstHint();
|
||||
// Deny RETURN unless the command might work
|
||||
if (worst.status === Status.VALID) {
|
||||
this.cli.exec();
|
||||
this.element.value = '';
|
||||
}
|
||||
else {
|
||||
// If we've denied RETURN because the command was not VALID,
|
||||
// select the part of the command line that is causing problems
|
||||
// TODO: if there are 2 errors are we picking the right one?
|
||||
this.element.selectionStart = worst.start;
|
||||
this.element.selectionEnd = worst.end;
|
||||
}
|
||||
}
|
||||
|
||||
this.update();
|
||||
|
||||
// Special actions which delegate to the assignment
|
||||
var current = this.cli.getAssignmentAt(this.element.selectionStart);
|
||||
if (current) {
|
||||
// TAB does a special complete thing
|
||||
if (ev.keyCode === keyutil.KeyHelper.KEY.TAB) {
|
||||
current.complete();
|
||||
this.update();
|
||||
}
|
||||
|
||||
// UP/DOWN look for some history
|
||||
if (ev.keyCode === keyutil.KeyHelper.KEY.UP) {
|
||||
current.increment();
|
||||
this.update();
|
||||
}
|
||||
if (ev.keyCode === keyutil.KeyHelper.KEY.DOWN) {
|
||||
current.decrement();
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
|
||||
return handled;
|
||||
},
|
||||
|
||||
/**
|
||||
* Actually parse the input and make sure we're all up to date
|
||||
*/
|
||||
update: function() {
|
||||
this.isUpdating = true;
|
||||
var input = {
|
||||
typed: this.element.value,
|
||||
cursor: {
|
||||
start: this.element.selectionStart,
|
||||
end: this.element.selectionEnd
|
||||
}
|
||||
};
|
||||
this.cli.update(input);
|
||||
|
||||
var display = this.cli.getAssignmentAt(input.cursor.start).getHint();
|
||||
|
||||
// 1. Update the completer with prompt/error marker/TAB info
|
||||
this.completer.classList.remove(Status.VALID.toString());
|
||||
this.completer.classList.remove(Status.INCOMPLETE.toString());
|
||||
this.completer.classList.remove(Status.INVALID.toString());
|
||||
// TODO: borked implementation? This is modern browser only. Fix
|
||||
// dom.removeCssClass(completer, Status.VALID.toString());
|
||||
// dom.removeCssClass(completer, Status.INCOMPLETE.toString());
|
||||
// dom.removeCssClass(completer, Status.INVALID.toString());
|
||||
|
||||
var completion = '<span class="cptPrompt">></span> ';
|
||||
if (this.element.value.length > 0) {
|
||||
var scores = this.cli.getInputStatusMarkup();
|
||||
completion += this.markupStatusScore(scores);
|
||||
}
|
||||
|
||||
// Display the "-> prediction" at the end of the completer
|
||||
if (this.element.value.length > 0 &&
|
||||
display.predictions && display.predictions.length > 0) {
|
||||
var tab = display.predictions[0];
|
||||
completion += ' ⇥ ' + (tab.name ? tab.name : tab);
|
||||
}
|
||||
this.completer.innerHTML = completion;
|
||||
this.completer.classList.add(this.cli.getWorstHint().status.toString());
|
||||
// dom.addCssClass(input, this.cli.getWorstHint().status.toString());
|
||||
|
||||
// 2. Update the hint element
|
||||
var hint = '';
|
||||
if (this.element.value.length !== 0) {
|
||||
hint += display.message;
|
||||
if (display.predictions && display.predictions.length > 0) {
|
||||
hint += ': [ ';
|
||||
display.predictions.forEach(function(prediction) {
|
||||
hint += (prediction.name ? prediction.name : prediction);
|
||||
hint += ' | ';
|
||||
}, this);
|
||||
hint = hint.replace(/\| $/, ']');
|
||||
}
|
||||
}
|
||||
|
||||
this.hinter.innerHTML = hint;
|
||||
if (hint.length === 0) {
|
||||
this.hinter.classList.add('cptNoHints');
|
||||
}
|
||||
else {
|
||||
this.hinter.classList.remove('cptNoHints');
|
||||
}
|
||||
|
||||
this.isUpdating = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Markup an array of Status values with spans
|
||||
*/
|
||||
markupStatusScore: function(scores) {
|
||||
var completion = '';
|
||||
// Create mark-up
|
||||
var i = 0;
|
||||
var lastStatus = -1;
|
||||
while (true) {
|
||||
if (lastStatus !== scores[i]) {
|
||||
completion += '<span class=' + scores[i].toString() + '>';
|
||||
lastStatus = scores[i];
|
||||
}
|
||||
completion += this.element.value[i];
|
||||
i++;
|
||||
if (i === this.element.value.length) {
|
||||
completion += '</span>';
|
||||
break;
|
||||
}
|
||||
if (lastStatus !== scores[i]) {
|
||||
completion += '</span>';
|
||||
}
|
||||
}
|
||||
|
||||
return completion;
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the input element to reflect the changed argument
|
||||
*/
|
||||
onArgChange: function(ev) {
|
||||
if (this.isUpdating) {
|
||||
return;
|
||||
}
|
||||
|
||||
var prefix = this.element.value.substring(0, ev.argument.start);
|
||||
var suffix = this.element.value.substring(ev.argument.end);
|
||||
var insert = typeof ev.text === 'string' ? ev.text : ev.text.name;
|
||||
this.element.value = prefix + insert + suffix;
|
||||
// Fix the cursor.
|
||||
var insertEnd = (prefix + insert).length;
|
||||
this.element.selectionStart = insertEnd;
|
||||
this.element.selectionEnd = insertEnd;
|
||||
}
|
||||
};
|
||||
exports.CliView = CliView;
|
||||
|
||||
|
||||
});
|
||||
|
Before Width: | Height: | Size: 669 B |
|
Before Width: | Height: | Size: 42 B |
|
Before Width: | Height: | Size: 604 B |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 635 B |
|
Before Width: | Height: | Size: 11 KiB |
|
|
@ -1,39 +0,0 @@
|
|||
|
||||
.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; }
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
|
||||
<div class=cptRow>
|
||||
<!-- The div for the input (i.e. what was typed) -->
|
||||
<div class="cptRowIn" save="${rowin}"
|
||||
onclick="${copyToInput}"
|
||||
ondblclick="${executeRequest}">
|
||||
|
||||
<!-- What the user actually typed -->
|
||||
<div class="cptGt">> </div>
|
||||
<div class="cptOutTyped">${request.typed}</div>
|
||||
|
||||
<!-- The extra details that appear on hover -->
|
||||
<div class=cptHover save="${duration}"></div>
|
||||
<img class=cptHover onclick="${hideOutput}" save="${hide}"
|
||||
alt="Hide command output" _src="${imagePath}/minus.png"/>
|
||||
<img class="cptHover cptHidden" onclick="${showOutput}" save="${show}"
|
||||
alt="Show command output" _src="${imagePath}/plus.png"/>
|
||||
<img class=cptHover onclick="${remove}"
|
||||
alt="Remove this command from the history" _src="${imagePath}/closer.png"/>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- The div for the command output -->
|
||||
<div class="cptRowOut" save="${rowout}">
|
||||
<div class="cptRowOutput" save="${output}"></div>
|
||||
<img _src="${imagePath}/throbber.gif" save="${throb}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,149 +0,0 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Skywriter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Joe Walker (jwalker@mozilla.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var dom = require("pilot/dom");
|
||||
var event = require("pilot/event");
|
||||
var requestViewHtml = require("text!cockpit/ui/requestView.html");
|
||||
var Templater = require("pilot/domtemplate").Templater;
|
||||
|
||||
var requestViewCss = require("text!cockpit/ui/requestView.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');
|
||||
|
||||
/**
|
||||
* Adds a row to the CLI output display
|
||||
*/
|
||||
function RequestView(request, cliView) {
|
||||
this.request = request;
|
||||
this.cliView = cliView;
|
||||
|
||||
this.imagePath = '/plugins/ace/plugins/cockpit/lib/ui/images';
|
||||
|
||||
// Elements attached to this by the templater. For info only
|
||||
this.rowin = null;
|
||||
this.rowout = null;
|
||||
this.output = null;
|
||||
this.hide = null;
|
||||
this.show = null;
|
||||
this.duration = null;
|
||||
this.throb = null;
|
||||
|
||||
new Templater().processNode(row.cloneNode(true), this);
|
||||
|
||||
this.cliView.output.appendChild(this.rowin);
|
||||
this.cliView.output.appendChild(this.rowout);
|
||||
|
||||
this.request.addEventListener('output', this.onRequestChange.bind(this));
|
||||
};
|
||||
|
||||
RequestView.prototype = {
|
||||
/**
|
||||
* A single click on an invocation line in the console copies the command to
|
||||
* the command line
|
||||
*/
|
||||
copyToInput: function() {
|
||||
this.cliView.element.value = this.request.typed;
|
||||
},
|
||||
|
||||
/**
|
||||
* A double click on an invocation line in the console executes the command
|
||||
*/
|
||||
executeRequest: function(ev) {
|
||||
this.cliView.cli.update({
|
||||
typed: this.request.typed,
|
||||
cursor: { start:0, end:0 }
|
||||
});
|
||||
this.cliView.cli.exec();
|
||||
},
|
||||
|
||||
hideOutput: function(ev) {
|
||||
this.output.style.display = 'none';
|
||||
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;
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Skywriter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Joe Walker (jwalker@mozilla.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
|
||||
var types = require("pilot/types");
|
||||
var SelectionType = require('pilot/types/basic').SelectionType;
|
||||
|
||||
var direction = new SelectionType({
|
||||
name: 'direction',
|
||||
data: [ 'above', 'below' ]
|
||||
});
|
||||
|
||||
var hintDirectionSetting = {
|
||||
name: "hintDirection",
|
||||
description: "Are hints shown above or below the command line?",
|
||||
type: "direction",
|
||||
defaultValue: "above"
|
||||
};
|
||||
|
||||
var outputDirectionSetting = {
|
||||
name: "outputDirection",
|
||||
description: "Is the output window shown above or below the command line?",
|
||||
type: "direction",
|
||||
defaultValue: "above"
|
||||
};
|
||||
|
||||
var outputHeightSetting = {
|
||||
name: "outputHeight",
|
||||
description: "What height should the output panel be?",
|
||||
type: "number",
|
||||
defaultValue: 300
|
||||
};
|
||||
|
||||
exports.startup = function(data, reason) {
|
||||
types.registerType(direction);
|
||||
data.env.settings.addSetting(hintDirectionSetting);
|
||||
data.env.settings.addSetting(outputDirectionSetting);
|
||||
data.env.settings.addSetting(outputHeightSetting);
|
||||
};
|
||||
|
||||
exports.shutdown = function(data, reason) {
|
||||
types.unregisterType(direction);
|
||||
data.env.settings.removeSetting(hintDirectionSetting);
|
||||
data.env.settings.removeSetting(outputDirectionSetting);
|
||||
data.env.settings.removeSetting(outputHeightSetting);
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -1,342 +0,0 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Skywriter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Joe Walker (jwalker@mozilla.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var console = require('pilot/console');
|
||||
var Trace = require('pilot/stacktrace').Trace;
|
||||
var oop = require('pilot/oop');
|
||||
var EventEmitter = require('pilot/event_emitter').EventEmitter;
|
||||
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 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(param);
|
||||
}, this);
|
||||
commands[command.name] = command;
|
||||
|
||||
commandNames.push(command.name);
|
||||
commandNames.sort();
|
||||
};
|
||||
|
||||
function upgradeType(param) {
|
||||
var lookup = param.type;
|
||||
param.type = types.getType(lookup);
|
||||
if (param.type == null) {
|
||||
throw new Error('In ' + command.name + '/' + param.name +
|
||||
': can\'t find type for: ' + JSON.stringify(lookup));
|
||||
}
|
||||
}
|
||||
|
||||
function removeCommand(command) {
|
||||
var name = (typeof command === 'string' ? command : command.name);
|
||||
delete commands[name];
|
||||
lang.arrayRemove(commandNames, name);
|
||||
};
|
||||
|
||||
function getCommand(name) {
|
||||
return commands[name];
|
||||
};
|
||||
|
||||
function getCommandNames() {
|
||||
return commandNames;
|
||||
};
|
||||
|
||||
/**
|
||||
* Entry point for keyboard accelerators or anything else that knows
|
||||
* everything it needs to about the command params
|
||||
* @param command Either a command, or the name of one
|
||||
*/
|
||||
function exec(command, env, args, typed) {
|
||||
if (typeof command === 'string') {
|
||||
command = commands[command];
|
||||
}
|
||||
if (!command) {
|
||||
// TODO: Should we complain more than returning false?
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Ugg. really?
|
||||
env.selection = env.editor.getSelection();
|
||||
|
||||
var request = new Request({
|
||||
command: command,
|
||||
args: args,
|
||||
typed: typed
|
||||
});
|
||||
command.exec(env, args || {}, request);
|
||||
return true;
|
||||
};
|
||||
|
||||
exports.removeCommand = removeCommand;
|
||||
exports.addCommand = addCommand;
|
||||
exports.getCommand = getCommand;
|
||||
exports.getCommandNames = getCommandNames;
|
||||
exports.exec = exec;
|
||||
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.
|
||||
* <p>Future requirements could include:
|
||||
* <ul>
|
||||
* <li>Multiple command lines
|
||||
* <li>The ability to recall key presses (i.e. requests with no output) which
|
||||
* will likely be needed for macro recording or similar
|
||||
* <li>The ability to store the command history either on the server or in the
|
||||
* browser local storage.
|
||||
* </ul>
|
||||
* <p>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):
|
||||
* <pre>
|
||||
* var request = new Request({
|
||||
* command: command,
|
||||
* args: args,
|
||||
* typed: typed
|
||||
* });
|
||||
* </pre>
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* 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:
|
||||
* <pre>request.error = true; request.done(output);</pre>
|
||||
*/
|
||||
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() {
|
||||
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._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);
|
||||
}
|
||||
|
||||
this._dispatchEvent('output', {});
|
||||
};
|
||||
exports.Request = Request;
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
/* ***** 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):
|
||||
* 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(function(require, exports, module) {
|
||||
|
||||
|
||||
var extensionSpecs = {};
|
||||
|
||||
exports.addExtensionSpec = function(extensionSpec) {
|
||||
extensionSpecs[extensionSpec.name] = extensionSpec;
|
||||
};
|
||||
|
||||
exports.removeExtensionSpec = function(extensionSpec) {
|
||||
if (typeof extensionSpec === "string") {
|
||||
delete extensionSpecs[extensionSpec];
|
||||
}
|
||||
else {
|
||||
delete extensionSpecs[extensionSpec.name];
|
||||
}
|
||||
};
|
||||
|
||||
exports.getExtensionSpec = function(name) {
|
||||
return extensionSpecs[name];
|
||||
};
|
||||
|
||||
exports.getExtensionSpecs = function() {
|
||||
return Object.keys(extensionSpecs);
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -1,263 +0,0 @@
|
|||
/* ***** 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(function(require, exports, module) {
|
||||
|
||||
var checks = require("pilot/typecheck");
|
||||
var canon = require('pilot/canon');
|
||||
|
||||
/**
|
||||
* 'help' command
|
||||
*/
|
||||
var helpCommandSpec = {
|
||||
name: 'help',
|
||||
params: [
|
||||
{
|
||||
name: 'search',
|
||||
type: 'text',
|
||||
description: 'Search string to narrow the output.',
|
||||
defaultValue: null
|
||||
}
|
||||
],
|
||||
description: 'Get help on the available commands.',
|
||||
exec: function(env, args, request) {
|
||||
var output = [];
|
||||
|
||||
var command = canon.getCommand(args.search);
|
||||
if (command && command.exec) {
|
||||
// caught a real command
|
||||
output.push(command.description ?
|
||||
command.description :
|
||||
'No description for ' + args.search);
|
||||
} else {
|
||||
var showHidden = false;
|
||||
|
||||
if (!args.search) {
|
||||
output.push('<h2>Welcome to Skywriter - Code in the Cloud</h2><ul>' +
|
||||
'<li><a href="http://labs.mozilla.com/projects/skywriter" target="_blank">Home Page</a></li>' +
|
||||
'<li><a href="https://wiki.mozilla.org/Labs/Skywriter" target="_blank">Wiki</a></li>' +
|
||||
'<li><a href="https://wiki.mozilla.org/Labs/Skywriter/UserGuide" target="_blank">User Guide</a></li>' +
|
||||
'<li><a href="https://wiki.mozilla.org/Labs/Skywriter/Tips" target="_blank">Tips and Tricks</a></li>' +
|
||||
'<li><a href="https://wiki.mozilla.org/Labs/Skywriter/FAQ" target="_blank">FAQ</a></li>' +
|
||||
'<li><a href="https://wiki.mozilla.org/Labs/Skywriter/DeveloperGuide" target="_blank">Developers Guide</a></li>' +
|
||||
'</ul>');
|
||||
}
|
||||
|
||||
if (command) {
|
||||
// We must be looking at sub-commands
|
||||
output.push('<h2>Sub-Commands of ' + command.name + '</h2>');
|
||||
output.push('<p>' + command.description + '</p>');
|
||||
}
|
||||
else if (args.search) {
|
||||
if (args.search == 'hidden') { // sneaky, sneaky.
|
||||
args.search = '';
|
||||
showHidden = true;
|
||||
}
|
||||
output.push('<h2>Commands starting with \'' + args.search + '\':</h2>');
|
||||
}
|
||||
else {
|
||||
output.push('<h2>Available Commands:</h2>');
|
||||
}
|
||||
|
||||
var commandNames = canon.getCommandNames();
|
||||
commandNames.sort();
|
||||
|
||||
output.push('<table>');
|
||||
for (var i = 0; i < commandNames.length; i++) {
|
||||
command = canon.getCommand(commandNames[i]);
|
||||
if (!showHidden && command.hidden) {
|
||||
continue;
|
||||
}
|
||||
if (command.description === undefined) {
|
||||
// Ignore editor actions
|
||||
continue;
|
||||
}
|
||||
if (args.search && command.name.indexOf(args.search) !== 0) {
|
||||
// Filtered out by the user
|
||||
continue;
|
||||
}
|
||||
if (!args.search && command.name.indexOf(' ') != -1) {
|
||||
// sub command
|
||||
continue;
|
||||
}
|
||||
if (command && command.name == args.search) {
|
||||
// sub command, and we've already given that help
|
||||
continue;
|
||||
}
|
||||
|
||||
// todo add back a column with parameter information, perhaps?
|
||||
|
||||
output.push('<tr>');
|
||||
output.push('<th class="right">' + command.name + '</th>');
|
||||
output.push('<td>' + command.description + '</td>');
|
||||
output.push('</tr>');
|
||||
}
|
||||
output.push('</table>');
|
||||
|
||||
if (!args.search) {
|
||||
output.push('For more information, see the <a href="https://wiki.mozilla.org/Labs/Skywriter">Skywriter Wiki</a>.');
|
||||
}
|
||||
}
|
||||
|
||||
request.done(output.join(''));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 'eval' command
|
||||
*/
|
||||
var evalCommandSpec = {
|
||||
name: 'eval',
|
||||
params: [
|
||||
{
|
||||
name: 'javascript',
|
||||
type: 'text',
|
||||
description: 'The JavaScript to evaluate'
|
||||
}
|
||||
],
|
||||
description: 'evals given js code and show the result',
|
||||
hidden: true,
|
||||
exec: function(env, args, request) {
|
||||
var result;
|
||||
var javascript = args.javascript;
|
||||
try {
|
||||
result = eval(javascript);
|
||||
} catch (e) {
|
||||
result = '<b>Error: ' + e.message + '</b>';
|
||||
}
|
||||
|
||||
var msg = '';
|
||||
var type = '';
|
||||
var x;
|
||||
|
||||
if (checks.isFunction(result)) {
|
||||
// converts the function to a well formated string
|
||||
msg = (result + '').replace(/\n/g, '<br>').replace(/ /g, ' ');
|
||||
type = 'function';
|
||||
} else if (checks.isObject(result)) {
|
||||
if (Array.isArray(result)) {
|
||||
type = 'array';
|
||||
} else {
|
||||
type = 'object';
|
||||
}
|
||||
|
||||
var items = [];
|
||||
var value;
|
||||
|
||||
for (x in result) {
|
||||
if (result.hasOwnProperty(x)) {
|
||||
if (checks.isFunction(result[x])) {
|
||||
value = '[function]';
|
||||
} else if (checks.isObject(result[x])) {
|
||||
value = '[object]';
|
||||
} else {
|
||||
value = result[x];
|
||||
}
|
||||
|
||||
items.push({name: x, value: value});
|
||||
}
|
||||
}
|
||||
|
||||
items.sort(function(a,b) {
|
||||
return (a.name.toLowerCase() < b.name.toLowerCase()) ? -1 : 1;
|
||||
});
|
||||
|
||||
for (x = 0; x < items.length; x++) {
|
||||
msg += '<b>' + items[x].name + '</b>: ' + items[x].value + '<br>';
|
||||
}
|
||||
|
||||
} else {
|
||||
msg = result;
|
||||
type = typeof result;
|
||||
}
|
||||
|
||||
request.done('Result for eval <b>\'' + javascript + '\'</b>' +
|
||||
' (type: '+ type+'): <br><br>'+ msg);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 'version' command
|
||||
*/
|
||||
var versionCommandSpec = {
|
||||
name: 'version',
|
||||
description: 'show the Skywriter version',
|
||||
hidden: true,
|
||||
exec: function(env, args, request) {
|
||||
var version = 'Skywriter ' + skywriter.versionNumber + ' (' +
|
||||
skywriter.versionCodename + ')';
|
||||
request.done(version);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 'skywriter' command
|
||||
*/
|
||||
var skywriterCommandSpec = {
|
||||
name: 'skywriter',
|
||||
hidden: true,
|
||||
exec: function(env, args, request) {
|
||||
var index = Math.floor(Math.random() * messages.length);
|
||||
request.done('Skywriter ' + messages[index]);
|
||||
}
|
||||
};
|
||||
var messages = [
|
||||
'really wants you to trick it out in some way.',
|
||||
'is your Web editor.',
|
||||
'would love to be like Emacs on the Web.',
|
||||
'is written on the Web platform, so you can tweak it.'
|
||||
];
|
||||
|
||||
|
||||
var canon = require('pilot/canon');
|
||||
|
||||
exports.startup = function(data, reason) {
|
||||
canon.addCommand(helpCommandSpec);
|
||||
canon.addCommand(evalCommandSpec);
|
||||
// canon.addCommand(versionCommandSpec);
|
||||
canon.addCommand(skywriterCommandSpec);
|
||||
};
|
||||
|
||||
exports.shutdown = function(data, reason) {
|
||||
canon.removeCommand(helpCommandSpec);
|
||||
canon.removeCommand(evalCommandSpec);
|
||||
// canon.removeCommand(versionCommandSpec);
|
||||
canon.removeCommand(skywriterCommandSpec);
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
/* ***** 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(function(require, exports, module) {
|
||||
|
||||
|
||||
/**
|
||||
* CLI 'up'
|
||||
* Decrement the 'current entry' pointer
|
||||
*/
|
||||
var historyPreviousCommandSpec = {
|
||||
name: "historyPrevious",
|
||||
predicates: { isCommandLine: true, isKeyUp: true },
|
||||
key: "up",
|
||||
exec: function(args, request) {
|
||||
if (pointer > 0) {
|
||||
pointer--;
|
||||
}
|
||||
|
||||
var display = history.requests[pointer].typed;
|
||||
env.commandLine.setInput(display);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* CLI 'down'
|
||||
* Increment the 'current entry' pointer
|
||||
*/
|
||||
var historyNextCommandSpec = {
|
||||
name: "historyNext",
|
||||
predicates: { isCommandLine: true, isKeyUp: true },
|
||||
key: "down",
|
||||
exec: function(args, request) {
|
||||
if (pointer < history.requests.length) {
|
||||
pointer++;
|
||||
}
|
||||
|
||||
var display = (pointer === history.requests.length)
|
||||
? ''
|
||||
: history.requests[pointer].typed;
|
||||
|
||||
env.commandLine.setInput(display);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 'history' command
|
||||
*/
|
||||
var historyCommandSpec = {
|
||||
name: "history",
|
||||
description: "Show history of the commands",
|
||||
exec: function(args, request) {
|
||||
var output = [];
|
||||
output.push('<table>');
|
||||
var count = 1;
|
||||
|
||||
history.requests.forEach(function(request) {
|
||||
output.push('<tr>');
|
||||
output.push('<th>' + count + '</th>');
|
||||
output.push('<td>' + request.typed + '</td>');
|
||||
output.push('</tr>');
|
||||
count++;
|
||||
});
|
||||
output.push('</table>');
|
||||
|
||||
request.done(output.join(''));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The pointer to the command that we show on up|down
|
||||
*/
|
||||
var pointer = 0;
|
||||
|
||||
/**
|
||||
* Reset the pointer to the latest command execution
|
||||
*/
|
||||
exports.addedRequestOutput = function() {
|
||||
pointer = history.requests.length;
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -1,135 +0,0 @@
|
|||
/* ***** 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(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 += '<a class="setting" href="' + url +
|
||||
'" title="View external documentation on setting: ' +
|
||||
setting.name +
|
||||
'" target="_blank">' +
|
||||
setting.name +
|
||||
'</a> = ' +
|
||||
setting.value +
|
||||
'<br/>';
|
||||
});
|
||||
} else {
|
||||
// set with only a setting, shows the value for that setting
|
||||
if (args.value === undefined) {
|
||||
html = '<strong>' + setting.name + '</strong> = ' +
|
||||
setting.get();
|
||||
} else {
|
||||
// Actually change the setting
|
||||
args.setting.set(args.value);
|
||||
html = 'Setting: <strong>' + args.setting.name + '</strong> = ' +
|
||||
args.setting.get();
|
||||
}
|
||||
}
|
||||
request.done(html);
|
||||
}
|
||||
};
|
||||
|
||||
var unsetCommandSpec = {
|
||||
name: 'unset',
|
||||
params: [
|
||||
{
|
||||
name: 'setting',
|
||||
type: 'setting',
|
||||
description: 'The name of the setting to return to defaults'
|
||||
}
|
||||
],
|
||||
description: 'unset a setting entirely',
|
||||
exec: function(env, args, request) {
|
||||
var setting = env.settings.get(args.setting);
|
||||
if (!setting) {
|
||||
request.doneWithError('No setting with the name <strong>' +
|
||||
args.setting + '</strong>.');
|
||||
return;
|
||||
}
|
||||
|
||||
setting.reset();
|
||||
request.done('Reset ' + setting.name + ' to default: ' +
|
||||
env.settings.get(args.setting));
|
||||
}
|
||||
};
|
||||
|
||||
var canon = require('pilot/canon');
|
||||
|
||||
exports.startup = function(data, reason) {
|
||||
canon.addCommand(setCommandSpec);
|
||||
canon.addCommand(unsetCommandSpec);
|
||||
};
|
||||
|
||||
exports.shutdown = function(data, reason) {
|
||||
canon.removeCommand(setCommandSpec);
|
||||
canon.removeCommand(unsetCommandSpec);
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
/* ***** 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(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;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
/* ***** 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 Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org Services B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
exports.setText = function(elem, text) {
|
||||
if (elem.innerText !== undefined) {
|
||||
elem.innerText = text;
|
||||
}
|
||||
if (elem.textContent !== undefined) {
|
||||
elem.textContent = text;
|
||||
}
|
||||
};
|
||||
|
||||
exports.hasCssClass = function(el, name) {
|
||||
var classes = el.className.split(/\s+/g);
|
||||
return classes.indexOf(name) !== -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a CSS class to the list of classes on the given node
|
||||
*/
|
||||
exports.addCssClass = function(el, name) {
|
||||
if (!exports.hasCssClass(el, name)) {
|
||||
el.className += " " + name;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add or remove a CSS class from the list of classes on the given node
|
||||
* depending on the value of <tt>include</tt>
|
||||
*/
|
||||
exports.setCssClass = function(node, className, include) {
|
||||
if (include) {
|
||||
exports.addCssClass(node, className);
|
||||
} else {
|
||||
exports.removeCssClass(node, className);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove a CSS class from the list of classes on the given node
|
||||
*/
|
||||
exports.removeCssClass = function(el, name) {
|
||||
var classes = el.className.split(/\s+/g);
|
||||
while (true) {
|
||||
var index = classes.indexOf(name);
|
||||
if (index == -1) {
|
||||
break;
|
||||
}
|
||||
classes.splice(index, 1);
|
||||
}
|
||||
el.className = classes.join(" ");
|
||||
};
|
||||
|
||||
exports.importCssString = function(cssText, doc){
|
||||
doc = doc || document;
|
||||
|
||||
if (doc.createStyleSheet) {
|
||||
var sheet = doc.createStyleSheet();
|
||||
sheet.cssText = cssText;
|
||||
}
|
||||
else {
|
||||
var style = doc.createElement("style");
|
||||
style.appendChild(doc.createTextNode(cssText));
|
||||
doc.getElementsByTagName("head")[0].appendChild(style);
|
||||
}
|
||||
};
|
||||
|
||||
exports.getInnerWidth = function(element) {
|
||||
return (parseInt(exports.computedStyle(element, "paddingLeft"))
|
||||
+ parseInt(exports.computedStyle(element, "paddingRight")) + element.clientWidth);
|
||||
};
|
||||
|
||||
exports.getInnerHeight = function(element) {
|
||||
return (parseInt(exports.computedStyle(element, "paddingTop"))
|
||||
+ parseInt(exports.computedStyle(element, "paddingBottom")) + element.clientHeight);
|
||||
};
|
||||
|
||||
exports.computedStyle = function(element, style) {
|
||||
if (window.getComputedStyle) {
|
||||
return (window.getComputedStyle(element, "") || {})[style] || "";
|
||||
}
|
||||
else {
|
||||
return element.currentStyle[style];
|
||||
}
|
||||
};
|
||||
|
||||
exports.scrollbarWidth = function() {
|
||||
|
||||
var inner = document.createElement('p');
|
||||
inner.style.width = "100%";
|
||||
inner.style.height = "200px";
|
||||
|
||||
var outer = document.createElement("div");
|
||||
var style = outer.style;
|
||||
|
||||
style.position = "absolute";
|
||||
style.left = "-10000px";
|
||||
style.overflow = "hidden";
|
||||
style.width = "200px";
|
||||
style.height = "150px";
|
||||
|
||||
outer.appendChild(inner);
|
||||
document.body.appendChild(outer);
|
||||
var noScrollbar = inner.offsetWidth;
|
||||
|
||||
style.overflow = "scroll";
|
||||
var withScrollbar = inner.offsetWidth;
|
||||
|
||||
if (noScrollbar == withScrollbar) {
|
||||
withScrollbar = outer.clientWidth;
|
||||
}
|
||||
|
||||
document.body.removeChild(outer);
|
||||
|
||||
return noScrollbar-withScrollbar;
|
||||
};
|
||||
|
||||
});
|
||||
|
|
@ -1,404 +0,0 @@
|
|||
/* ***** 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(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 <x if="${...}">
|
||||
* @param node An element with an 'if' attribute
|
||||
* @param data The data to use with envEval
|
||||
* @returns true if processing should continue, false otherwise
|
||||
*/
|
||||
Templater.prototype.processIf = function(node, data) {
|
||||
this.scope.push('if');
|
||||
try {
|
||||
var originalValue = node.getAttribute('if');
|
||||
var value = this.stripBraces(originalValue);
|
||||
var recurse = true;
|
||||
try {
|
||||
var reply = this.envEval(value, data, originalValue);
|
||||
recurse = !!reply;
|
||||
} catch (ex) {
|
||||
this.handleError('Error with \'' + value + '\'', ex);
|
||||
recurse = false;
|
||||
}
|
||||
if (!recurse) {
|
||||
node.parentNode.removeChild(node);
|
||||
}
|
||||
node.removeAttribute('if');
|
||||
return recurse;
|
||||
} finally {
|
||||
this.scope.pop();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle <x foreach="param in ${array}"> and the special case of
|
||||
* <loop foreach="param in ${array}">
|
||||
* @param node An element with a 'foreach' attribute
|
||||
* @param data The data to use with envEval
|
||||
*/
|
||||
Templater.prototype.processForEach = function(node, data) {
|
||||
this.scope.push('foreach');
|
||||
try {
|
||||
var originalValue = node.getAttribute('foreach');
|
||||
var value = originalValue;
|
||||
|
||||
var paramName = 'param';
|
||||
if (value.charAt(0) === '$') {
|
||||
// No custom loop variable name. Use the default: 'param'
|
||||
value = this.stripBraces(value);
|
||||
} else {
|
||||
// Extract the loop variable name from 'NAME in ${ARRAY}'
|
||||
var nameArr = value.split(' in ');
|
||||
paramName = nameArr[0].trim();
|
||||
value = this.stripBraces(nameArr[1].trim());
|
||||
}
|
||||
node.removeAttribute('foreach');
|
||||
try {
|
||||
var self = this;
|
||||
// Process a single iteration of a loop
|
||||
var processSingle = function(member, clone, ref) {
|
||||
ref.parentNode.insertBefore(clone, ref);
|
||||
data[paramName] = member;
|
||||
self.processNode(clone, data);
|
||||
delete data[paramName];
|
||||
};
|
||||
|
||||
// processSingle is no good for <loop> nodes where we want to work on
|
||||
// the childNodes rather than the node itself
|
||||
var processAll = function(scope, member) {
|
||||
self.scope.push(scope);
|
||||
try {
|
||||
if (node.nodeName === 'LOOP') {
|
||||
for (var i = 0; i < node.childNodes.length; i++) {
|
||||
var clone = node.childNodes[i].cloneNode(true);
|
||||
processSingle(member, clone, node);
|
||||
}
|
||||
} else {
|
||||
var clone = node.cloneNode(true);
|
||||
clone.removeAttribute('foreach');
|
||||
processSingle(member, clone, node);
|
||||
}
|
||||
} finally {
|
||||
self.scope.pop();
|
||||
}
|
||||
};
|
||||
|
||||
var reply = this.envEval(value, data, originalValue);
|
||||
if (Array.isArray(reply)) {
|
||||
reply.forEach(function(data, i) {
|
||||
processAll('' + i, data);
|
||||
}, this);
|
||||
} else {
|
||||
for (var param in reply) {
|
||||
if (reply.hasOwnProperty(param)) {
|
||||
processAll(param, param);
|
||||
}
|
||||
}
|
||||
}
|
||||
node.parentNode.removeChild(node);
|
||||
} catch (ex) {
|
||||
this.handleError('Error with \'' + value + '\'', ex);
|
||||
}
|
||||
} finally {
|
||||
this.scope.pop();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Take a text node and replace it with another text node with the ${...}
|
||||
* sections parsed out. We replace the node by altering node.parentNode but
|
||||
* we could probably use a DOM Text API to achieve the same thing.
|
||||
* @param node The Text node to work on
|
||||
* @param data The data to use in calls to envEval
|
||||
*/
|
||||
Templater.prototype.processTextNode = function(node, data) {
|
||||
// Replace references in other attributes
|
||||
var value = node.data;
|
||||
// We can't use the string.replace() with function trick (see generic
|
||||
// attribute processing in processNode()) because we need to support
|
||||
// functions that return DOM nodes, so we can't have the conversion to a
|
||||
// string.
|
||||
// Instead we process the string as an array of parts. In order to split
|
||||
// the string up, we first replace '${' with '\uF001$' and '}' with '\uF002'
|
||||
// We can then split using \uF001 or \uF002 to get an array of strings
|
||||
// where scripts are prefixed with $.
|
||||
// \uF001 and \uF002 are just unicode chars reserved for private use.
|
||||
value = value.replace(/\$\{([^}]*)\}/g, '\uF001$$$1\uF002');
|
||||
var parts = value.split(/\uF001|\uF002/);
|
||||
if (parts.length > 1) {
|
||||
parts.forEach(function(part) {
|
||||
if (part === null || part === undefined || part === '') {
|
||||
return;
|
||||
}
|
||||
if (part.charAt(0) === '$') {
|
||||
part = this.envEval(part.slice(1), data, node.data);
|
||||
}
|
||||
// It looks like this was done a few lines above but see envEval
|
||||
if (part === null) {
|
||||
part = "null";
|
||||
}
|
||||
if (part === undefined) {
|
||||
part = "undefined";
|
||||
}
|
||||
// if (isDOMElement(part)) { ... }
|
||||
if (typeof part.cloneNode !== 'function') {
|
||||
part = node.ownerDocument.createTextNode(part.toString());
|
||||
}
|
||||
node.parentNode.insertBefore(part, node);
|
||||
}, this);
|
||||
node.parentNode.removeChild(node);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Warn of string does not begin '${' and end '}'
|
||||
* @param str the string to check.
|
||||
* @return The string stripped of ${ and }, or untouched if it does not match
|
||||
*/
|
||||
Templater.prototype.stripBraces = function(str) {
|
||||
if (!str.match(/\$\{.*\}/g)) {
|
||||
this.handleError('Expected ' + str + ' to match ${...}');
|
||||
return str;
|
||||
}
|
||||
return str.slice(2, -1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Combined getter and setter that works with a path through some data set.
|
||||
* For example:
|
||||
* <ul>
|
||||
* <li>property('a.b', { a: { b: 99 }}); // returns 99
|
||||
* <li>property('a', { a: { b: 99 }}); // returns { b: 99 }
|
||||
* <li>property('a', { a: { b: 99 }}, 42); // returns 99 and alters the
|
||||
* input data to be { a: { b: 42 }}
|
||||
* </ul>
|
||||
* @param path An array of strings indicating the path through the data, or
|
||||
* a string to be cut into an array using <tt>split('.')</tt>
|
||||
* @param data An object to look in for the <tt>path</tt> 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 <tt>path</tt> before any
|
||||
* <tt>newValue</tt> 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 <tt>env</tt> 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) {
|
||||
console.log(message);
|
||||
};
|
||||
|
||||
exports.Templater = Templater;
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -1,242 +0,0 @@
|
|||
/* ***** 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 Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org Services B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var useragent = require("pilot/useragent");
|
||||
|
||||
exports.addListener = function(elem, type, callback) {
|
||||
if (elem.addEventListener) {
|
||||
return elem.addEventListener(type, callback, false);
|
||||
}
|
||||
if (elem.attachEvent) {
|
||||
var wrapper = function() {
|
||||
callback(window.event);
|
||||
};
|
||||
callback._wrapper = wrapper;
|
||||
elem.attachEvent("on" + type, wrapper);
|
||||
}
|
||||
};
|
||||
|
||||
exports.removeListener = function(elem, type, callback) {
|
||||
if (elem.removeEventListener) {
|
||||
return elem.removeEventListener(type, callback, false);
|
||||
}
|
||||
if (elem.detachEvent) {
|
||||
elem.detachEvent("on" + type, callback._wrapper || callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Prevents propagation and clobbers the default action of the passed event
|
||||
*/
|
||||
exports.stopEvent = function(e) {
|
||||
exports.stopPropagation(e);
|
||||
exports.preventDefault(e);
|
||||
return false;
|
||||
};
|
||||
|
||||
exports.stopPropagation = function(e) {
|
||||
if (e.stopPropagation)
|
||||
e.stopPropagation();
|
||||
else
|
||||
e.cancelBubble = true;
|
||||
};
|
||||
|
||||
exports.preventDefault = function(e) {
|
||||
if (e.preventDefault)
|
||||
e.preventDefault();
|
||||
else
|
||||
e.returnValue = false;
|
||||
};
|
||||
|
||||
exports.getDocumentX = function(e) {
|
||||
if (e.clientX) {
|
||||
var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
|
||||
return e.clientX + scrollLeft;
|
||||
} else {
|
||||
return e.pageX;
|
||||
}
|
||||
};
|
||||
|
||||
exports.getDocumentY = function(e) {
|
||||
if (e.clientY) {
|
||||
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
|
||||
return e.clientY + scrollTop;
|
||||
} else {
|
||||
return e.pageX;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {Number} 0 for left button, 1 for middle button, 2 for right button
|
||||
*/
|
||||
exports.getButton = function(e) {
|
||||
// DOM Event
|
||||
if (e.preventDefault) {
|
||||
return e.button;
|
||||
}
|
||||
// old IE
|
||||
else {
|
||||
return Math.max(e.button - 1, 2);
|
||||
}
|
||||
};
|
||||
|
||||
if (document.documentElement.setCapture) {
|
||||
exports.capture = function(el, eventHandler, releaseCaptureHandler) {
|
||||
function onMouseMove(e) {
|
||||
eventHandler(e);
|
||||
return exports.stopPropagation(e);
|
||||
}
|
||||
|
||||
function onReleaseCapture(e) {
|
||||
eventHandler && eventHandler(e);
|
||||
releaseCaptureHandler && releaseCaptureHandler();
|
||||
|
||||
exports.removeListener(el, "mousemove", eventHandler);
|
||||
exports.removeListener(el, "mouseup", onReleaseCapture);
|
||||
exports.removeListener(el, "losecapture", onReleaseCapture);
|
||||
|
||||
el.releaseCapture();
|
||||
}
|
||||
|
||||
exports.addListener(el, "mousemove", eventHandler);
|
||||
exports.addListener(el, "mouseup", onReleaseCapture);
|
||||
exports.addListener(el, "losecapture", onReleaseCapture);
|
||||
el.setCapture();
|
||||
};
|
||||
}
|
||||
else {
|
||||
exports.capture = function(el, eventHandler, releaseCaptureHandler) {
|
||||
function onMouseMove(e) {
|
||||
eventHandler(e);
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
function onMouseUp(e) {
|
||||
eventHandler && eventHandler(e);
|
||||
releaseCaptureHandler && releaseCaptureHandler();
|
||||
|
||||
el.removeEventListener("mousemove", onMouseMove, true);
|
||||
el.removeEventListener("mouseup", onMouseUp, true);
|
||||
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
el.addEventListener("mousemove", onMouseMove, true);
|
||||
el.addEventListener("mouseup", onMouseUp, true);
|
||||
};
|
||||
}
|
||||
|
||||
exports.addMouseWheelListener = function(el, callback) {
|
||||
var listener = function(e) {
|
||||
if (e.wheelDelta !== undefined) {
|
||||
if (e.wheelDeltaX !== undefined) {
|
||||
e.wheelX = -e.wheelDeltaX / 8;
|
||||
e.wheelY = -e.wheelDeltaY / 8;
|
||||
} else {
|
||||
e.wheelX = 0;
|
||||
e.wheelY = -e.wheelDelta / 8;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (e.axis && e.axis == e.HORIZONTAL_AXIS) {
|
||||
e.wheelX = (e.detail || 0) * 5;
|
||||
e.wheelY = 0;
|
||||
} else {
|
||||
e.wheelX = 0;
|
||||
e.wheelY = (e.detail || 0) * 5;
|
||||
}
|
||||
}
|
||||
callback(e);
|
||||
};
|
||||
exports.addListener(el, "DOMMouseScroll", listener);
|
||||
exports.addListener(el, "mousewheel", listener);
|
||||
};
|
||||
|
||||
exports.addMultiMouseDownListener = function(el, button, count, timeout, callback) {
|
||||
var clicks = 0;
|
||||
var startX, startY;
|
||||
|
||||
var listener = function(e) {
|
||||
clicks += 1;
|
||||
if (clicks == 1) {
|
||||
startX = e.clientX;
|
||||
startY = e.clientY;
|
||||
|
||||
setTimeout(function() {
|
||||
clicks = 0;
|
||||
}, timeout || 600);
|
||||
}
|
||||
|
||||
if (exports.getButton(e) != button
|
||||
|| Math.abs(e.clientX - startX) > 5 || Math.abs(e.clientY - startY) > 5)
|
||||
clicks = 0;
|
||||
|
||||
if (clicks == count) {
|
||||
clicks = 0;
|
||||
callback(e);
|
||||
}
|
||||
return exports.preventDefault(e);
|
||||
};
|
||||
|
||||
exports.addListener(el, "mousedown", listener);
|
||||
useragent.isIE && exports.addListener(el, "dblclick", listener);
|
||||
};
|
||||
|
||||
exports.addKeyListener = function(el, callback) {
|
||||
var lastDown = null;
|
||||
|
||||
exports.addListener(el, "keydown", function(e) {
|
||||
lastDown = e.keyIdentifier || e.keyCode;
|
||||
return callback(e);
|
||||
});
|
||||
|
||||
// repeated keys are fired as keypress and not keydown events
|
||||
if (useragent.isMac && (useragent.isGecko || useragent.isOpera)) {
|
||||
exports.addListener(el, "keypress", function(e) {
|
||||
var keyId = e.keyIdentifier || e.keyCode;
|
||||
if (lastDown !== keyId) {
|
||||
return callback(e);
|
||||
} else {
|
||||
lastDown = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
/* ***** 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 Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org Services B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var EventEmitter = {};
|
||||
|
||||
EventEmitter._dispatchEvent = function(eventName, e) {
|
||||
this._eventRegistry = this._eventRegistry || {};
|
||||
|
||||
var listeners = this._eventRegistry[eventName];
|
||||
if (!listeners || !listeners.length) return;
|
||||
|
||||
var e = e || {};
|
||||
e.type = eventName;
|
||||
|
||||
for (var i=0; i<listeners.length; i++) {
|
||||
listeners[i](e);
|
||||
}
|
||||
};
|
||||
|
||||
EventEmitter.on =
|
||||
EventEmitter.addEventListener = function(eventName, callback) {
|
||||
this._eventRegistry = this._eventRegistry || {};
|
||||
|
||||
var listeners = this._eventRegistry[eventName];
|
||||
if (!listeners) {
|
||||
var listeners = this._eventRegistry[eventName] = [];
|
||||
}
|
||||
if (listeners.indexOf(callback) == -1) {
|
||||
listeners.push(callback);
|
||||
}
|
||||
};
|
||||
|
||||
EventEmitter.removeEventListener = function(eventName, callback) {
|
||||
this._eventRegistry = this._eventRegistry || {};
|
||||
|
||||
var listeners = this._eventRegistry[eventName];
|
||||
if (!listeners) {
|
||||
return;
|
||||
}
|
||||
var index = listeners.indexOf(callback);
|
||||
if (index !== -1) {
|
||||
listeners.splice(index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
exports.EventEmitter = EventEmitter;
|
||||
|
||||
});
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
/* ***** 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):
|
||||
* 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(function(require, exports, module) {
|
||||
|
||||
/**
|
||||
* Array detector.
|
||||
* Firefox 3.5 and Safari 4 have this already. Chrome 4 however ...
|
||||
* Note to Dojo - your isArray is still broken: instanceof doesn't work with
|
||||
* Arrays taken from a different frame/window.
|
||||
*/
|
||||
if (!Array.isArray) {
|
||||
Array.isArray = function(data) {
|
||||
return data && Object.prototype.toString.call(data) === "[object Array]";
|
||||
};
|
||||
}
|
||||
|
||||
// from MDC
|
||||
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
|
||||
if (!Array.prototype.indexOf)
|
||||
{
|
||||
Array.prototype.indexOf = function(searchElement /*, fromIndex */)
|
||||
{
|
||||
if (this === void 0 || this === null)
|
||||
throw new TypeError();
|
||||
|
||||
var t = Object(this);
|
||||
var len = t.length >>> 0;
|
||||
if (len === 0)
|
||||
return -1;
|
||||
|
||||
var n = 0;
|
||||
if (arguments.length > 0) {
|
||||
n = Number(arguments[1]);
|
||||
if (n !== n)
|
||||
n = 0;
|
||||
else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0))
|
||||
n = (n > 0 || -1) * Math.floor(Math.abs(n));
|
||||
}
|
||||
|
||||
if (n >= len)
|
||||
return -1;
|
||||
|
||||
var k = n >= 0
|
||||
? n
|
||||
: Math.max(len - Math.abs(n), 0);
|
||||
|
||||
for (; k < len; k++) {
|
||||
if (k in t && t[k] === searchElement)
|
||||
return k;
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
}
|
||||
|
||||
// from MDC
|
||||
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach
|
||||
if (!Array.prototype.forEach) {
|
||||
Array.prototype.forEach = function(fun /*, thisp */) {
|
||||
if (this === void 0 || this === null)
|
||||
throw new TypeError();
|
||||
|
||||
var t = Object(this);
|
||||
var len = t.length >>> 0;
|
||||
if (typeof fun !== "function")
|
||||
throw new TypeError();
|
||||
|
||||
var thisp = arguments[1];
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (i in t)
|
||||
fun.call(thisp, t[i], i, t);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the list of keys on an object.
|
||||
*/
|
||||
if (!Object.keys) {
|
||||
Object.keys = function(obj) {
|
||||
var k, ret = [];
|
||||
for (k in obj) {
|
||||
if (obj.hasOwnProperty(k)) {
|
||||
ret.push(k);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
|
||||
if (!Function.prototype.bind) {
|
||||
// from MDC
|
||||
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
|
||||
Function.prototype.bind = function (obj) {
|
||||
var slice = [].slice;
|
||||
var args = slice.call(arguments, 1);
|
||||
var self = this;
|
||||
var nop = function () {};
|
||||
|
||||
// optimize common case
|
||||
if (arguments.length == 1) {
|
||||
var bound = function() {
|
||||
return self.apply(this instanceof nop ? this : obj, arguments);
|
||||
};
|
||||
}
|
||||
else {
|
||||
var bound = function () {
|
||||
return self.apply(
|
||||
this instanceof nop ? this : ( obj || {} ),
|
||||
args.concat( slice.call(arguments) )
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
nop.prototype = self.prototype;
|
||||
bound.prototype = new nop();
|
||||
|
||||
// From Narwhal
|
||||
bound.name = this.name;
|
||||
bound.displayName = this.displayName;
|
||||
bound.length = this.length;
|
||||
bound.unbound = self;
|
||||
|
||||
return bound;
|
||||
};
|
||||
}
|
||||
|
||||
exports.globalsLoaded = true;
|
||||
|
||||
});
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
/* ***** 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):
|
||||
* 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 ***** */
|
||||
|
||||
var deps = [
|
||||
"pilot/fixoldbrowsers",
|
||||
"pilot/types/basic",
|
||||
"pilot/types/command",
|
||||
"pilot/types/settings",
|
||||
"pilot/commands/settings",
|
||||
"pilot/commands/basic",
|
||||
// "pilot/commands/history",
|
||||
"pilot/settings/canon",
|
||||
"pilot/canon"
|
||||
];
|
||||
|
||||
var packages = deps.slice();
|
||||
packages.unshift("require", "exports", "module");
|
||||
|
||||
define(packages, function(require, exports, module) {
|
||||
|
||||
exports.startup = function(data, reason) {
|
||||
deps.forEach(function(dep) {
|
||||
var module = require(dep);
|
||||
if (typeof module.startup === "function") {
|
||||
module.startup(data, reason);
|
||||
}
|
||||
});
|
||||
};
|
||||
/*
|
||||
exports.shutdown(data, reason) {
|
||||
deps.forEach(function(dep) {
|
||||
var module = require(dep);
|
||||
if (typeof module.shutdown === "function") {
|
||||
module.shutdown(data, reason);
|
||||
}
|
||||
});
|
||||
};
|
||||
*/
|
||||
});
|
||||
|
|
@ -1,459 +0,0 @@
|
|||
/* ***** 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(function(request, exports, module) {
|
||||
|
||||
var console = require('pilot/console');
|
||||
var Trace = require('pilot/stacktrace').Trace;
|
||||
var keyutil = require('pilot/keyboard/keyutil');
|
||||
var history = require('canon/history');
|
||||
var Request = require('canon/request').Request;
|
||||
var env = require('environment').env;
|
||||
|
||||
exports.keymappings = {};
|
||||
|
||||
exports.addKeymapping = function(mapping) {
|
||||
exports.keymappings[mapping.name] = mapping;
|
||||
};
|
||||
|
||||
exports.removeKeymapping = function(name) {
|
||||
delete exports.keymapping[name];
|
||||
};
|
||||
|
||||
exports.startup = function(data, reason) {
|
||||
var settings = data.env.settings;
|
||||
// TODO register this
|
||||
// catalog.addExtensionSpec("keymapping", {
|
||||
// "description": "A keymapping defines how keystrokes are interpreted.",
|
||||
// "params": [
|
||||
// {
|
||||
// "name": "states",
|
||||
// "required": true,
|
||||
// "description":
|
||||
// "Holds the states and all the informations about the keymapping. See docs: pluginguide/keymapping"
|
||||
// }
|
||||
// ]
|
||||
// });
|
||||
settings.settingChange.add({
|
||||
match: "customKeymapping",
|
||||
ref: exports.keyboardManager,
|
||||
func: exports.keyboardManager._customKeymappingChanged
|
||||
.bind(exports.keyboardManager)
|
||||
});
|
||||
};
|
||||
|
||||
exports.shutdown = function(data, reason) {
|
||||
var settings = data.env.settings;
|
||||
settings.settingChange.remove(exports.keyboardManager);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Things to do to sanitize this code:
|
||||
* - 'no command' is a bizarre special value at the very least it should be a
|
||||
* constant to make typos more obvious, but it would be better to refactor
|
||||
* so that a natural value like null worked.
|
||||
* - sender seems to be totally customized to the editor case, and the functions
|
||||
* that we assume that it has make no sense for the commandLine case. We
|
||||
* should either document and implement the same function set for both cases
|
||||
* or admit that the cases are different enough to have separate
|
||||
* implementations.
|
||||
* - remove remaining sproutcore-isms
|
||||
* - fold buildFlags into processKeyEvent or something better, preferably the
|
||||
* latter. We don't want the environment to become a singleton
|
||||
*/
|
||||
|
||||
/**
|
||||
* Every time we call processKeyEvent, we pass in some flags that require the
|
||||
* same processing to set them up. This function can be called to do that
|
||||
* setup.
|
||||
* @param env Probably environment.env
|
||||
* @param flags Probably {} (but check other places where this is called)
|
||||
*/
|
||||
exports.buildFlags = function(flags) {
|
||||
flags.context = env.contexts[0];
|
||||
return flags;
|
||||
};
|
||||
|
||||
/**
|
||||
* The canon, or the repository of commands, contains functions to process
|
||||
* events and dispatch command messages to targets.
|
||||
* @class
|
||||
*/
|
||||
var KeyboardManager = function() { };
|
||||
|
||||
KeyboardManager.prototype = {
|
||||
_customKeymappingCache: { states: {} },
|
||||
|
||||
/**
|
||||
* Searches through the command canon for an event matching the given flags
|
||||
* with a key equivalent matching the given SproutCore event, and, if the
|
||||
* command is found, sends a message to the appropriate target.
|
||||
*
|
||||
* This will get a couple of upgrades in the not-too-distant future:
|
||||
* 1. caching in the Canon for fast lookup based on key
|
||||
* 2. there will be an extra layer in between to allow remapping via
|
||||
* user preferences and keyboard mapping plugins
|
||||
*
|
||||
* @return True if a matching command was found, false otherwise.
|
||||
*/
|
||||
processKeyEvent: function(evt, sender, flags) {
|
||||
// Use our modified commandCodes function to detect the meta key in
|
||||
// more circumstances than SproutCore alone does.
|
||||
var symbolicName = keyutil.commandCodes(evt, true)[0];
|
||||
if (util.none(symbolicName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Maybe it should be the job of our caller to do this?
|
||||
exports.buildFlags(flags);
|
||||
|
||||
flags.isCommandKey = true;
|
||||
return this._matchCommand(symbolicName, sender, flags);
|
||||
},
|
||||
|
||||
_matchCommand: function(symbolicName, sender, flags) {
|
||||
var match = this._findCommandExtension(symbolicName, sender, flags);
|
||||
if (match && match.commandExt !== 'no command') {
|
||||
if (flags.isTextView) {
|
||||
sender.resetKeyBuffers();
|
||||
}
|
||||
|
||||
var commandExt = match.commandExt;
|
||||
commandExt.load(function(command) {
|
||||
var request = new Request({
|
||||
command: command,
|
||||
commandExt: commandExt
|
||||
});
|
||||
history.execute(match.args, request);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
// 'no command' is returned if a keyevent is handled but there is no
|
||||
// command executed (for example when switchting the keyboard state).
|
||||
if (match && match.commandExt === 'no command') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
_buildBindingsRegex: function(bindings) {
|
||||
// Escape a given Regex string.
|
||||
bindings.forEach(function(binding) {
|
||||
if (!util.none(binding.key)) {
|
||||
binding.key = new RegExp('^' + binding.key + '$');
|
||||
} else if (Array.isArray(binding.regex)) {
|
||||
binding.key = new RegExp('^' + binding.regex[1] + '$');
|
||||
binding.regex = new RegExp(binding.regex.join('') + '$');
|
||||
} else {
|
||||
binding.regex = new RegExp(binding.regex + '$');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Build the RegExp from the keymapping as RegExp can't stored directly
|
||||
* in the metadata JSON and as the RegExp used to match the keys/buffer
|
||||
* need to be adapted.
|
||||
*/
|
||||
_buildKeymappingRegex: function(keymapping) {
|
||||
for (state in keymapping.states) {
|
||||
this._buildBindingsRegex(keymapping.states[state]);
|
||||
}
|
||||
keymapping._convertedRegExp = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Loop through the commands in the canon, looking for something that
|
||||
* matches according to #_commandMatches, and return that.
|
||||
*/
|
||||
_findCommandExtension: function(symbolicName, sender, flags) {
|
||||
// If the flags indicate that we handle the textView's input then take
|
||||
// a look at keymappings as well.
|
||||
if (flags.isTextView) {
|
||||
var currentState = sender._keyState;
|
||||
|
||||
// Don't add the symbolic name to the key buffer if the alt_ key is
|
||||
// part of the symbolic name. If it starts with alt_, this means
|
||||
// that the user hit an alt keycombo and there will be a single,
|
||||
// new character detected after this event, which then will be
|
||||
// added to the buffer (e.g. alt_j will result in ∆).
|
||||
if (!flags.isCommandKey || symbolicName.indexOf('alt_') === -1) {
|
||||
sender._keyBuffer +=
|
||||
symbolicName.replace(/ctrl_meta|meta/,'ctrl');
|
||||
sender._keyMetaBuffer += symbolicName;
|
||||
}
|
||||
|
||||
// List of all the keymappings to look at.
|
||||
var ak = [ this._customKeymappingCache ];
|
||||
|
||||
// Get keymapping extension points.
|
||||
ak = ak.concat(catalog.getExtensions('keymapping'));
|
||||
|
||||
for (var i = 0; i < ak.length; i++) {
|
||||
// Check if the keymapping has the current state.
|
||||
if (util.none(ak[i].states[currentState])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (util.none(ak[i]._convertedRegExp)) {
|
||||
this._buildKeymappingRegex(ak[i]);
|
||||
}
|
||||
|
||||
// Try to match the current mapping.
|
||||
var result = this._bindingsMatch(
|
||||
symbolicName,
|
||||
flags,
|
||||
sender,
|
||||
ak[i]);
|
||||
|
||||
if (!util.none(result)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var commandExts = catalog.getExtensions('command');
|
||||
var reply = null;
|
||||
var args = {};
|
||||
|
||||
symbolicName = symbolicName.replace(/ctrl_meta|meta/,'ctrl');
|
||||
|
||||
commandExts.some(function(commandExt) {
|
||||
if (this._commandMatches(commandExt, symbolicName, flags)) {
|
||||
reply = commandExt;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}.bind(this));
|
||||
|
||||
return util.none(reply) ? null : { commandExt: reply, args: args };
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the given parameters fit to one binding in the given bindings.
|
||||
* Returns the command and arguments if a command was matched.
|
||||
*/
|
||||
_bindingsMatch: function(symbolicName, flags, sender, keymapping) {
|
||||
var match;
|
||||
var commandExt = null;
|
||||
var args = {};
|
||||
var bufferToUse;
|
||||
|
||||
if (!util.none(keymapping.hasMetaKey)) {
|
||||
bufferToUse = sender._keyBuffer;
|
||||
} else {
|
||||
bufferToUse = sender._keyMetaBuffer;
|
||||
}
|
||||
|
||||
// Add the alt_key to the buffer as we don't want it to be in the buffer
|
||||
// that is saved but for matching, it needs to be there.
|
||||
if (symbolicName.indexOf('alt_') === 0 && flags.isCommandKey) {
|
||||
bufferToUse += symbolicName;
|
||||
}
|
||||
|
||||
// Loop over all the bindings of the keymapp until a match is found.
|
||||
keymapping.states[sender._keyState].some(function(binding) {
|
||||
// Check if the key matches.
|
||||
if (binding.key && !binding.key.test(symbolicName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the regex matches.
|
||||
if (binding.regex && !(match = binding.regex.exec(bufferToUse))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for disallowed matches.
|
||||
if (binding.disallowMatches) {
|
||||
for (var i = 0; i < binding.disallowMatches.length; i++) {
|
||||
if (!!match[binding.disallowMatches[i]]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check predicates.
|
||||
if (!exports.flagsMatch(binding.predicates, flags)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If there is a command to execute, then figure out the
|
||||
// comand and the arguments.
|
||||
if (binding.exec) {
|
||||
// Get the command.
|
||||
commandExt = catalog.getExtensionByKey('command', binding.exec);
|
||||
if (util.none(commandExt)) {
|
||||
throw new Error('Can\'t find command ' + binding.exec +
|
||||
' in state=' + sender._keyState +
|
||||
', symbolicName=' + symbolicName);
|
||||
}
|
||||
|
||||
// Bulid the arguments.
|
||||
if (binding.params) {
|
||||
var value;
|
||||
binding.params.forEach(function(param) {
|
||||
if (!util.none(param.match) && !util.none(match)) {
|
||||
value = match[param.match] || param.defaultValue;
|
||||
} else {
|
||||
value = param.defaultValue;
|
||||
}
|
||||
|
||||
if (param.type === 'number') {
|
||||
value = parseInt(value, 10);
|
||||
}
|
||||
|
||||
args[param.name] = value;
|
||||
});
|
||||
}
|
||||
sender.resetKeyBuffers();
|
||||
}
|
||||
|
||||
// Handle the 'then' property.
|
||||
if (binding.then) {
|
||||
sender._keyState = binding.then;
|
||||
sender.resetKeyBuffers();
|
||||
}
|
||||
|
||||
// If there is no command matched now, then return a 'false'
|
||||
// command to stop matching.
|
||||
if (util.none(commandExt)) {
|
||||
commandExt = 'no command';
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if (util.none(commandExt)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return { commandExt: commandExt, args: args };
|
||||
},
|
||||
|
||||
/**
|
||||
* Check that the given command fits the given key name and flags.
|
||||
*/
|
||||
_commandMatches: function(commandExt, symbolicName, flags) {
|
||||
var mappedKeys = commandExt.key;
|
||||
if (!mappedKeys) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check predicates
|
||||
if (!exports.flagsMatch(commandExt.predicates, flags)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof(mappedKeys) === 'string') {
|
||||
if (mappedKeys != symbolicName) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!Array.isArray(mappedKeys)) {
|
||||
mappedKeys = [mappedKeys];
|
||||
commandExt.key = mappedKeys;
|
||||
}
|
||||
|
||||
for (var i = 0; i < mappedKeys.length; i++) {
|
||||
var keymap = mappedKeys[i];
|
||||
if (typeof(keymap) === 'string') {
|
||||
if (keymap == symbolicName) {
|
||||
return true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (keymap.key != symbolicName) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return exports.flagsMatch(keymap.predicates, flags);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Build a cache of custom keymappings whenever the associated setting
|
||||
* changes.
|
||||
*/
|
||||
_customKeymappingChanged: function(settingName, value) {
|
||||
var ckc = this._customKeymappingCache =
|
||||
JSON.parse(value);
|
||||
|
||||
ckc.states = ckc.states || {};
|
||||
|
||||
for (state in ckc.states) {
|
||||
this._buildBindingsRegex(ckc.states[state]);
|
||||
}
|
||||
ckc._convertedRegExp = true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
exports.flagsMatch = function(predicates, flags) {
|
||||
if (util.none(predicates)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!flags) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var flagName in predicates) {
|
||||
if (flags[flagName] !== predicates[flagName]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* The global exported KeyboardManager
|
||||
*/
|
||||
exports.keyboardManager = new KeyboardManager();
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -1,273 +0,0 @@
|
|||
/*! @license
|
||||
==========================================================================
|
||||
SproutCore -- JavaScript Application Framework
|
||||
copyright 2006-2009, Sprout Systems Inc., Apple Inc. and contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
SproutCore and the SproutCore logo are trademarks of Sprout Systems, Inc.
|
||||
|
||||
For more information about SproutCore, visit http://www.sproutcore.com
|
||||
|
||||
|
||||
==========================================================================
|
||||
@license */
|
||||
|
||||
// Most of the following code is taken from SproutCore with a few changes.
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var event = require('pilot/event');
|
||||
var useragent = require('pilot/useragent');
|
||||
|
||||
/**
|
||||
* Helper functions and hashes for key handling.
|
||||
*/
|
||||
exports.KeyHelper = function() {
|
||||
var ret = {
|
||||
MODIFIER_KEYS: {
|
||||
16: 'shift', 17: 'ctrl', 18: 'alt', 224: 'meta'
|
||||
},
|
||||
|
||||
FUNCTION_KEYS : {
|
||||
8: 'backspace', 9: 'tab', 13: 'return', 19: 'pause',
|
||||
27: 'escape', 33: 'pageup', 34: 'pagedown', 35: 'end',
|
||||
36: 'home', 37: 'left', 38: 'up', 39: 'right',
|
||||
40: 'down', 44: 'printscreen', 45: 'insert', 46: 'delete',
|
||||
112: 'f1', 113: 'f2', 114: 'f3', 115: 'f4',
|
||||
116: 'f5', 117: 'f7', 119: 'f8', 120: 'f9',
|
||||
121: 'f10', 122: 'f11', 123: 'f12', 144: 'numlock',
|
||||
145: 'scrolllock'
|
||||
},
|
||||
|
||||
PRINTABLE_KEYS: {
|
||||
32: ' ', 48: '0', 49: '1', 50: '2', 51: '3', 52: '4', 53: '5',
|
||||
54: '6', 55: '7', 56: '8', 57: '9', 59: ';', 61: '=', 65: 'a',
|
||||
66: 'b', 67: 'c', 68: 'd', 69: 'e', 70: 'f', 71: 'g', 72: 'h',
|
||||
73: 'i', 74: 'j', 75: 'k', 76: 'l', 77: 'm', 78: 'n', 79: 'o',
|
||||
80: 'p', 81: 'q', 82: 'r', 83: 's', 84: 't', 85: 'u', 86: 'v',
|
||||
87: 'w', 88: 'x', 89: 'y', 90: 'z', 107: '+', 109: '-', 110: '.',
|
||||
188: ',', 190: '.', 191: '/', 192: '`', 219: '[', 220: '\\',
|
||||
221: ']', 222: '\"'
|
||||
},
|
||||
|
||||
/**
|
||||
* Create the lookup table for Firefox to convert charCodes to keyCodes
|
||||
* in the keyPress event.
|
||||
*/
|
||||
PRINTABLE_KEYS_CHARCODE: {},
|
||||
|
||||
/**
|
||||
* Allow us to lookup keyCodes by symbolic name rather than number
|
||||
*/
|
||||
KEY: {}
|
||||
};
|
||||
|
||||
// Create the PRINTABLE_KEYS_CHARCODE hash.
|
||||
for (var i in ret.PRINTABLE_KEYS) {
|
||||
var k = ret.PRINTABLE_KEYS[i];
|
||||
ret.PRINTABLE_KEYS_CHARCODE[k.charCodeAt(0)] = i;
|
||||
if (k.toUpperCase() != k) {
|
||||
ret.PRINTABLE_KEYS_CHARCODE[k.toUpperCase().charCodeAt(0)] = i;
|
||||
}
|
||||
}
|
||||
|
||||
// A reverse map of FUNCTION_KEYS
|
||||
for (i in ret.FUNCTION_KEYS) {
|
||||
var name = ret.FUNCTION_KEYS[i].toUpperCase();
|
||||
ret.KEY[name] = parseInt(i, 10);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}();
|
||||
|
||||
/**
|
||||
* Determines if the keyDown event is a non-printable or function key.
|
||||
* These kinds of events are processed as keyboard shortcuts.
|
||||
* If no shortcut handles the event, then it will be sent as a regular
|
||||
* keyDown event.
|
||||
* @private
|
||||
*/
|
||||
var isFunctionOrNonPrintableKey = function(evt) {
|
||||
return !!(evt.altKey || evt.ctrlKey || evt.metaKey ||
|
||||
((evt.charCode !== evt.which) &&
|
||||
exports.KeyHelper.FUNCTION_KEYS[evt.which]));
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns character codes for the event.
|
||||
* The first value is the normalized code string, with any Shift or Ctrl
|
||||
* characters added to the beginning.
|
||||
* The second value is the char string by itself.
|
||||
* @return {Array}
|
||||
*/
|
||||
exports.commandCodes = function(evt, dontIgnoreMeta) {
|
||||
var code = evt._keyCode || evt.keyCode;
|
||||
var charCode = (evt._charCode === undefined ? evt.charCode : evt._charCode);
|
||||
var ret = null;
|
||||
var key = null;
|
||||
var modifiers = '';
|
||||
var lowercase;
|
||||
var allowShift = true;
|
||||
|
||||
// Absent a value for 'keyCode' or 'which', we can't compute the
|
||||
// command codes. Bail out.
|
||||
if (code === 0 && evt.which === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the charCode is not zero, then we do not handle a command key
|
||||
// here. Bail out.
|
||||
if (charCode !== 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for modifier keys.
|
||||
if (exports.KeyHelper.MODIFIER_KEYS[charCode]) {
|
||||
return [exports.KeyHelper.MODIFIER_KEYS[charCode], null];
|
||||
}
|
||||
|
||||
// handle function keys.
|
||||
if (code) {
|
||||
ret = exports.KeyHelper.FUNCTION_KEYS[code];
|
||||
if (!ret && (evt.altKey || evt.ctrlKey || evt.metaKey)) {
|
||||
ret = exports.KeyHelper.PRINTABLE_KEYS[code];
|
||||
// Don't handle the shift key if the combo is
|
||||
// (meta_|ctrl_)<number>
|
||||
// This is necessary for the French keyboard. On that keyboard,
|
||||
// you have to hold down the shift key to access the number
|
||||
// characters.
|
||||
if (code > 47 && code < 58) {
|
||||
allowShift = evt.altKey;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
if (evt.altKey) {
|
||||
modifiers += 'alt_';
|
||||
}
|
||||
if (evt.ctrlKey) {
|
||||
modifiers += 'ctrl_';
|
||||
}
|
||||
if (evt.metaKey) {
|
||||
modifiers += 'meta_';
|
||||
}
|
||||
} else if (evt.ctrlKey || evt.metaKey) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise just go get the right key.
|
||||
if (!ret) {
|
||||
code = evt.which;
|
||||
key = ret = String.fromCharCode(code);
|
||||
lowercase = ret.toLowerCase();
|
||||
|
||||
if (evt.metaKey) {
|
||||
modifiers = 'meta_';
|
||||
ret = lowercase;
|
||||
|
||||
} else ret = null;
|
||||
}
|
||||
|
||||
if (evt.shiftKey && ret && allowShift) {
|
||||
modifiers += 'shift_';
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
ret = modifiers + ret;
|
||||
}
|
||||
|
||||
if (!dontIgnoreMeta && ret) {
|
||||
ret = ret.replace(/ctrl_meta|meta/,'ctrl');
|
||||
}
|
||||
|
||||
return [ret, key];
|
||||
};
|
||||
|
||||
// Note: Most of the following code is taken from SproutCore with a few changes.
|
||||
|
||||
/**
|
||||
* Firefox sends a few key events twice: the first time to the keydown event
|
||||
* and then later again to the keypress event. To handle them correct, they
|
||||
* should be processed only once. Due to this, we will skip these events
|
||||
* in keydown and handle them then in keypress.
|
||||
*/
|
||||
exports.addKeyDownListener = function(element, boundFunction) {
|
||||
|
||||
var handleBoundFunction = function(ev) {
|
||||
var handled = boundFunction(ev);
|
||||
// If the boundFunction returned true, then stop the event.
|
||||
if (handled) {
|
||||
event.stopEvent(ev);
|
||||
}
|
||||
return handled;
|
||||
};
|
||||
|
||||
element.addEventListener('keydown', function(ev) {
|
||||
if (useragent.isGecko) {
|
||||
// Check for function keys (like DELETE, TAB, LEFT, RIGHT...)
|
||||
if (exports.KeyHelper.FUNCTION_KEYS[ev.keyCode]) {
|
||||
return true;
|
||||
// Check for command keys (like ctrl_c, ctrl_z...)
|
||||
} else if ((ev.ctrlKey || ev.metaKey) &&
|
||||
exports.KeyHelper.PRINTABLE_KEYS[ev.keyCode]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isFunctionOrNonPrintableKey(ev)) {
|
||||
return handleBoundFunction(ev);
|
||||
}
|
||||
|
||||
return true;
|
||||
}, false);
|
||||
|
||||
element.addEventListener('keypress', function(ev) {
|
||||
if (useragent.isGecko) {
|
||||
// If this is a function key, we have to use the keyCode.
|
||||
if (exports.KeyHelper.FUNCTION_KEYS[ev.keyCode]) {
|
||||
return handleBoundFunction(ev);
|
||||
} else if ((ev.ctrlKey || ev.metaKey) &&
|
||||
exports.KeyHelper.PRINTABLE_KEYS_CHARCODE[ev.charCode]){
|
||||
// Check for command keys (like ctrl_c, ctrl_z...).
|
||||
// For command keys have to convert the charCode to a keyCode
|
||||
// as it has been sent from the keydown event to be in line
|
||||
// with the other browsers implementations.
|
||||
|
||||
// FF does not allow let you change the keyCode or charCode
|
||||
// property. Store to a custom keyCode/charCode variable.
|
||||
// The getCommandCodes() function takes care of these
|
||||
// special variables.
|
||||
ev._keyCode = exports.KeyHelper.PRINTABLE_KEYS_CHARCODE[ev.charCode];
|
||||
ev._charCode = 0;
|
||||
return handleBoundFunction(ev);
|
||||
}
|
||||
}
|
||||
|
||||
// normal processing: send keyDown for printable keys.
|
||||
if (ev.charCode !== undefined && ev.charCode === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return handleBoundFunction(ev);
|
||||
}, false);
|
||||
};
|
||||
|
||||
});
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
require.def(['require', 'exports', 'module',
|
||||
'keyboard/keyboard',
|
||||
'keyboard/tests/plugindev'
|
||||
], function(require, exports, module,
|
||||
keyboard,
|
||||
t
|
||||
) {
|
||||
|
||||
/* ***** 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 ***** */
|
||||
|
||||
|
||||
|
||||
|
||||
exports.testKeyMatching = function() {
|
||||
var km = keyboard.keyboardManager;
|
||||
var command = {};
|
||||
t.equal(km._commandMatches(command, 'meta_z', {}), false,
|
||||
'no keymapping means false');
|
||||
|
||||
command = {
|
||||
key: 'meta_z'
|
||||
};
|
||||
t.equal(km._commandMatches(command, 'meta_z', {}), true,
|
||||
'matching keys, simple string');
|
||||
t.equal(km._commandMatches(command, 'meta_a', {}), false,
|
||||
'not matching key, simple string');
|
||||
|
||||
command = {
|
||||
key: {key: 'meta_z', predicates: {isGreen: true}}
|
||||
};
|
||||
t.equal(km._commandMatches(command, 'meta_z', {}), false,
|
||||
'object with not matching predicate');
|
||||
t.equal(km._commandMatches(command, 'meta_z', {isGreen: true}), true,
|
||||
'object with matching key and predicate');
|
||||
t.equal(km._commandMatches(command, 'meta_a', {isGreen: true}), false,
|
||||
'object with not matching key');
|
||||
t.equal(km._commandMatches(command, 'meta_a', {isGreen: false}), false,
|
||||
'object with neither matching');
|
||||
t.equal(km._commandMatches(command, 'meta_z', {isGreen: false}), false,
|
||||
'object with matching key and but different predicate');
|
||||
|
||||
command = {
|
||||
key: ['meta_b', {key: 'meta_z', predicates: {isGreen: true}},
|
||||
{key: 'meta_c'}]
|
||||
};
|
||||
t.equal(km._commandMatches(command, 'meta_z', {}), false,
|
||||
'list: object with not matching predicate');
|
||||
t.equal(km._commandMatches(command, 'meta_z', {isGreen: true}), true,
|
||||
'list: object with matching key and predicate');
|
||||
t.equal(km._commandMatches(command, 'meta_a', {isGreen: true}), false,
|
||||
'list: object with not matching key');
|
||||
t.equal(km._commandMatches(command, 'meta_a', {isGreen: false}), false,
|
||||
'list: object with neither matching');
|
||||
t.equal(km._commandMatches(command, 'meta_z', {isGreen: false}), false,
|
||||
'list: object with matching key and but different predicate');
|
||||
t.equal(km._commandMatches(command, 'meta_b'), true,
|
||||
'list: simple key match');
|
||||
t.equal(km._commandMatches(command, 'meta_c'), true,
|
||||
'list: object without predicate match');
|
||||
t.equal(km._commandMatches(command, 'meta_c', {isGreen: false}), true,
|
||||
'list: flags don\'t matter without predicates');
|
||||
};
|
||||
|
||||
});
|
||||
|
|
@ -1,107 +0,0 @@
|
|||
/* ***** 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 Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org Services B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
exports.stringReverse = function(string) {
|
||||
return string.split("").reverse().join("");
|
||||
};
|
||||
|
||||
exports.stringRepeat = function (string, count) {
|
||||
return new Array(count + 1).join(string);
|
||||
};
|
||||
|
||||
exports.copyObject = function(obj) {
|
||||
var copy = {};
|
||||
for (var key in obj) {
|
||||
copy[key] = obj[key];
|
||||
}
|
||||
return copy;
|
||||
};
|
||||
|
||||
exports.arrayToMap = function(arr) {
|
||||
var map = {};
|
||||
for (var i=0; i<arr.length; i++) {
|
||||
map[arr[i]] = 1;
|
||||
}
|
||||
return map;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* splice out of 'array' anything that === 'value'
|
||||
*/
|
||||
exports.arrayRemove = function(array, value) {
|
||||
for (var i = 0; i <= array.length; i++) {
|
||||
if (value === array[i]) {
|
||||
array.splice(i, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.escapeRegExp = function(str) {
|
||||
return str.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1');
|
||||
};
|
||||
|
||||
exports.deferredCall = function(fcn) {
|
||||
|
||||
var timer = null;
|
||||
var callback = function() {
|
||||
timer = null;
|
||||
fcn();
|
||||
};
|
||||
|
||||
return {
|
||||
schedule: function() {
|
||||
if (!timer) {
|
||||
timer = setTimeout(callback, 0);
|
||||
}
|
||||
},
|
||||
|
||||
call: function() {
|
||||
this.cancel();
|
||||
fcn();
|
||||
},
|
||||
|
||||
cancel: function() {
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
});
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
/* ***** 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 Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org Services B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
exports.inherits = function(ctor, superCtor) {
|
||||
var tempCtor = function() {};
|
||||
tempCtor.prototype = superCtor.prototype;
|
||||
ctor.super_ = superCtor.prototype;
|
||||
ctor.prototype = new tempCtor();
|
||||
ctor.prototype.constructor = ctor;
|
||||
};
|
||||
|
||||
exports.mixin = function(obj, mixin) {
|
||||
for (var key in mixin) {
|
||||
obj[key] = mixin[key];
|
||||
}
|
||||
};
|
||||
|
||||
exports.implement = function(proto, mixin) {
|
||||
exports.mixin(proto, mixin);
|
||||
};
|
||||
|
||||
});
|
||||
|
|
@ -1,158 +0,0 @@
|
|||
/* ***** 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):
|
||||
* 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(function(require, exports, module) {
|
||||
|
||||
var Promise = require("pilot/promise").Promise;
|
||||
|
||||
exports.REASONS = {
|
||||
APP_STARTUP: 1,
|
||||
APP_SHUTDOWN: 2,
|
||||
PLUGIN_ENABLE: 3,
|
||||
PLUGIN_DISABLE: 4,
|
||||
PLUGIN_INSTALL: 5,
|
||||
PLUGIN_UNINSTALL: 6,
|
||||
PLUGIN_UPGRADE: 7,
|
||||
PLUGIN_DOWNGRADE: 8
|
||||
};
|
||||
|
||||
exports.Plugin = function(name) {
|
||||
this.name = name;
|
||||
this.status = this.INSTALLED;
|
||||
};
|
||||
|
||||
exports.Plugin.prototype = {
|
||||
/**
|
||||
* constants for the state
|
||||
*/
|
||||
NEW: 0,
|
||||
INSTALLED: 1,
|
||||
REGISTERED: 2,
|
||||
STARTED: 3,
|
||||
UNREGISTERED: 4,
|
||||
SHUTDOWN: 5,
|
||||
|
||||
install: function(data, reason) {
|
||||
var pr = new Promise();
|
||||
if (this.status > this.NEW) {
|
||||
pr.resolve(this);
|
||||
return pr;
|
||||
}
|
||||
require([this.name], function(pluginModule) {
|
||||
if (pluginModule.install) {
|
||||
pluginModule.install(data, reason);
|
||||
}
|
||||
this.status = this.INSTALLED;
|
||||
pr.resolve(this);
|
||||
}.bind(this));
|
||||
return pr;
|
||||
},
|
||||
|
||||
register: function(data, reason) {
|
||||
var pr = new Promise();
|
||||
if (this.status != this.INSTALLED) {
|
||||
pr.resolve(this);
|
||||
return pr;
|
||||
}
|
||||
require([this.name], function(pluginModule) {
|
||||
if (pluginModule.register) {
|
||||
pluginModule.register(data, reason);
|
||||
}
|
||||
this.status = this.REGISTERED;
|
||||
pr.resolve(this);
|
||||
}.bind(this));
|
||||
return pr;
|
||||
},
|
||||
|
||||
startup: function(data, reason) {
|
||||
var pr = new Promise();
|
||||
if (this.status != this.REGISTERED) {
|
||||
pr.resolve(this);
|
||||
return pr;
|
||||
}
|
||||
require([this.name], function(pluginModule) {
|
||||
if (pluginModule.startup) {
|
||||
pluginModule.startup(data, reason);
|
||||
}
|
||||
this.status = this.STARTED;
|
||||
pr.resolve(this);
|
||||
}.bind(this));
|
||||
return pr;
|
||||
},
|
||||
|
||||
shutdown: function(data, reason) {
|
||||
if (this.status != this.STARTED) {
|
||||
return;
|
||||
}
|
||||
pluginModule = require(this.name);
|
||||
if (pluginModule.shutdown) {
|
||||
pluginModule.shutdown(data, reason);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.PluginCatalog = function() {
|
||||
this.plugins = {};
|
||||
};
|
||||
|
||||
exports.PluginCatalog.prototype = {
|
||||
registerPlugins: function(pluginList, data, reason) {
|
||||
var registrationPromises = [];
|
||||
pluginList.forEach(function(pluginName) {
|
||||
var plugin = this.plugins[pluginName];
|
||||
if (plugin === undefined) {
|
||||
plugin = new exports.Plugin(pluginName);
|
||||
this.plugins[pluginName] = plugin;
|
||||
registrationPromises.push(plugin.register(data, reason));
|
||||
}
|
||||
}.bind(this));
|
||||
return Promise.group(registrationPromises);
|
||||
},
|
||||
|
||||
startupPlugins: function(data, reason) {
|
||||
var startupPromises = [];
|
||||
for (var pluginName in this.plugins) {
|
||||
var plugin = this.plugins[pluginName];
|
||||
startupPromises.push(plugin.startup(data, reason));
|
||||
}
|
||||
return Promise.group(startupPromises);
|
||||
}
|
||||
};
|
||||
|
||||
exports.catalog = new exports.PluginCatalog();
|
||||
|
||||
});
|
||||
|
|
@ -1,264 +0,0 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Skywriter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Joe Walker (jwalker@mozilla.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var console = require("pilot/console");
|
||||
var Trace = require('pilot/stacktrace').Trace;
|
||||
|
||||
/**
|
||||
* A promise can be in one of 2 states.
|
||||
* The ERROR and SUCCESS states are terminal, the PENDING state is the only
|
||||
* start state.
|
||||
*/
|
||||
var ERROR = -1;
|
||||
var PENDING = 0;
|
||||
var SUCCESS = 1;
|
||||
|
||||
/**
|
||||
* We give promises and ID so we can track which are outstanding
|
||||
*/
|
||||
var _nextId = 0;
|
||||
|
||||
/**
|
||||
* Debugging help if 2 things try to complete the same promise.
|
||||
* This can be slow (especially on chrome due to the stack trace unwinding) so
|
||||
* we should leave this turned off in normal use.
|
||||
*/
|
||||
var _traceCompletion = false;
|
||||
|
||||
/**
|
||||
* Outstanding promises. Handy list for debugging only.
|
||||
*/
|
||||
var _outstanding = [];
|
||||
|
||||
/**
|
||||
* Recently resolved promises. Also for debugging only.
|
||||
*/
|
||||
var _recent = [];
|
||||
|
||||
/**
|
||||
* Create an unfulfilled promise
|
||||
*/
|
||||
Promise = function () {
|
||||
this._status = PENDING;
|
||||
this._value = undefined;
|
||||
this._onSuccessHandlers = [];
|
||||
this._onErrorHandlers = [];
|
||||
|
||||
// Debugging help
|
||||
this._id = _nextId++;
|
||||
//this._createTrace = new Trace(new Error());
|
||||
_outstanding[this._id] = this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Yeay for RTTI.
|
||||
*/
|
||||
Promise.prototype.isPromise = true;
|
||||
|
||||
/**
|
||||
* Have we either been resolve()ed or reject()ed?
|
||||
*/
|
||||
Promise.prototype.isComplete = function() {
|
||||
return this._status != PENDING;
|
||||
};
|
||||
|
||||
/**
|
||||
* Have we resolve()ed?
|
||||
*/
|
||||
Promise.prototype.isResolved = function() {
|
||||
return this._status == SUCCESS;
|
||||
};
|
||||
|
||||
/**
|
||||
* Have we reject()ed?
|
||||
*/
|
||||
Promise.prototype.isRejected = function() {
|
||||
return this._status == ERROR;
|
||||
};
|
||||
|
||||
/**
|
||||
* Take the specified action of fulfillment of a promise, and (optionally)
|
||||
* a different action on promise rejection.
|
||||
*/
|
||||
Promise.prototype.then = function(onSuccess, onError) {
|
||||
if (typeof onSuccess === 'function') {
|
||||
if (this._status === SUCCESS) {
|
||||
onSuccess.call(null, this._value);
|
||||
} else if (this._status === PENDING) {
|
||||
this._onSuccessHandlers.push(onSuccess);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof onError === 'function') {
|
||||
if (this._status === ERROR) {
|
||||
onError.call(null, this._value);
|
||||
} else if (this._status === PENDING) {
|
||||
this._onErrorHandlers.push(onError);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Like then() except that rather than returning <tt>this</tt> we return
|
||||
* a promise which
|
||||
*/
|
||||
Promise.prototype.chainPromise = function(onSuccess) {
|
||||
var chain = new Promise();
|
||||
chain._chainedFrom = this;
|
||||
this.then(function(data) {
|
||||
try {
|
||||
chain.resolve(onSuccess(data));
|
||||
} catch (ex) {
|
||||
chain.reject(ex);
|
||||
}
|
||||
}, function(ex) {
|
||||
chain.reject(ex);
|
||||
});
|
||||
return chain;
|
||||
};
|
||||
|
||||
/**
|
||||
* Supply the fulfillment of a promise
|
||||
*/
|
||||
Promise.prototype.resolve = function(data) {
|
||||
return this._complete(this._onSuccessHandlers, SUCCESS, data, 'resolve');
|
||||
};
|
||||
|
||||
/**
|
||||
* Renege on a promise
|
||||
*/
|
||||
Promise.prototype.reject = function(data) {
|
||||
return this._complete(this._onErrorHandlers, ERROR, data, 'reject');
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal method to be called on resolve() or reject().
|
||||
* @private
|
||||
*/
|
||||
Promise.prototype._complete = function(list, status, data, name) {
|
||||
// Complain if we've already been completed
|
||||
if (this._status != PENDING) {
|
||||
console.group('Promise already closed');
|
||||
console.error('Attempted ' + name + '() with ', data);
|
||||
console.error('Previous status = ', this._status,
|
||||
', previous value = ', this._value);
|
||||
console.trace();
|
||||
|
||||
if (this._completeTrace) {
|
||||
console.error('Trace of previous completion:');
|
||||
this._completeTrace.log(5);
|
||||
}
|
||||
console.groupEnd();
|
||||
return this;
|
||||
}
|
||||
|
||||
if (_traceCompletion) {
|
||||
this._completeTrace = new Trace(new Error());
|
||||
}
|
||||
|
||||
this._status = status;
|
||||
this._value = data;
|
||||
|
||||
// Call all the handlers, and then delete them
|
||||
list.forEach(function(handler) {
|
||||
handler.call(null, this._value);
|
||||
}, this);
|
||||
this._onSuccessHandlers.length = 0;
|
||||
this._onErrorHandlers.length = 0;
|
||||
|
||||
// Remove the given {promise} from the _outstanding list, and add it to the
|
||||
// _recent list, pruning more than 20 recent promises from that list.
|
||||
delete _outstanding[this._id];
|
||||
_recent.push(this);
|
||||
while (_recent.length > 20) {
|
||||
_recent.shift();
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Takes an array of promises and returns a promise that that is fulfilled once
|
||||
* all the promises in the array are fulfilled
|
||||
* @param group The array of promises
|
||||
* @return the promise that is fulfilled when all the array is fulfilled
|
||||
*/
|
||||
Promise.group = function(promiseList) {
|
||||
if (!(promiseList instanceof Array)) {
|
||||
promiseList = Array.prototype.slice.call(arguments);
|
||||
}
|
||||
|
||||
// If the original array has nothing in it, return now to avoid waiting
|
||||
if (promiseList.length === 0) {
|
||||
return new Promise().resolve([]);
|
||||
}
|
||||
|
||||
var groupPromise = new Promise();
|
||||
var results = [];
|
||||
var fulfilled = 0;
|
||||
|
||||
var onSuccessFactory = function(index) {
|
||||
return function(data) {
|
||||
results[index] = data;
|
||||
fulfilled++;
|
||||
// If the group has already failed, silently drop extra results
|
||||
if (groupPromise._status !== ERROR) {
|
||||
if (fulfilled === promiseList.length) {
|
||||
groupPromise.resolve(results);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
promiseList.forEach(function(promise, index) {
|
||||
var onSuccess = onSuccessFactory(index);
|
||||
var onError = groupPromise.reject.bind(groupPromise);
|
||||
promise.then(onSuccess, onError);
|
||||
});
|
||||
|
||||
return groupPromise;
|
||||
};
|
||||
|
||||
exports.Promise = Promise;
|
||||
exports._outstanding = _outstanding;
|
||||
exports._recent = _recent;
|
||||
|
||||
});
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
/* ***** 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):
|
||||
* 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(function(require, exports, module) {
|
||||
|
||||
var Promise = require('pilot/promise').Promise;
|
||||
|
||||
exports.xhr = function(method, url, async, beforeSendCallback) {
|
||||
var pr = new Promise();
|
||||
|
||||
if (!skywriter.proxy || !skywriter.proxy.xhr) {
|
||||
var req = new XMLHttpRequest();
|
||||
req.onreadystatechange = function() {
|
||||
if (req.readyState !== 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
var status = req.status;
|
||||
if (status !== 0 && status !== 200) {
|
||||
var error = new Error(req.responseText + ' (Status ' + req.status + ")");
|
||||
error.xhr = req;
|
||||
pr.reject(error);
|
||||
return;
|
||||
}
|
||||
|
||||
pr.resolve(req.responseText);
|
||||
}.bind(this);
|
||||
|
||||
req.open("GET", url, async);
|
||||
if (beforeSendCallback) {
|
||||
beforeSendCallback(req);
|
||||
}
|
||||
req.send();
|
||||
} else {
|
||||
skywriter.proxy.xhr.call(this, method, url, async, beforeSendCallback, pr);
|
||||
}
|
||||
|
||||
return pr;
|
||||
};
|
||||
|
||||
exports.Worker = function(url) {
|
||||
if (!skywriter.proxy || !skywriter.proxy.worker) {
|
||||
return new Worker(url);
|
||||
} else {
|
||||
return new skywriter.proxy.worker(url);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
|
@ -1,185 +0,0 @@
|
|||
/* ***** 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):
|
||||
* Patrick Walton (pwalton@mozilla.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var util = require("util/util");
|
||||
|
||||
/**
|
||||
* Returns the result of adding the two positions.
|
||||
*/
|
||||
exports.addPositions = function(a, b) {
|
||||
return { row: a.row + b.row, col: a.col + b.col };
|
||||
};
|
||||
|
||||
/** Returns a copy of the given range. */
|
||||
exports.cloneRange = function(range) {
|
||||
var oldStart = range.start, oldEnd = range.end;
|
||||
var newStart = { row: oldStart.row, col: oldStart.col };
|
||||
var newEnd = { row: oldEnd.row, col: oldEnd.col };
|
||||
return { start: newStart, end: newEnd };
|
||||
};
|
||||
|
||||
/**
|
||||
* Given two positions a and b, returns a negative number if a < b, 0 if a = b,
|
||||
* or a positive number if a > b.
|
||||
*/
|
||||
exports.comparePositions = function(positionA, positionB) {
|
||||
var rowDiff = positionA.row - positionB.row;
|
||||
return rowDiff === 0 ? positionA.col - positionB.col : rowDiff;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the two ranges are equal and false otherwise.
|
||||
*/
|
||||
exports.equal = function(rangeA, rangeB) {
|
||||
return (exports.comparePositions(rangeA.start, rangeB.start) === 0 &&
|
||||
exports.comparePositions(rangeA.end, rangeB.end) === 0);
|
||||
};
|
||||
|
||||
exports.extendRange = function(range, delta) {
|
||||
var end = range.end;
|
||||
return {
|
||||
start: range.start,
|
||||
end: {
|
||||
row: end.row + delta.row,
|
||||
col: end.col + delta.col
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Given two sets of ranges, returns the ranges of characters that exist in one
|
||||
* of the sets but not both.
|
||||
*/
|
||||
exports.intersectRangeSets = function(setA, setB) {
|
||||
var stackA = util.clone(setA), stackB = util.clone(setB);
|
||||
var result = [];
|
||||
while (stackA.length > 0 && stackB.length > 0) {
|
||||
var rangeA = stackA.shift(), rangeB = stackB.shift();
|
||||
var startDiff = exports.comparePositions(rangeA.start, rangeB.start);
|
||||
var endDiff = exports.comparePositions(rangeA.end, rangeB.end);
|
||||
|
||||
if (exports.comparePositions(rangeA.end, rangeB.start) < 0) {
|
||||
// A is completely before B
|
||||
result.push(rangeA);
|
||||
stackB.unshift(rangeB);
|
||||
} else if (exports.comparePositions(rangeB.end, rangeA.start) < 0) {
|
||||
// B is completely before A
|
||||
result.push(rangeB);
|
||||
stackA.unshift(rangeA);
|
||||
} else if (startDiff < 0) { // A starts before B
|
||||
result.push({ start: rangeA.start, end: rangeB.start });
|
||||
stackA.unshift({ start: rangeB.start, end: rangeA.end });
|
||||
stackB.unshift(rangeB);
|
||||
} else if (startDiff === 0) { // A and B start at the same place
|
||||
if (endDiff < 0) { // A ends before B
|
||||
stackB.unshift({ start: rangeA.end, end: rangeB.end });
|
||||
} else if (endDiff > 0) { // A ends after B
|
||||
stackA.unshift({ start: rangeB.end, end: rangeA.end });
|
||||
}
|
||||
} else if (startDiff > 0) { // A starts after B
|
||||
result.push({ start: rangeB.start, end: rangeA.start });
|
||||
stackA.unshift(rangeA);
|
||||
stackB.unshift({ start: rangeA.start, end: rangeB.end });
|
||||
}
|
||||
}
|
||||
return result.concat(stackA, stackB);
|
||||
};
|
||||
|
||||
exports.isZeroLength = function(range) {
|
||||
return range.start.row === range.end.row &&
|
||||
range.start.col === range.end.col;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the greater of the two positions.
|
||||
*/
|
||||
exports.maxPosition = function(a, b) {
|
||||
return exports.comparePositions(a, b) > 0 ? a : b;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a range with swapped 'end' and 'start' values into one with the
|
||||
* values in the correct order.
|
||||
*
|
||||
* TODO: Unit test.
|
||||
*/
|
||||
exports.normalizeRange = function(range) {
|
||||
return this.comparePositions(range.start, range.end) < 0 ? range :
|
||||
{ start: range.end, end: range.start };
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a single range that spans the entire given set of ranges.
|
||||
*/
|
||||
exports.rangeSetBoundaries = function(rangeSet) {
|
||||
return {
|
||||
start: rangeSet[0].start,
|
||||
end: rangeSet[rangeSet.length - 1].end
|
||||
};
|
||||
};
|
||||
|
||||
exports.toString = function(range) {
|
||||
var start = range.start, end = range.end;
|
||||
return '[ ' + start.row + ', ' + start.col + ' ' + end.row + ',' + + end.col +' ]';
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the union of the two ranges.
|
||||
*/
|
||||
exports.unionRanges = function(a, b) {
|
||||
return {
|
||||
start: a.start.row < b.start.row ||
|
||||
(a.start.row === b.start.row && a.start.col < b.start.col) ?
|
||||
a.start : b.start,
|
||||
end: a.end.row > b.end.row ||
|
||||
(a.end.row === b.end.row && a.end.col > b.end.col) ?
|
||||
a.end : b.end
|
||||
};
|
||||
};
|
||||
|
||||
exports.isPosition = function(pos) {
|
||||
return !util.none(pos) && !util.none(pos.row) && !util.none(pos.col);
|
||||
};
|
||||
|
||||
exports.isRange = function(range) {
|
||||
return (!util.none(range) && exports.isPosition(range.start) &&
|
||||
exports.isPosition(range.end));
|
||||
};
|
||||
|
||||
});
|
||||
|
|
@ -1,303 +0,0 @@
|
|||
/* ***** 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)
|
||||
* Julian Viereck (jviereck@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(function(require, exports, module) {
|
||||
|
||||
/**
|
||||
* This plug-in manages settings.
|
||||
*/
|
||||
|
||||
var console = require('pilot/console');
|
||||
var oop = require('pilot/oop');
|
||||
var types = require('pilot/types');
|
||||
var EventEmitter = require('pilot/event_emitter').EventEmitter;
|
||||
var catalog = require('pilot/catalog');
|
||||
|
||||
var settingExtensionSpec = {
|
||||
name: 'setting',
|
||||
description: 'A setting is something that the application offers as a ' +
|
||||
'way to customize how it works',
|
||||
register: 'env.settings.addSetting',
|
||||
indexOn: 'name'
|
||||
};
|
||||
|
||||
exports.startup = function(data, reason) {
|
||||
catalog.addExtensionSpec(settingExtensionSpec);
|
||||
};
|
||||
|
||||
exports.shutdown = function(data, reason) {
|
||||
catalog.removeExtensionSpec(settingExtensionSpec);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a new setting.
|
||||
* @param settingSpec An object literal that looks like this:
|
||||
* {
|
||||
* name: 'thing',
|
||||
* description: 'Thing is an example setting',
|
||||
* type: 'string',
|
||||
* defaultValue: 'something'
|
||||
* }
|
||||
*/
|
||||
function Setting(settingSpec, settings) {
|
||||
this._settings = settings;
|
||||
|
||||
Object.keys(settingSpec).forEach(function(key) {
|
||||
this[key] = settingSpec[key];
|
||||
}, this);
|
||||
|
||||
this.type = types.getType(this.type);
|
||||
if (this.type == null) {
|
||||
throw new Error('In ' + this.name +
|
||||
': can\'t find type for: ' + JSON.stringify(settingSpec.type));
|
||||
}
|
||||
|
||||
if (!this.name) {
|
||||
throw new Error('Setting.name == undefined. Ignoring.', this);
|
||||
}
|
||||
|
||||
if (!this.defaultValue === undefined) {
|
||||
throw new Error('Setting.defaultValue == undefined', this);
|
||||
}
|
||||
|
||||
this.value = this.defaultValue;
|
||||
}
|
||||
Setting.prototype = {
|
||||
get: function() {
|
||||
return this.value;
|
||||
},
|
||||
|
||||
set: function(value) {
|
||||
if (this.value === value) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.value = value;
|
||||
if (this._settings.persister) {
|
||||
this._settings.persister.persistValue(this._settings, this.name, value);
|
||||
}
|
||||
|
||||
this._dispatchEvent('change', { setting: this, value: value });
|
||||
},
|
||||
|
||||
/**
|
||||
* Reset the value of the <code>key</code> setting to it's default
|
||||
*/
|
||||
resetValue: function() {
|
||||
this.set(this.defaultValue);
|
||||
}
|
||||
};
|
||||
oop.implement(Setting.prototype, EventEmitter);
|
||||
|
||||
|
||||
/**
|
||||
* A base class for all the various methods of storing settings.
|
||||
* <p>Usage:
|
||||
* <pre>
|
||||
* // 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');
|
||||
* </pre>
|
||||
* @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.
|
||||
* <p>Example usage:
|
||||
* <pre>
|
||||
* 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
|
||||
* });
|
||||
* </pre>
|
||||
* @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();
|
||||
},
|
||||
|
||||
removeSetting: function(setting) {
|
||||
var name = (typeof setting === 'string' ? setting : setting.name);
|
||||
delete this._settings[name];
|
||||
util.arrayRemove(this._settingNames, name);
|
||||
},
|
||||
|
||||
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;
|
||||
|
||||
});
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Skywriter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Joe Walker (jwalker@mozilla.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
|
||||
var historyLengthSetting = {
|
||||
name: "historyLength",
|
||||
description: "How many typed commands do we recall for reference?",
|
||||
type: "number",
|
||||
defaultValue: 50
|
||||
};
|
||||
|
||||
exports.startup = function(data, reason) {
|
||||
data.env.settings.addSetting(historyLengthSetting);
|
||||
};
|
||||
|
||||
exports.shutdown = function(data, reason) {
|
||||
data.env.settings.removeSetting(historyLengthSetting);
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -1,332 +0,0 @@
|
|||
define(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 <loic@dachary.org> (2008)
|
||||
// Johan Euphrosine <proppy@aminche.com> (2008)
|
||||
// Øyvind Sean Kinsey http://kinsey.no/blog
|
||||
//
|
||||
// Information and discussions
|
||||
// http://jspoker.pokersource.info/skin/test-printstacktrace.html
|
||||
// http://eriwen.com/javascript/js-stack-trace/
|
||||
// http://eriwen.com/javascript/stacktrace-update/
|
||||
// http://pastie.org/253058
|
||||
// http://browsershots.org/http://jspoker.pokersource.info/skin/test-printstacktrace.html
|
||||
//
|
||||
|
||||
//
|
||||
// guessFunctionNameFromLines comes from firebug
|
||||
//
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2007, Parakey Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above
|
||||
// copyright notice, this list of conditions and the
|
||||
// following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the
|
||||
// following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// * Neither the name of Parakey Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior
|
||||
// written permission of Parakey Inc.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Different browsers create stack traces in different ways.
|
||||
* <strike>Feature</strike> Browser detection baby ;).
|
||||
*/
|
||||
var mode = (function() {
|
||||
|
||||
// We use SC's browser detection here to avoid the "break on error"
|
||||
// functionality provided by Firebug. Firebug tries to do the right
|
||||
// thing here and break, but it happens every time you load the page.
|
||||
// bug 554105
|
||||
if (ua.isGecko) {
|
||||
return 'firefox';
|
||||
} else if (ua.isOpera) {
|
||||
return 'opera';
|
||||
} else {
|
||||
return 'other';
|
||||
}
|
||||
|
||||
// SC doesn't do any detection of Chrome at this time.
|
||||
|
||||
// this is the original feature detection code that is used as a
|
||||
// fallback.
|
||||
try {
|
||||
(0)();
|
||||
} catch (e) {
|
||||
if (e.arguments) {
|
||||
return 'chrome';
|
||||
}
|
||||
if (e.stack) {
|
||||
return 'firefox';
|
||||
}
|
||||
if (window.opera && !('stacktrace' in e)) { //Opera 9-
|
||||
return 'opera';
|
||||
}
|
||||
}
|
||||
return 'other';
|
||||
})();
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function stringifyArguments(args) {
|
||||
for (var i = 0; i < args.length; ++i) {
|
||||
var argument = args[i];
|
||||
if (typeof argument == 'object') {
|
||||
args[i] = '#object';
|
||||
} else if (typeof argument == 'function') {
|
||||
args[i] = '#function';
|
||||
} else if (typeof argument == 'string') {
|
||||
args[i] = '"' + argument + '"';
|
||||
}
|
||||
}
|
||||
return args.join(',');
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a stack trace from the format emitted by each browser.
|
||||
*/
|
||||
var decoders = {
|
||||
chrome: function(e) {
|
||||
var stack = e.stack;
|
||||
if (!stack) {
|
||||
console.log(e);
|
||||
return [];
|
||||
}
|
||||
return stack.replace(/^.*?\n/, '').
|
||||
replace(/^.*?\n/, '').
|
||||
replace(/^.*?\n/, '').
|
||||
replace(/^[^\(]+?[\n$]/gm, '').
|
||||
replace(/^\s+at\s+/gm, '').
|
||||
replace(/^Object.<anonymous>\s*\(/gm, '{anonymous}()@').
|
||||
split('\n');
|
||||
},
|
||||
|
||||
firefox: function(e) {
|
||||
var stack = e.stack;
|
||||
if (!stack) {
|
||||
console.log(e);
|
||||
return [];
|
||||
}
|
||||
// stack = stack.replace(/^.*?\n/, '');
|
||||
stack = stack.replace(/(?:\n@:0)?\s+$/m, '');
|
||||
stack = stack.replace(/^\(/gm, '{anonymous}(');
|
||||
return stack.split('\n');
|
||||
},
|
||||
|
||||
// Opera 7.x and 8.x only!
|
||||
opera: function(e) {
|
||||
var lines = e.message.split('\n'), ANON = '{anonymous}',
|
||||
lineRE = /Line\s+(\d+).*?script\s+(http\S+)(?:.*?in\s+function\s+(\S+))?/i, i, j, len;
|
||||
|
||||
for (i = 4, j = 0, len = lines.length; i < len; i += 2) {
|
||||
if (lineRE.test(lines[i])) {
|
||||
lines[j++] = (RegExp.$3 ? RegExp.$3 + '()@' + RegExp.$2 + RegExp.$1 : ANON + '()@' + RegExp.$2 + ':' + RegExp.$1) +
|
||||
' -- ' +
|
||||
lines[i + 1].replace(/^\s+/, '');
|
||||
}
|
||||
}
|
||||
|
||||
lines.splice(j, lines.length - j);
|
||||
return lines;
|
||||
},
|
||||
|
||||
// Safari, Opera 9+, IE, and others
|
||||
other: function(curr) {
|
||||
var ANON = '{anonymous}', fnRE = /function\s*([\w\-$]+)?\s*\(/i, stack = [], j = 0, fn, args;
|
||||
|
||||
var maxStackSize = 10;
|
||||
while (curr && stack.length < maxStackSize) {
|
||||
fn = fnRE.test(curr.toString()) ? RegExp.$1 || ANON : ANON;
|
||||
args = Array.prototype.slice.call(curr['arguments']);
|
||||
stack[j++] = fn + '(' + stringifyArguments(args) + ')';
|
||||
|
||||
//Opera bug: if curr.caller does not exist, Opera returns curr (WTF)
|
||||
if (curr === curr.caller && window.opera) {
|
||||
//TODO: check for same arguments if possible
|
||||
break;
|
||||
}
|
||||
curr = curr.caller;
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function NameGuesser() {
|
||||
}
|
||||
|
||||
NameGuesser.prototype = {
|
||||
|
||||
sourceCache: {},
|
||||
|
||||
ajax: function(url) {
|
||||
var req = this.createXMLHTTPObject();
|
||||
if (!req) {
|
||||
return;
|
||||
}
|
||||
req.open('GET', url, false);
|
||||
req.setRequestHeader('User-Agent', 'XMLHTTP/1.0');
|
||||
req.send('');
|
||||
return req.responseText;
|
||||
},
|
||||
|
||||
createXMLHTTPObject: function() {
|
||||
// Try XHR methods in order and store XHR factory
|
||||
var xmlhttp, XMLHttpFactories = [
|
||||
function() {
|
||||
return new XMLHttpRequest();
|
||||
}, function() {
|
||||
return new ActiveXObject('Msxml2.XMLHTTP');
|
||||
}, function() {
|
||||
return new ActiveXObject('Msxml3.XMLHTTP');
|
||||
}, function() {
|
||||
return new ActiveXObject('Microsoft.XMLHTTP');
|
||||
}
|
||||
];
|
||||
for (var i = 0; i < XMLHttpFactories.length; i++) {
|
||||
try {
|
||||
xmlhttp = XMLHttpFactories[i]();
|
||||
// Use memoization to cache the factory
|
||||
this.createXMLHTTPObject = XMLHttpFactories[i];
|
||||
return xmlhttp;
|
||||
} catch (e) {}
|
||||
}
|
||||
},
|
||||
|
||||
getSource: function(url) {
|
||||
if (!(url in this.sourceCache)) {
|
||||
this.sourceCache[url] = this.ajax(url).split('\n');
|
||||
}
|
||||
return this.sourceCache[url];
|
||||
},
|
||||
|
||||
guessFunctions: function(stack) {
|
||||
for (var i = 0; i < stack.length; ++i) {
|
||||
var reStack = /{anonymous}\(.*\)@(\w+:\/\/([-\w\.]+)+(:\d+)?[^:]+):(\d+):?(\d+)?/;
|
||||
var frame = stack[i], m = reStack.exec(frame);
|
||||
if (m) {
|
||||
var file = m[1], lineno = m[4]; //m[7] is character position in Chrome
|
||||
if (file && lineno) {
|
||||
var functionName = this.guessFunctionName(file, lineno);
|
||||
stack[i] = frame.replace('{anonymous}', functionName);
|
||||
}
|
||||
}
|
||||
}
|
||||
return stack;
|
||||
},
|
||||
|
||||
guessFunctionName: function(url, lineNo) {
|
||||
try {
|
||||
return this.guessFunctionNameFromLines(lineNo, this.getSource(url));
|
||||
} catch (e) {
|
||||
return 'getSource failed with url: ' + url + ', exception: ' + e.toString();
|
||||
}
|
||||
},
|
||||
|
||||
guessFunctionNameFromLines: function(lineNo, source) {
|
||||
var reFunctionArgNames = /function ([^(]*)\(([^)]*)\)/;
|
||||
var reGuessFunction = /['"]?([0-9A-Za-z_]+)['"]?\s*[:=]\s*(function|eval|new Function)/;
|
||||
// Walk backwards from the first line in the function until we find the line which
|
||||
// matches the pattern above, which is the function definition
|
||||
var line = '', maxLines = 10;
|
||||
for (var i = 0; i < maxLines; ++i) {
|
||||
line = source[lineNo - i] + line;
|
||||
if (line !== undefined) {
|
||||
var m = reGuessFunction.exec(line);
|
||||
if (m) {
|
||||
return m[1];
|
||||
}
|
||||
else {
|
||||
m = reFunctionArgNames.exec(line);
|
||||
}
|
||||
if (m && m[1]) {
|
||||
return m[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
return '(?)';
|
||||
}
|
||||
};
|
||||
|
||||
var guesser = new NameGuesser();
|
||||
|
||||
var frameIgnorePatterns = [
|
||||
/http:\/\/localhost:4020\/sproutcore.js:/
|
||||
];
|
||||
|
||||
exports.ignoreFramesMatching = function(regex) {
|
||||
frameIgnorePatterns.push(regex);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a stack trace from an exception
|
||||
* @param ex {Error} The error to create a stacktrace from (optional)
|
||||
* @param guess {Boolean} If we should try to resolve the names of anonymous functions
|
||||
*/
|
||||
exports.Trace = function Trace(ex, guess) {
|
||||
this._ex = ex;
|
||||
this._stack = decoders[mode](ex);
|
||||
|
||||
if (guess) {
|
||||
this._stack = guesser.guessFunctions(this._stack);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Log to the console a number of lines (default all of them)
|
||||
* @param lines {number} Maximum number of lines to wrote to console
|
||||
*/
|
||||
exports.Trace.prototype.log = function(lines) {
|
||||
if (lines <= 0) {
|
||||
// You aren't going to have more lines in your stack trace than this
|
||||
// and it still fits in a 32bit integer
|
||||
lines = 999999999;
|
||||
}
|
||||
|
||||
var printed = 0;
|
||||
for (var i = 0; i < this._stack.length && printed < lines; i++) {
|
||||
var frame = this._stack[i];
|
||||
var display = true;
|
||||
frameIgnorePatterns.forEach(function(regex) {
|
||||
if (regex.test(frame)) {
|
||||
display = false;
|
||||
}
|
||||
});
|
||||
if (display) {
|
||||
console.debug(frame);
|
||||
printed++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
|
@ -1,163 +0,0 @@
|
|||
require.def(['require', 'exports', 'module',
|
||||
'rangeutils/tests/plugindev',
|
||||
'rangeutils/tests/utils/range'
|
||||
], function(require, exports, module,
|
||||
t,
|
||||
Range
|
||||
) {
|
||||
|
||||
/* ***** 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 ***** */
|
||||
|
||||
|
||||
|
||||
|
||||
exports.testAddPositions = function() {
|
||||
t.deepEqual(Range.addPositions({ row: 0, col: 0 },
|
||||
{ row: 0, col: 0 }), { row: 0, col: 0 }, '0,0 + 0,0 and 0,0');
|
||||
t.deepEqual(Range.addPositions({ row: 1, col: 0 },
|
||||
{ row: 2, col: 0 }), { row: 3, col: 0 }, '1,0 + 2,0 and 3,0');
|
||||
t.deepEqual(Range.addPositions({ row: 0, col: 1 },
|
||||
{ row: 0, col: 1 }), { row: 0, col: 2 }, '0,1 + 0,1 and 0,2');
|
||||
t.deepEqual(Range.addPositions({ row: 1, col: 2 },
|
||||
{ row: -1, col: -2 }), { row: 0, col: 0 }, '1,2 + -1,-2 and 0,0');
|
||||
};
|
||||
|
||||
exports.testCloneRange = function() {
|
||||
var oldRange = { start: { row: 1, col: 2 }, end: { row: 3, col: 4 } };
|
||||
var newRange = Range.cloneRange(oldRange);
|
||||
t.deepEqual(oldRange, newRange, "the old range and the new range");
|
||||
t.ok(oldRange.start !== newRange.start, "the old range's start position " +
|
||||
"is distinct from the new range's start position");
|
||||
t.ok(oldRange.end !== newRange.end, "the old range's end position is " +
|
||||
"distinct from the new range's end position");
|
||||
t.ok(oldRange !== newRange, "the old range is distinct from the new " +
|
||||
"range");
|
||||
};
|
||||
|
||||
exports.testComparePositions = function() {
|
||||
t.equal(Range.comparePositions({ row: 0, col: 0 },
|
||||
{ row: 0, col: 0 }), 0, '0,0 = 0,0');
|
||||
t.ok(Range.comparePositions({ row: 0, col: 0 },
|
||||
{ row: 1, col: 0 }) < 0, '0,0 < 1,0');
|
||||
t.ok(Range.comparePositions({ row: 0, col: 0 },
|
||||
{ row: 0, col: 1 }) < 0, '0,0 < 0,1');
|
||||
t.ok(Range.comparePositions({ row: 1, col: 0 },
|
||||
{ row: 0, col: 0 }) > 0, '1,0 > 0,0');
|
||||
t.ok(Range.comparePositions({ row: 0, col: 1 },
|
||||
{ row: 0, col: 0 }) > 0, '0,1 > 0,0');
|
||||
};
|
||||
|
||||
exports.testExtendRange = function() {
|
||||
t.deepEqual(Range.extendRange({
|
||||
start: { row: 1, col: 2 },
|
||||
end: { row: 3, col: 4 }
|
||||
}, { row: 5, col: 6 }), {
|
||||
start: { row: 1, col: 2 },
|
||||
end: { row: 8, col: 10 }
|
||||
}, '[ 1,2 3,4 ] extended by 5,6 = [ 1,2 8,10 ]');
|
||||
t.deepEqual(Range.extendRange({
|
||||
start: { row: 7, col: 8 },
|
||||
end: { row: 9, col: 10 }
|
||||
}, { row: 0, col: 0 }), {
|
||||
start: { row: 7, col: 8 },
|
||||
end: { row: 9, col: 10 }
|
||||
}, '[ 7,8 9,10 ] extended by 0,0 remains the same');
|
||||
};
|
||||
|
||||
exports.testMaxPosition = function() {
|
||||
t.deepEqual(Range.maxPosition({ row: 0, col: 0 },
|
||||
{ row: 0, col: 0 }), { row: 0, col: 0 }, 'max(0,0 0,0) = 0,0');
|
||||
t.deepEqual(Range.maxPosition({ row: 0, col: 0 },
|
||||
{ row: 1, col: 0 }), { row: 1, col: 0 }, 'max(0,0 1,0) = 1,0');
|
||||
t.deepEqual(Range.maxPosition({ row: 0, col: 0 },
|
||||
{ row: 0, col: 1 }), { row: 0, col: 1 }, 'max(0,0 0,1) = 0,1');
|
||||
t.deepEqual(Range.maxPosition({ row: 1, col: 0 },
|
||||
{ row: 0, col: 0 }), { row: 1, col: 0 }, 'max(1,0 0,0) = 1,0');
|
||||
t.deepEqual(Range.maxPosition({ row: 0, col: 1 },
|
||||
{ row: 0, col: 0 }), { row: 0, col: 1 }, 'max(0,1 0,0) = 0,1');
|
||||
};
|
||||
|
||||
exports.testNormalizeRange = function() {
|
||||
t.deepEqual(Range.normalizeRange({
|
||||
start: { row: 0, col: 0 },
|
||||
end: { row: 0, col: 0 }
|
||||
}), {
|
||||
start: { row: 0, col: 0 },
|
||||
end: { row: 0, col: 0 }
|
||||
}, 'normalize(0,0 0,0) and (0,0 0,0)');
|
||||
t.deepEqual(Range.normalizeRange({
|
||||
start: { row: 1, col: 2 },
|
||||
end: { row: 3, col: 4 }
|
||||
}), {
|
||||
start: { row: 1, col: 2 },
|
||||
end: { row: 3, col: 4 }
|
||||
}, 'normalize(1,2 3,4) and (1,2 3,4)');
|
||||
t.deepEqual(Range.normalizeRange({
|
||||
start: { row: 4, col: 3 },
|
||||
end: { row: 2, col: 1 }
|
||||
}), {
|
||||
start: { row: 2, col: 1 },
|
||||
end: { row: 4, col: 3 }
|
||||
}, 'normalize(4,3 2,1) and (2,1 4,3)');
|
||||
};
|
||||
|
||||
exports.testUnionRanges = function() {
|
||||
t.deepEqual(Range.unionRanges({
|
||||
start: { row: 1, col: 2 },
|
||||
end: { row: 3, col: 4 }
|
||||
}, {
|
||||
start: { row: 5, col: 6 },
|
||||
end: { row: 7, col: 8 }
|
||||
}), {
|
||||
start: { row: 1, col: 2 },
|
||||
end: { row: 7, col: 8 }
|
||||
}, '[ 1,2 3,4 ] union [ 5,6 7,8 ] = [ 1,2 7,8 ]');
|
||||
t.deepEqual(Range.unionRanges({
|
||||
start: { row: 4, col: 4 },
|
||||
end: { row: 5, col: 5 }
|
||||
}, {
|
||||
start: { row: 3, col: 3 },
|
||||
end: { row: 4, col: 5 }
|
||||
}), {
|
||||
start: { row: 3, col: 3 },
|
||||
end: { row: 5, col: 5 }
|
||||
}, '[ 4,4 5,5 ] union [ 3,3 4,5 ] = [ 3,3 5,5 ]');
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Skywriter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Joe Walker (jwalker@mozilla.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var objectToString = Object.prototype.toString;
|
||||
|
||||
/**
|
||||
* Return true if it is a String
|
||||
*/
|
||||
exports.isString = function(it) {
|
||||
return it && objectToString.call(it) === "[object String]";
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if it is a Boolean.
|
||||
*/
|
||||
exports.isBoolean = function(it) {
|
||||
return it && objectToString.call(it) === "[object Boolean]";
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if it is a Number.
|
||||
*/
|
||||
exports.isNumber = function(it) {
|
||||
return it && objectToString.call(it) === "[object Number]" && isFinite(it);
|
||||
};
|
||||
|
||||
/**
|
||||
* Hack copied from dojo.
|
||||
*/
|
||||
exports.isObject = function(it) {
|
||||
return it !== undefined &&
|
||||
(it === null || typeof it == "object" ||
|
||||
Array.isArray(it) || exports.isFunction(it));
|
||||
};
|
||||
|
||||
/**
|
||||
* Is the passed object a function?
|
||||
* From dojo.isFunction()
|
||||
*/
|
||||
exports.isFunction = function(it) {
|
||||
return it && objectToString.call(it) === "[object Function]";
|
||||
};
|
||||
|
||||
});
|
||||
|
|
@ -1,262 +0,0 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Skywriter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Joe Walker (jwalker@mozilla.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
/**
|
||||
* 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 < arguments; i++) {
|
||||
if (arguments[i] > combined) {
|
||||
combined = arguments[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 <tt>value</tt> 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 <tt>str</tt> 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.
|
||||
* <p>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;
|
||||
}
|
||||
};
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
var type = types[name];
|
||||
if (typeof type === 'function') {
|
||||
// TODO: should we complain if typeSpec is a string?
|
||||
type = new type(typeSpec);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a type, previously registered using #registerType()
|
||||
*/
|
||||
exports.getType = function(typeSpec) {
|
||||
if (typeof typeSpec === 'string') {
|
||||
return reconstituteType(typeSpec, 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);
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -1,291 +0,0 @@
|
|||
/* ***** 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(function(require, exports, module) {
|
||||
|
||||
var types = require("pilot/types");
|
||||
var Type = types.Type;
|
||||
var Conversion = types.Conversion;
|
||||
var Status = types.Status;
|
||||
|
||||
/**
|
||||
* These are the basic types that we accept. They are vaguely based on the
|
||||
* Jetpack settings system (https://wiki.mozilla.org/Labs/Jetpack/JEP/24)
|
||||
* although clearly more restricted.
|
||||
*
|
||||
* <p>In addition to these types, Jetpack also accepts range, member, password
|
||||
* that we are thinking of adding.
|
||||
*
|
||||
* <p>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. settings
|
||||
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;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* One of a known set of options
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* Registration and de-registration.
|
||||
*/
|
||||
exports.startup = function() {
|
||||
types.registerType(text);
|
||||
types.registerType(number);
|
||||
types.registerType(bool);
|
||||
types.registerType(SelectionType);
|
||||
types.registerType(DeferredType);
|
||||
};
|
||||
|
||||
exports.shutdown = function() {
|
||||
types.unregisterType(text);
|
||||
types.unregisterType(number);
|
||||
types.unregisterType(bool);
|
||||
types.unregisterType(SelectionType);
|
||||
types.unregisterType(DeferredType);
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
/* ***** 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(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);
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -1,109 +0,0 @@
|
|||
/* ***** 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(function(require, exports, module) {
|
||||
|
||||
var SelectionType = require('pilot/types/basic').SelectionType;
|
||||
var DeferredType = require('pilot/types/basic').DeferredType;
|
||||
var types = require('pilot/types');
|
||||
var settings = require('pilot/settings').settings;
|
||||
|
||||
|
||||
/**
|
||||
* EVIL: This relies on us using settingValue in the same event as setting
|
||||
* The alternative is to have some central place where we store the current
|
||||
* command line, but this might be a lesser evil for now.
|
||||
*/
|
||||
var lastSetting;
|
||||
|
||||
/**
|
||||
* Select from the available settings
|
||||
*/
|
||||
var setting = new SelectionType({
|
||||
name: 'setting',
|
||||
data: function() {
|
||||
return env.settings.getSettingNames();
|
||||
},
|
||||
stringify: function(setting) {
|
||||
lastSetting = setting;
|
||||
return setting.name;
|
||||
},
|
||||
fromString: function(str) {
|
||||
lastSetting = settings.getSetting(str);
|
||||
return lastSetting;
|
||||
},
|
||||
noMatch: function() {
|
||||
lastSetting = null;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Something of a hack to allow the set command to give a clearer definition
|
||||
* of the type to the command line.
|
||||
*/
|
||||
var settingValue = new DeferredType({
|
||||
name: 'settingValue',
|
||||
defer: function() {
|
||||
if (lastSetting) {
|
||||
return lastSetting.type;
|
||||
}
|
||||
else {
|
||||
return types.getType('text');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var env;
|
||||
|
||||
/**
|
||||
* Registration and de-registration.
|
||||
*/
|
||||
exports.startup = function(data, reason) {
|
||||
// TODO: this is probably all kinds of evil, but we need something working
|
||||
env = data.env;
|
||||
types.registerType(setting);
|
||||
types.registerType(settingValue);
|
||||
};
|
||||
|
||||
exports.shutdown = function(data, reason) {
|
||||
types.unregisterType(setting);
|
||||
types.unregisterType(settingValue);
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
/* ***** 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 Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org Services B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var os = (navigator.platform.match(/mac|win|linux/i) || ["other"])[0].toLowerCase();
|
||||
var ua = navigator.userAgent;
|
||||
var av = navigator.appVersion;
|
||||
|
||||
/** Is the user using a browser that identifies itself as Windows */
|
||||
exports.isWin = (os == "win");
|
||||
|
||||
/** Is the user using a browser that identifies itself as Mac OS */
|
||||
exports.isMac = (os == "mac");
|
||||
|
||||
/** Is the user using a browser that identifies itself as Linux */
|
||||
exports.isLinux = (os == "linux");
|
||||
|
||||
exports.isIE = ! + "\v1";
|
||||
|
||||
/** Is this Firefox or related? */
|
||||
exports.isGecko = exports.isMozilla = window.controllers && window.navigator.product === "Gecko";
|
||||
|
||||
/** Is this Opera */
|
||||
exports.isOpera = window.opera && Object.prototype.toString.call(window.opera) == "[object Opera]";
|
||||
|
||||
/** Is the user using a browser that identifies itself as WebKit */
|
||||
exports.isWebKit = parseFloat(ua.split("WebKit/")[1]) || undefined;
|
||||
|
||||
exports.isAIR = ua.indexOf("AdobeAIR") >= 0;
|
||||
|
||||
/**
|
||||
* I hate doing this, but we need some way to determine if the user is on a Mac
|
||||
* The reason is that users have different expectations of their key combinations.
|
||||
*
|
||||
* Take copy as an example, Mac people expect to use CMD or APPLE + C
|
||||
* Windows folks expect to use CTRL + C
|
||||
*/
|
||||
exports.OS = {
|
||||
LINUX: 'LINUX',
|
||||
MAC: 'MAC',
|
||||
WINDOWS: 'WINDOWS'
|
||||
};
|
||||
|
||||
/**
|
||||
* Return an exports.OS constant
|
||||
*/
|
||||
exports.getOS = function() {
|
||||
if (exports.isMac) {
|
||||
return exports.OS['MAC'];
|
||||
} else if (exports.isLinux) {
|
||||
return exports.OS['LINUX'];
|
||||
} else {
|
||||
return exports.OS['WINDOWS'];
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
1
support/cockpit
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 47df3c340244b15c272ed87b17cd87659f4bcd0c
|
||||