зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1023233 - Add getSpec to union type; f=gl, r=mratcliffe
This commit is contained in:
Родитель
665b395d5a
Коммит
19227363e4
|
@ -103,3 +103,4 @@ skip-if = true || e10s # Disabled until TZ bug is fixed
|
|||
[browser_gcli_tokenize.js]
|
||||
[browser_gcli_tooltip.js]
|
||||
[browser_gcli_types.js]
|
||||
[browser_gcli_union.js]
|
||||
|
|
|
@ -10,36 +10,51 @@ function test() {
|
|||
helpers.addTabWithToolbar(TEST_URI, function(options) {
|
||||
return helpers.audit(options, [
|
||||
{
|
||||
setup: 'inject',
|
||||
setup: 'inject',
|
||||
check: {
|
||||
input: 'inject',
|
||||
hints: ' <library>',
|
||||
markup: 'VVVVVV',
|
||||
hints: ' <library>',
|
||||
status: 'ERROR'
|
||||
},
|
||||
},
|
||||
{
|
||||
setup: 'inject j',
|
||||
setup: 'inject j',
|
||||
check: {
|
||||
input: 'inject j',
|
||||
hints: 'Query',
|
||||
markup: 'VVVVVVVI',
|
||||
hints: 'Query',
|
||||
status: 'ERROR'
|
||||
},
|
||||
},
|
||||
{
|
||||
setup: 'inject http://example.com/browser/browser/devtools/commandline/test/browser_cmd_inject.js',
|
||||
setup: 'inject notauri',
|
||||
check: {
|
||||
input: 'inject notauri',
|
||||
hints: ' -> http://notauri/',
|
||||
markup: 'VVVVVVVIIIIIII',
|
||||
status: 'ERROR',
|
||||
args: {
|
||||
library: {
|
||||
value: undefined,
|
||||
status: 'INCOMPLETE'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
setup: 'inject http://example.com/browser/browser/devtools/commandline/test/browser_cmd_inject.js',
|
||||
check: {
|
||||
input: 'inject http://example.com/browser/browser/devtools/commandline/test/browser_cmd_inject.js',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
|
||||
hints: '',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
library: {
|
||||
value: function(library) {
|
||||
is(library.type, 'string', 'inject type name');
|
||||
is(library.string, 'http://example.com/browser/browser/devtools/commandline/test/browser_cmd_inject.js',
|
||||
'inject uri data');
|
||||
is(library.type, 'url', 'inject type name');
|
||||
is(library.url.origin, 'http://example.com', 'inject url hostname');
|
||||
ok(library.url.path.indexOf('_inject.js') != -1, 'inject url path');
|
||||
},
|
||||
status: 'VALID'
|
||||
}
|
||||
|
@ -48,27 +63,6 @@ function test() {
|
|||
exec: {
|
||||
output: [ /http:\/\/example.com\/browser\/browser\/devtools\/commandline\/test\/browser_cmd_inject.js loaded/ ]
|
||||
}
|
||||
},
|
||||
{
|
||||
setup: 'inject notauri',
|
||||
check: {
|
||||
input: 'inject notauri',
|
||||
hints: '',
|
||||
markup: 'VVVVVVVVVVVVVV',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
library: {
|
||||
value: function(library) {
|
||||
is(library.type, 'string', 'inject type name');
|
||||
is(library.string, 'notauri', 'inject notauri data');
|
||||
},
|
||||
status: 'VALID'
|
||||
}
|
||||
}
|
||||
},
|
||||
exec: {
|
||||
output: [ /Failed to load notauri - Invalid URI/ ]
|
||||
}
|
||||
}
|
||||
]);
|
||||
}).then(finish, helpers.handleError);
|
||||
|
|
|
@ -77,7 +77,7 @@ function forEachType(options, typeSpec, callback) {
|
|||
return;
|
||||
}
|
||||
else if (name === 'union') {
|
||||
typeSpec.types = [{ name: "string" }];
|
||||
typeSpec.alternatives = [{ name: 'string' }];
|
||||
}
|
||||
|
||||
var type = types.createType(typeSpec);
|
||||
|
@ -89,7 +89,7 @@ function forEachType(options, typeSpec, callback) {
|
|||
delete typeSpec.data;
|
||||
delete typeSpec.delegateType;
|
||||
delete typeSpec.subtype;
|
||||
delete typeSpec.types;
|
||||
delete typeSpec.alternatives;
|
||||
|
||||
return value;
|
||||
});
|
||||
|
@ -134,3 +134,20 @@ exports.testNullDefault = function(options) {
|
|||
});
|
||||
});
|
||||
};
|
||||
|
||||
exports.testGetSpec = function(options) {
|
||||
return forEachType(options, {}, function(type) {
|
||||
if (type.name === 'param') {
|
||||
return;
|
||||
}
|
||||
|
||||
var spec = type.getSpec('cmd', 'param');
|
||||
assert.ok(spec != null, 'non null spec for ' + type.name);
|
||||
|
||||
var str = JSON.stringify(spec);
|
||||
assert.ok(str != null, 'serializable spec for ' + type.name);
|
||||
|
||||
var example = options.requisition.types.createType(spec);
|
||||
assert.ok(example != null, 'creatable spec for ' + type.name);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Copyright 2012, Mozilla Foundation and contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
// <INJECTED SOURCE:START>
|
||||
|
||||
// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
|
||||
// DO NOT EDIT IT DIRECTLY
|
||||
|
||||
var exports = {};
|
||||
|
||||
var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testUnion.js</p>";
|
||||
|
||||
function test() {
|
||||
return Task.spawn(function() {
|
||||
let options = yield helpers.openTab(TEST_URI);
|
||||
yield helpers.openToolbar(options);
|
||||
gcli.addItems(mockCommands.items);
|
||||
|
||||
yield helpers.runTests(options, exports);
|
||||
|
||||
gcli.removeItems(mockCommands.items);
|
||||
yield helpers.closeToolbar(options);
|
||||
yield helpers.closeTab(options);
|
||||
}).then(finish, helpers.handleError);
|
||||
}
|
||||
|
||||
// <INJECTED SOURCE:END>
|
||||
|
||||
// var assert = require('../testharness/assert');
|
||||
// var helpers = require('./helpers');
|
||||
|
||||
exports.testDefault = function(options) {
|
||||
return helpers.audit(options, [
|
||||
{
|
||||
setup: 'unionc1',
|
||||
check: {
|
||||
input: 'unionc1',
|
||||
markup: 'VVVVVVV',
|
||||
hints: ' <first>',
|
||||
status: 'ERROR',
|
||||
args: {
|
||||
first: {
|
||||
value: undefined,
|
||||
arg: '',
|
||||
status: 'INCOMPLETE'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
setup: 'unionc1 three',
|
||||
check: {
|
||||
input: 'unionc1 three',
|
||||
markup: 'VVVVVVVVVVVVV',
|
||||
hints: '',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
first: {
|
||||
value: function(data) {
|
||||
assert.is(Object.keys(data).length, 2, 'union3 Object.keys');
|
||||
assert.is(data.type, 'string', 'union3 val type');
|
||||
assert.is(data.string, 'three', 'union3 val string');
|
||||
},
|
||||
arg: ' three',
|
||||
status: 'VALID'
|
||||
}
|
||||
}
|
||||
},
|
||||
exec: {
|
||||
output: [
|
||||
/"type": ?"string"/,
|
||||
/"string": ?"three"/
|
||||
]
|
||||
},
|
||||
post: function(output, text) {
|
||||
var data = output.data.first;
|
||||
assert.is(Object.keys(data).length, 2, 'union3 Object.keys');
|
||||
assert.is(data.type, 'string', 'union3 val type');
|
||||
assert.is(data.string, 'three', 'union3 val string');
|
||||
}
|
||||
},
|
||||
{
|
||||
setup: 'unionc1 one',
|
||||
check: {
|
||||
input: 'unionc1 one',
|
||||
markup: 'VVVVVVVVVVV',
|
||||
hints: '',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
first: {
|
||||
value: function(data) {
|
||||
assert.is(Object.keys(data).length, 2, 'union1 Object.keys');
|
||||
assert.is(data.type, 'selection', 'union1 val type');
|
||||
assert.is(data.selection, 1, 'union1 val selection');
|
||||
},
|
||||
arg: ' one',
|
||||
status: 'VALID'
|
||||
}
|
||||
}
|
||||
},
|
||||
exec: {
|
||||
output: [
|
||||
/"type": ?"selection"/,
|
||||
/"selection": ?1/
|
||||
]
|
||||
},
|
||||
post: function(output, text) {
|
||||
var data = output.data.first;
|
||||
assert.is(Object.keys(data).length, 2, 'union1 Object.keys');
|
||||
assert.is(data.type, 'selection', 'union1 val type');
|
||||
assert.is(data.selection, 1, 'union1 val selection');
|
||||
}
|
||||
},
|
||||
{
|
||||
skipIf: options.isPhantomjs, // Phantom goes weird with predictions
|
||||
setup: 'unionc1 5',
|
||||
check: {
|
||||
input: 'unionc1 5',
|
||||
markup: 'VVVVVVVVV',
|
||||
hints: ' -> two',
|
||||
predictions: [ 'two' ],
|
||||
status: 'VALID',
|
||||
args: {
|
||||
first: {
|
||||
value: function(data) {
|
||||
assert.is(Object.keys(data).length, 2, 'union5 Object.keys');
|
||||
assert.is(data.type, 'number', 'union5 val type');
|
||||
assert.is(data.number, 5, 'union5 val number');
|
||||
},
|
||||
arg: ' 5',
|
||||
status: 'VALID'
|
||||
}
|
||||
}
|
||||
},
|
||||
exec: {
|
||||
output: [
|
||||
/"type": ?"number"/,
|
||||
/"number": ?5/
|
||||
]
|
||||
},
|
||||
post: function(output, text) {
|
||||
var data = output.data.first;
|
||||
assert.is(Object.keys(data).length, 2, 'union5 Object.keys');
|
||||
assert.is(data.type, 'number', 'union5 val type');
|
||||
assert.is(data.number, 5, 'union5 val number');
|
||||
}
|
||||
},
|
||||
{
|
||||
skipRemainingIf: options.isPhantomjs,
|
||||
setup: 'unionc2 on',
|
||||
check: {
|
||||
input: 'unionc2 on',
|
||||
hints: 'e',
|
||||
markup: 'VVVVVVVVII',
|
||||
current: 'first',
|
||||
status: 'ERROR',
|
||||
predictionsContains: [
|
||||
'one',
|
||||
'http://on/',
|
||||
'https://on/'
|
||||
],
|
||||
args: {
|
||||
command: { name: 'unionc2' },
|
||||
first: {
|
||||
value: undefined,
|
||||
arg: ' on',
|
||||
status: 'INCOMPLETE',
|
||||
message: 'Can\'t use \'on\'.'
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
]);
|
||||
};
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Copyright 2012, Mozilla Foundation and contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
// <INJECTED SOURCE:START>
|
||||
|
||||
// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
|
||||
// DO NOT EDIT IT DIRECTLY
|
||||
|
||||
var exports = {};
|
||||
|
||||
var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testUrl.js</p>";
|
||||
|
||||
function test() {
|
||||
return Task.spawn(function() {
|
||||
let options = yield helpers.openTab(TEST_URI);
|
||||
yield helpers.openToolbar(options);
|
||||
gcli.addItems(mockCommands.items);
|
||||
|
||||
yield helpers.runTests(options, exports);
|
||||
|
||||
gcli.removeItems(mockCommands.items);
|
||||
yield helpers.closeToolbar(options);
|
||||
yield helpers.closeTab(options);
|
||||
}).then(finish, helpers.handleError);
|
||||
}
|
||||
|
||||
// <INJECTED SOURCE:END>
|
||||
|
||||
// var assert = require('../testharness/assert');
|
||||
// var helpers = require('./helpers');
|
||||
|
||||
exports.testDefault = function(options) {
|
||||
return helpers.audit(options, [
|
||||
{
|
||||
skipRemainingIf: options.isPhantomjs,
|
||||
setup: 'urlc',
|
||||
check: {
|
||||
input: 'urlc',
|
||||
markup: 'VVVV',
|
||||
hints: ' <url>',
|
||||
status: 'ERROR',
|
||||
args: {
|
||||
url: {
|
||||
value: undefined,
|
||||
arg: '',
|
||||
status: 'INCOMPLETE'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
setup: 'urlc example',
|
||||
check: {
|
||||
input: 'urlc example',
|
||||
markup: 'VVVVVIIIIIII',
|
||||
hints: ' -> http://example/',
|
||||
predictions: [
|
||||
'http://example/',
|
||||
'https://example/',
|
||||
'http://localhost:9999/example'
|
||||
],
|
||||
status: 'ERROR',
|
||||
args: {
|
||||
url: {
|
||||
value: undefined,
|
||||
arg: ' example',
|
||||
status: 'INCOMPLETE'
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
setup: 'urlc example.com/',
|
||||
check: {
|
||||
input: 'urlc example.com/',
|
||||
markup: 'VVVVVIIIIIIIIIIII',
|
||||
hints: ' -> http://example.com/',
|
||||
status: 'ERROR',
|
||||
args: {
|
||||
url: {
|
||||
value: undefined,
|
||||
arg: ' example.com/',
|
||||
status: 'INCOMPLETE'
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
setup: 'urlc http://example.com/index?q=a#hash',
|
||||
check: {
|
||||
input: 'urlc http://example.com/index?q=a#hash',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
|
||||
hints: '',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
url: {
|
||||
value: function(data) {
|
||||
assert.is(data.hash, '#hash', 'url hash');
|
||||
},
|
||||
arg: ' http://example.com/index?q=a#hash',
|
||||
status: 'VALID'
|
||||
}
|
||||
}
|
||||
},
|
||||
exec: { output: /"url": ?/ }
|
||||
}
|
||||
]);
|
||||
};
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
|
||||
var Promise = require('gcli/util/promise').Promise;
|
||||
var converters = require('gcli/converters/converters');
|
||||
var mockCommands = {};
|
||||
|
||||
// We use an alias for exports here because this module is used in Firefox
|
||||
|
@ -40,6 +41,9 @@ mockCommands.setup = function(requisition) {
|
|||
else if (item.item === 'type') {
|
||||
requisition.types.addType(item);
|
||||
}
|
||||
else if (item.item === 'converter') {
|
||||
converters.addConverter(item);
|
||||
}
|
||||
else {
|
||||
console.error('Ignoring item ', item);
|
||||
}
|
||||
|
@ -54,6 +58,9 @@ mockCommands.shutdown = function(requisition) {
|
|||
else if (item.item === 'type') {
|
||||
requisition.types.removeType(item);
|
||||
}
|
||||
else if (item.item === 'converter') {
|
||||
converters.removeConverter(item);
|
||||
}
|
||||
else {
|
||||
console.error('Ignoring item ', item);
|
||||
}
|
||||
|
@ -70,6 +77,25 @@ function createExec(name) {
|
|||
}
|
||||
|
||||
mockCommands.items = [
|
||||
{
|
||||
item: 'converter',
|
||||
from: 'json',
|
||||
to: 'string',
|
||||
exec: function(json, context) {
|
||||
return JSON.stringify(json, null, ' ');
|
||||
}
|
||||
},
|
||||
{
|
||||
item: 'converter',
|
||||
from: 'json',
|
||||
to: 'view',
|
||||
exec: function(json, context) {
|
||||
var html = JSON.stringify(json, null, ' ').replace(/\n/g, '<br/>');
|
||||
return {
|
||||
html: '<pre>' + html + '</pre>'
|
||||
};
|
||||
}
|
||||
},
|
||||
{
|
||||
item: 'type',
|
||||
name: 'optionType',
|
||||
|
@ -670,5 +696,74 @@ mockCommands.items = [
|
|||
exec: function(args, context) {
|
||||
return 'Test completed';
|
||||
}
|
||||
},
|
||||
{
|
||||
item: 'command',
|
||||
name: 'urlc',
|
||||
params: [
|
||||
{
|
||||
name: 'url',
|
||||
type: 'url'
|
||||
}
|
||||
],
|
||||
returnType: 'json',
|
||||
exec: function(args, context) {
|
||||
return args;
|
||||
}
|
||||
},
|
||||
{
|
||||
item: 'command',
|
||||
name: 'unionc1',
|
||||
params: [
|
||||
{
|
||||
name: 'first',
|
||||
type: {
|
||||
name: 'union',
|
||||
alternatives: [
|
||||
{
|
||||
name: 'selection',
|
||||
lookup: [
|
||||
{ name: 'one', value: 1 },
|
||||
{ name: 'two', value: 2 },
|
||||
]
|
||||
},
|
||||
'number',
|
||||
{ name: 'string' }
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
returnType: 'json',
|
||||
exec: function(args, context) {
|
||||
return args;
|
||||
}
|
||||
},
|
||||
{
|
||||
item: 'command',
|
||||
name: 'unionc2',
|
||||
params: [
|
||||
{
|
||||
name: 'first',
|
||||
type: {
|
||||
name: 'union',
|
||||
alternatives: [
|
||||
{
|
||||
name: 'selection',
|
||||
lookup: [
|
||||
{ name: 'one', value: 1 },
|
||||
{ name: 'two', value: 2 },
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'url'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
returnType: 'json',
|
||||
exec: function(args, context) {
|
||||
return args;
|
||||
}
|
||||
}
|
||||
];
|
||||
|
|
|
@ -14,10 +14,10 @@ exports.items = [
|
|||
description: gcli.lookup("injectDesc"),
|
||||
manual: gcli.lookup("injectManual2"),
|
||||
params: [{
|
||||
name: 'library',
|
||||
name: "library",
|
||||
type: {
|
||||
name: "union",
|
||||
types: [
|
||||
alternatives: [
|
||||
{
|
||||
name: "selection",
|
||||
lookup: [
|
||||
|
@ -45,7 +45,7 @@ exports.items = [
|
|||
]
|
||||
},
|
||||
{
|
||||
name: "string"
|
||||
name: "url"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -55,9 +55,13 @@ exports.items = [
|
|||
let document = context.environment.document;
|
||||
let library = args.library;
|
||||
let name = (library.type === "selection") ?
|
||||
library.selection.name : library.string;
|
||||
library.selection.name : library.url;
|
||||
let src = (library.type === "selection") ?
|
||||
library.selection.src : library.string;
|
||||
library.selection.src : library.url;
|
||||
|
||||
if (context.environment.window.location.protocol == "https:") {
|
||||
src = src.replace(/^http:/, "https:");
|
||||
}
|
||||
|
||||
try {
|
||||
// Check if URI is valid
|
||||
|
|
|
@ -21,6 +21,7 @@ require('../test/suite');
|
|||
var examiner = require('../testharness/examiner');
|
||||
var stati = require('../testharness/status').stati;
|
||||
var helpers = require('../test/helpers');
|
||||
var cli = require('../cli');
|
||||
var Requisition = require('../cli').Requisition;
|
||||
var createRequisitionAutomator = require('../test/automators/requisition').createRequisitionAutomator;
|
||||
|
||||
|
@ -85,7 +86,15 @@ exports.items = [
|
|||
|
||||
return args.suite.run(options).then(function() {
|
||||
requisition.canon.getCommand('mocks').off(requisition);
|
||||
return examiner.toRemote();
|
||||
var output = context.typedData('examiner-output', examiner.toRemote());
|
||||
|
||||
if (output.data.summary.status === stati.pass) {
|
||||
return output;
|
||||
}
|
||||
else {
|
||||
cli.logErrors = false;
|
||||
throw output;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
@ -94,15 +103,8 @@ exports.items = [
|
|||
from: 'examiner-output',
|
||||
to: 'string',
|
||||
exec: function(output, conversionContext) {
|
||||
var reply = '\n' + examiner.detailedResultLog('NodeJS/NoDom') +
|
||||
'\n' + helpers.timingSummary;
|
||||
|
||||
if (output.summary.status === stati.pass) {
|
||||
return reply;
|
||||
}
|
||||
else {
|
||||
throw reply;
|
||||
}
|
||||
return '\n' + examiner.detailedResultLog('NodeJS/NoDom') +
|
||||
'\n' + helpers.timingSummary;
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -54,6 +54,7 @@ var items = [
|
|||
require('../types/setting').items,
|
||||
require('../types/string').items,
|
||||
require('../types/union').items,
|
||||
require('../types/url').items,
|
||||
|
||||
require('../fields/delegate').items,
|
||||
require('../fields/selection').items,
|
||||
|
|
|
@ -49,7 +49,7 @@ SelectionField.claim = function(type, context) {
|
|||
if (context == null) {
|
||||
return Field.NO_MATCH;
|
||||
}
|
||||
return type.getType(context).isSelection ? Field.MATCH : Field.NO_MATCH;
|
||||
return type.getType(context).hasPredictions ? Field.DEFAULT : Field.NO_MATCH;
|
||||
};
|
||||
|
||||
SelectionField.prototype.destroy = function() {
|
||||
|
|
|
@ -49,6 +49,7 @@ var items = [
|
|||
require('./types/setting').items,
|
||||
require('./types/string').items,
|
||||
require('./types/union').items,
|
||||
require('./types/url').items,
|
||||
|
||||
require('./fields/delegate').items,
|
||||
require('./fields/selection').items,
|
||||
|
|
|
@ -39,7 +39,7 @@ exports.items = [
|
|||
|
||||
getSpec: function(commandName, paramName) {
|
||||
return {
|
||||
name: 'remote',
|
||||
name: 'delegate',
|
||||
param: paramName
|
||||
};
|
||||
},
|
||||
|
@ -142,6 +142,10 @@ exports.items = [
|
|||
item: 'type',
|
||||
name: 'blank',
|
||||
|
||||
getSpec: function(commandName, paramName) {
|
||||
return 'blank';
|
||||
},
|
||||
|
||||
stringify: function(value, context) {
|
||||
return '';
|
||||
},
|
||||
|
|
|
@ -49,7 +49,7 @@ exports.items = [
|
|||
existing: 'maybe', // Should be one of 'yes', 'no', 'maybe'
|
||||
matches: undefined, // RegExp to match the file part of the path
|
||||
|
||||
isSelection: true, // It's not really a selection, but acts like one
|
||||
hasPredictions: true,
|
||||
|
||||
constructor: function() {
|
||||
if (this.filetype !== 'any' && this.filetype !== 'file' &&
|
||||
|
|
|
@ -381,10 +381,10 @@ SelectionType.prototype._findValue = function(lookup, value) {
|
|||
};
|
||||
|
||||
/**
|
||||
* SelectionType is designed to be inherited from, so SelectionField needs a way
|
||||
* to check if something works like a selection without using 'name'
|
||||
* This is how we indicate to SelectionField that we have predictions that
|
||||
* might work in a menu.
|
||||
*/
|
||||
SelectionType.prototype.isSelection = true;
|
||||
SelectionType.prototype.hasPredictions = true;
|
||||
|
||||
SelectionType.prototype.name = 'selection';
|
||||
|
||||
|
|
|
@ -1140,13 +1140,8 @@ Types.prototype.createType = function(typeSpec) {
|
|||
// Copy the properties of typeSpec onto the new type
|
||||
util.copyProperties(typeSpec, newType);
|
||||
|
||||
// Delegate and Array types need special powers to create types. Injecting
|
||||
// ourselves at this point seems nasty, but better than the alternative of
|
||||
// forcing all children of delegate types to require the full types API, and
|
||||
// not know where to get it from
|
||||
if (newType.name === 'delegate' || newType.name === 'array') {
|
||||
newType.types = this;
|
||||
}
|
||||
// Several types need special powers to create child types
|
||||
newType.types = this;
|
||||
|
||||
if (typeof NewTypeCtor !== 'function') {
|
||||
if (typeof newType.constructor === 'function') {
|
||||
|
|
|
@ -18,79 +18,101 @@
|
|||
|
||||
var Promise = require('../util/promise').Promise;
|
||||
var l10n = require('../util/l10n');
|
||||
var centralTypes = require("./types").centralTypes;
|
||||
var Conversion = require("./types").Conversion;
|
||||
var Status = require("./types").Status;
|
||||
var Conversion = require('./types').Conversion;
|
||||
var Status = require('./types').Status;
|
||||
|
||||
exports.items = [
|
||||
{
|
||||
// The union type allows for a combination of different parameter types.
|
||||
item: "type",
|
||||
name: "union",
|
||||
item: 'type',
|
||||
name: 'union',
|
||||
hasPredictions: true,
|
||||
|
||||
constructor: function() {
|
||||
// Get the properties of the type. The last object in the list of types
|
||||
// should always be a string type.
|
||||
this.types = this.types.map(function(typeData) {
|
||||
typeData.type = centralTypes.createType(typeData);
|
||||
typeData.lookup = typeData.lookup;
|
||||
return typeData;
|
||||
});
|
||||
// Get the properties of the type. Later types in the list should always
|
||||
// be more general, so 'catch all' types like string must be last
|
||||
this.alternatives = this.alternatives.map(function(typeData) {
|
||||
return this.types.createType(typeData);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
getSpec: function(command, param) {
|
||||
var spec = { name: 'union', alternatives: [] };
|
||||
this.alternatives.forEach(function(type) {
|
||||
spec.alternatives.push(type.getSpec(command, param));
|
||||
}.bind(this));
|
||||
return spec;
|
||||
},
|
||||
|
||||
stringify: function(value, context) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
return '';
|
||||
}
|
||||
|
||||
var type = this.types.find(function(typeData) {
|
||||
return typeData.name == value.type;
|
||||
}).type;
|
||||
var type = this.alternatives.find(function(typeData) {
|
||||
return typeData.name === value.type;
|
||||
});
|
||||
|
||||
return type.stringify(value[value.type], context);
|
||||
},
|
||||
|
||||
parse: function(arg, context) {
|
||||
// Try to parse the given argument in the provided order of the parameter
|
||||
// types. Returns a promise containing the Conversion of the value that
|
||||
// was parsed.
|
||||
var self = this;
|
||||
var conversionPromises = this.alternatives.map(function(type) {
|
||||
return type.parse(arg, context);
|
||||
}.bind(this));
|
||||
|
||||
var onError = function(i) {
|
||||
if (i >= self.types.length) {
|
||||
return Promise.reject(new Conversion(undefined, arg, Status.ERROR,
|
||||
l10n.lookup("commandParseError")));
|
||||
} else {
|
||||
return tryNext(i + 1);
|
||||
}
|
||||
};
|
||||
return Promise.all(conversionPromises).then(function(conversions) {
|
||||
// Find a list of the predictions made by any conversion
|
||||
var predictionPromises = conversions.map(function(conversion) {
|
||||
return conversion.getPredictions(context);
|
||||
}.bind(this));
|
||||
|
||||
var tryNext = function(i) {
|
||||
var type = self.types[i].type;
|
||||
return Promise.all(predictionPromises).then(function(allPredictions) {
|
||||
// Take one prediction from each set of predictions, ignoring
|
||||
// duplicates, until we've got up to Conversion.maxPredictions
|
||||
var maxIndex = allPredictions.reduce(function(prev, prediction) {
|
||||
return Math.max(prev, prediction.length);
|
||||
}.bind(this), 0);
|
||||
var predictions = [];
|
||||
|
||||
try {
|
||||
return type.parse(arg, context).then(function(conversion) {
|
||||
if (conversion.getStatus() === Status.VALID ||
|
||||
conversion.getStatus() === Status.INCOMPLETE) {
|
||||
// Converts the conversion value of the union type to an
|
||||
// object that identifies the current working type and the
|
||||
// data associated with it
|
||||
if (conversion.value) {
|
||||
var oldConversionValue = conversion.value;
|
||||
conversion.value = { type: type.name };
|
||||
conversion.value[type.name] = oldConversionValue;
|
||||
indexLoop:
|
||||
for (var index = 0; index < maxIndex; index++) {
|
||||
for (var p = 0; p <= allPredictions.length; p++) {
|
||||
if (predictions.length >= Conversion.maxPredictions) {
|
||||
break indexLoop;
|
||||
}
|
||||
return conversion;
|
||||
} else {
|
||||
return onError(i);
|
||||
}
|
||||
});
|
||||
} catch(e) {
|
||||
return onError(i);
|
||||
}
|
||||
};
|
||||
|
||||
return Promise.resolve(tryNext(0));
|
||||
if (allPredictions[p] != null) {
|
||||
var prediction = allPredictions[p][index];
|
||||
if (prediction != null && predictions.indexOf(prediction) === -1) {
|
||||
predictions.push(prediction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var bestStatus = Status.ERROR;
|
||||
var value;
|
||||
for (var i = 0; i < conversions.length; i++) {
|
||||
var conversion = conversions[i];
|
||||
var thisStatus = conversion.getStatus(arg);
|
||||
if (thisStatus < bestStatus) {
|
||||
bestStatus = thisStatus;
|
||||
}
|
||||
if (bestStatus === Status.VALID) {
|
||||
var type = this.alternatives[i].name;
|
||||
value = { type: type };
|
||||
value[type] = conversion.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var msg = (bestStatus === Status.VALID) ?
|
||||
'' :
|
||||
l10n.lookupFormat('typesSelectionNomatch', [ arg.text ]);
|
||||
return new Conversion(value, arg, bestStatus, msg, predictions);
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
},
|
||||
}
|
||||
];
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright 2012, Mozilla Foundation and contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var host = require('../util/host');
|
||||
var Promise = require('../util/promise').Promise;
|
||||
var Status = require('./types').Status;
|
||||
var Conversion = require('./types').Conversion;
|
||||
|
||||
exports.items = [
|
||||
{
|
||||
item: 'type',
|
||||
name: 'url',
|
||||
|
||||
getSpec: function() {
|
||||
return 'url';
|
||||
},
|
||||
|
||||
stringify: function(value, context) {
|
||||
if (value == null) {
|
||||
return '';
|
||||
}
|
||||
return value.href;
|
||||
},
|
||||
|
||||
parse: function(arg, context) {
|
||||
var conversion;
|
||||
|
||||
try {
|
||||
var url = host.createUrl(arg.text);
|
||||
conversion = new Conversion(url, arg);
|
||||
}
|
||||
catch (ex) {
|
||||
var predictions = [];
|
||||
var status = Status.ERROR;
|
||||
|
||||
// Maybe the URL was missing a scheme?
|
||||
if (arg.text.indexOf('://') === -1) {
|
||||
[ 'http', 'https' ].forEach(function(scheme) {
|
||||
try {
|
||||
var http = host.createUrl(scheme + '://' + arg.text);
|
||||
predictions.push({ name: http.href, value: http });
|
||||
}
|
||||
catch (ex) {
|
||||
// Ignore
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
// Try to create a URL with the current page as a base ref
|
||||
if (context.environment.window) {
|
||||
try {
|
||||
var base = context.environment.window.location.href;
|
||||
var localized = host.createUrl(arg.text, base);
|
||||
predictions.push({ name: localized.href, value: localized });
|
||||
}
|
||||
catch (ex) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (predictions.length > 0) {
|
||||
status = Status.INCOMPLETE;
|
||||
}
|
||||
|
||||
conversion = new Conversion(undefined, arg, status,
|
||||
ex.message, predictions);
|
||||
}
|
||||
|
||||
return Promise.resolve(conversion);
|
||||
}
|
||||
}
|
||||
];
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
var Cc = require('chrome').Cc;
|
||||
var Ci = require('chrome').Ci;
|
||||
var URL = require("sdk/url").URL;
|
||||
|
||||
var Task = require('resource://gre/modules/Task.jsm').Task;
|
||||
|
||||
|
@ -71,6 +72,13 @@ exports.exec = function(task) {
|
|||
return Task.spawn(task);
|
||||
};
|
||||
|
||||
/**
|
||||
* The URL API is new enough that we need specific platform help
|
||||
*/
|
||||
exports.createUrl = function(uristr, base) {
|
||||
return URL(uristr, base);
|
||||
};
|
||||
|
||||
/**
|
||||
* Load some HTML into the given document and return a DOM element.
|
||||
* This utility assumes that the html has a single root (other than whitespace)
|
||||
|
|
|
@ -75,6 +75,40 @@ if (typeof document !== 'undefined' && typeof HTMLElement !== 'undefined' &&
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Array.find
|
||||
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
|
||||
*/
|
||||
if (!Array.prototype.find) {
|
||||
Object.defineProperty(Array.prototype, 'find', {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: function(predicate) {
|
||||
if (this == null) {
|
||||
throw new TypeError('Array.prototype.find called on null or undefined');
|
||||
}
|
||||
if (typeof predicate !== 'function') {
|
||||
throw new TypeError('predicate must be a function');
|
||||
}
|
||||
var list = Object(this);
|
||||
var length = list.length >>> 0;
|
||||
var thisArg = arguments[1];
|
||||
var value;
|
||||
|
||||
for (var i = 0; i < length; i++) {
|
||||
if (i in list) {
|
||||
value = list[i];
|
||||
if (predicate.call(thisArg, value, i, list)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* String.prototype.trimLeft is non-standard, but it works in Firefox,
|
||||
* Chrome and Opera. It's easiest to create a shim here.
|
||||
|
|
Загрузка…
Ссылка в новой задаче