Skip to content
This repository was archived by the owner on Jun 28, 2022. It is now read-only.

Commit cd39f73

Browse files
committed
runat-1128988: Improve support for custom properties for commands
GCLI has allowed (by turning a blind eye) to commands and other items that have additional properties. This is used by Firefox to allow commands to be placed in the toolbox and toolbar buttons with custom icons. With remote GCLI it's important that these custom properties are transferred along with the standard command metadata. This change allows the 'specs' function to take an array of custom properties which should be transferred. Signed-off-by: Joe Walker <jwalker@mozilla.com>
1 parent 0691a90 commit cd39f73

5 files changed

Lines changed: 75 additions & 25 deletions

File tree

lib/gcli/commands/commands.js

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,15 +161,19 @@ function Command(types, commandSpec) {
161161

162162
/**
163163
* JSON serializer that avoids non-serializable data
164+
* @param customProps Array of strings containing additional properties which,
165+
* if specified in the command spec, will be included in the JSON. Normally we
166+
* transfer only the properties required for GCLI to function.
164167
*/
165-
Command.prototype.toJson = function() {
168+
Command.prototype.toJson = function(customProps) {
166169
var json = {
167170
item: 'command',
168171
name: this.name,
169172
params: this.params.map(function(param) { return param.toJson(); }),
170173
returnType: this.returnType,
171174
isParent: (this.exec == null)
172175
};
176+
173177
if (this.description !== l10n.lookup('canonDescNone')) {
174178
json.description = this.description;
175179
}
@@ -179,6 +183,15 @@ Command.prototype.toJson = function() {
179183
if (this.hidden != null) {
180184
json.hidden = this.hidden;
181185
}
186+
187+
if (Array.isArray(customProps)) {
188+
customProps.forEach(function(prop) {
189+
if (this[prop] != null) {
190+
json[prop] = this[prop];
191+
}
192+
}.bind(this));
193+
}
194+
182195
return json;
183196
};
184197

@@ -425,14 +438,17 @@ Commands.prototype.getAll = function() {
425438
/**
426439
* Get access to the stored commandMetaDatas (i.e. before they were made into
427440
* instances of Command/Parameters) so we can remote them.
441+
* @param customProps Array of strings containing additional properties which,
442+
* if specified in the command spec, will be included in the JSON. Normally we
443+
* transfer only the properties required for GCLI to function.
428444
*/
429-
Commands.prototype.getCommandSpecs = function() {
445+
Commands.prototype.getCommandSpecs = function(customProps) {
430446
var commandSpecs = [];
431447

432448
Object.keys(this._commands).forEach(function(name) {
433449
var command = this._commands[name];
434450
if (!command.noRemote) {
435-
commandSpecs.push(command.toJson());
451+
commandSpecs.push(command.toJson(customProps));
436452
}
437453
}.bind(this));
438454

lib/gcli/connectors/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
var createSystem = require('../system').createSystem;
2020
var connectFront = require('../system').connectFront;
21-
var GcliFront = require('./connectors/remoted').GcliFront;
21+
var GcliFront = require('./remoted').GcliFront;
2222

2323
// Patch-up IE9
2424
require('../util/legacy');

lib/gcli/connectors/remoted.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,16 @@ Remoter.prototype.removeListener = function(action) {
7878
Remoter.prototype.exposed = {
7979
/**
8080
* Retrieve a list of the remotely executable commands
81+
* @param customProps Array of strings containing additional properties which,
82+
* if specified in the command spec, will be included in the JSON. Normally we
83+
* transfer only the properties required for GCLI to function.
8184
*/
82-
specs: method(function() {
83-
return this.requisition.system.commands.getCommandSpecs();
85+
specs: method(function(customProps) {
86+
return this.requisition.system.commands.getCommandSpecs(customProps);
8487
}, {
85-
request: {},
88+
request: {
89+
customProps: Arg(0, "nullable:array:string")
90+
},
8691
response: RetVal("json")
8792
}),
8893

lib/gcli/system.js

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
'use strict';
1818

1919
var Promise = require('./util/promise').Promise;
20+
var util = require('./util/util');
2021
var Commands = require('./commands/commands').Commands;
2122
var Connectors = require('./connectors/connectors').Connectors;
2223
var Converters = require('./converters/converters').Converters;
@@ -242,34 +243,41 @@ exports.createSystem = function(options) {
242243

243244
/**
244245
* Connect a local system with another at the other end of a connector
246+
* @param system System to which we're adding commands
247+
* @param front Front which allows access to the remote system from which we
248+
* import commands
249+
* @param customProps Array of strings specifying additional properties defined
250+
* on remote commands that should be considered part of the metadata for the
251+
* commands imported into the local system
245252
*/
246-
exports.connectFront = function(system, front) {
253+
exports.connectFront = function(system, front, customProps) {
247254
front.on('commandsChanged', function(specs) {
248-
syncItems(system, specs, front);
255+
syncItems(system, front, customProps).then(null, util.errorHandler);
249256
});
250257

251-
return front.specs().then(function(specs) {
252-
syncItems(system, specs, front);
253-
return system;
254-
});
258+
return syncItems(system, front, customProps);
255259
};
256260

257261
/**
258262
* Remove the items in this system that came from a previous sync action, and
259-
* re-add them
263+
* re-add them. See connectFront() for explanation of properties
260264
*/
261-
function syncItems(system, specs, front) {
262-
// Go through all the commands removing any that are associated with the given
263-
// front. The method of association is the hack in addLocalFunctions.
264-
system.commands.getAll().forEach(function(command) {
265-
if (command.front === front) {
266-
system.commands.remove(command);
267-
}
268-
});
265+
function syncItems(system, front, customProps) {
266+
return front.specs(customProps).then(function(specs) {
267+
// Go through all the commands removing any that are associated with the
268+
// given front. The method of association is the hack in addLocalFunctions.
269+
system.commands.getAll().forEach(function(command) {
270+
if (command.front === front) {
271+
system.commands.remove(command);
272+
}
273+
});
269274

270-
var remoteItems = addLocalFunctions(specs, front);
271-
system.addItems(remoteItems);
272-
}
275+
var remoteItems = addLocalFunctions(specs, front);
276+
system.addItems(remoteItems);
277+
278+
return system;
279+
});
280+
};
273281

274282
/**
275283
* Take the data from the 'specs' command (or the 'commandsChanged' event) and

lib/gcli/test/testCanon.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,9 @@ exports.testAltCommands = function(options) {
195195
{ name: 'num', type: 'number' },
196196
{ name: 'opt', type: { name: 'selection', data: [ '1', '2', '3' ] } },
197197
],
198+
customProp1: 'localValue',
199+
customProp2: true,
200+
customProp3: 42,
198201
exec: function(args, context) {
199202
return context.commandName + ':' +
200203
args.str + ':' + args.num + ':' + args.opt;
@@ -211,6 +214,24 @@ exports.testAltCommands = function(options) {
211214
'],"isParent":false}]',
212215
'JSON.stringify(commandSpecs)');
213216

217+
var customProps = [ 'customProp1', 'customProp2', 'customProp3', ];
218+
var commandSpecs2 = altCommands.getCommandSpecs(customProps);
219+
assert.is(JSON.stringify(commandSpecs2),
220+
'[{' +
221+
'"item":"command",' +
222+
'"name":"tss",' +
223+
'"params":[' +
224+
'{"name":"str","type":"string"},' +
225+
'{"name":"num","type":"number"},' +
226+
'{"name":"opt","type":{"name":"selection","data":["1","2","3"]}}' +
227+
'],' +
228+
'"isParent":false,' +
229+
'"customProp1":"localValue",' +
230+
'"customProp2":true,' +
231+
'"customProp3":42' +
232+
'}]',
233+
'JSON.stringify(commandSpecs)');
234+
214235
var remoter = function(args, context) {
215236
assert.is(context.commandName, 'tss', 'commandName is tss');
216237

0 commit comments

Comments
 (0)