mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 20:05:49 +00:00
Bug 757496 - Support mozKeyboard.setSelectedOption[s]. r=fabrice
--HG-- extra : rebase_source : 4f62f03c060524aa62eb388554b1c94d674505b6
This commit is contained in:
parent
955543dd18
commit
a52844af7a
157
b2g/chrome/content/forms.js
Normal file
157
b2g/chrome/content/forms.js
Normal file
@ -0,0 +1,157 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
let Ci = Components.interfaces;
|
||||
let Cc = Components.classes;
|
||||
let Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
dump("###################################### forms.js loaded\n");
|
||||
|
||||
let HTMLSelectElement = Ci.nsIDOMHTMLSelectElement;
|
||||
let HTMLOptGroupElement = Ci.nsIDOMHTMLOptGroupElement;
|
||||
let HTMLOptionElement = Ci.nsIDOMHTMLOptionElement;
|
||||
|
||||
let FormAssistant = {
|
||||
init: function fa_init() {
|
||||
addEventListener("focus", this, true, false);
|
||||
addEventListener("click", this, true, false);
|
||||
addEventListener("blur", this, true, false);
|
||||
addMessageListener("Forms:Select:Choice", this);
|
||||
Services.obs.addObserver(this, "xpcom-shutdown", false);
|
||||
},
|
||||
|
||||
currentTarget: null,
|
||||
handleEvent: function fa_handleEvent(evt) {
|
||||
switch (evt.type) {
|
||||
case "click":
|
||||
case "focus": {
|
||||
content.setTimeout(function(self) {
|
||||
let target = evt.target;
|
||||
if (target instanceof HTMLSelectElement) {
|
||||
sendAsyncMessage("Forms:Input", self._getJSON(target));
|
||||
self.currentTarget = target;
|
||||
} else if (target instanceof HTMLOptionElement &&
|
||||
target.parentNode instanceof HTMLSelectElement) {
|
||||
target = target.parentNode;
|
||||
sendAsyncMessage("Forms:Input", self._getJSON(target));
|
||||
self.currentTarget = target;
|
||||
}
|
||||
}, 0, this);
|
||||
break;
|
||||
}
|
||||
|
||||
case "blur": {
|
||||
let target = this.currentTarget;
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
this.currentTarget = null;
|
||||
|
||||
sendAsyncMessage("Forms:Input", { "type": "blur" });
|
||||
|
||||
let e = target.ownerDocument.createEvent("Events");
|
||||
e.initEvent("change", true, true, target.ownerDocument.defaultView,
|
||||
0, false, false, false, false, null);
|
||||
|
||||
content.setTimeout(function() {
|
||||
target.dispatchEvent(evt);
|
||||
}, 0);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
receiveMessage: function fa_receiveMessage(msg) {
|
||||
let json = msg.json;
|
||||
switch (msg.name) {
|
||||
case "Forms:Select:Choice":
|
||||
if (!this.currentTarget)
|
||||
return;
|
||||
|
||||
let options = this.currentTarget.options;
|
||||
if ("index" in json) {
|
||||
options.item(json.index).selected = true;
|
||||
} else if ("indexes" in json) {
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
options.item(i).selected = (json.indexes.indexOf(i) != -1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
observe: function fa_observe(subject, topic, data) {
|
||||
Services.obs.removeObserver(this, "xpcom-shutdown");
|
||||
removeMessageListener("Forms:Select:Choice", this);
|
||||
},
|
||||
|
||||
_getJSON: function fa_getJSON(element) {
|
||||
let choices = getListForElement(element);
|
||||
return {
|
||||
type: element.type.toLowerCase(),
|
||||
choices: choices
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
FormAssistant.init();
|
||||
|
||||
function getListForElement(element) {
|
||||
if (!(element instanceof HTMLSelectElement))
|
||||
return null;
|
||||
|
||||
let optionIndex = 0;
|
||||
let result = {
|
||||
"multiple": element.multiple,
|
||||
"choices": []
|
||||
};
|
||||
|
||||
// Build up a flat JSON array of the choices.
|
||||
// In HTML, it's possible for select element choices to be under a
|
||||
// group header (but not recursively). We distinguish between headers
|
||||
// and entries using the boolean "list.group".
|
||||
let children = element.children;
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
let child = children[i];
|
||||
|
||||
if (child instanceof HTMLOptGroupElement) {
|
||||
result.choices.push({
|
||||
"group": true,
|
||||
"text": child.label || child.firstChild.data,
|
||||
"disabled": child.disabled
|
||||
});
|
||||
|
||||
let subchildren = child.children;
|
||||
for (let j = 0; j < subchildren.length; j++) {
|
||||
let subchild = subchildren[j];
|
||||
result.choices.push({
|
||||
"group": false,
|
||||
"inGroup": true,
|
||||
"text": subchild.text,
|
||||
"disabled": child.disabled || subchild.disabled,
|
||||
"selected": subchild.selected,
|
||||
"optionIndex": optionIndex++
|
||||
});
|
||||
}
|
||||
} else if (child instanceof HTMLOptionElement) {
|
||||
result.choices.push({
|
||||
"group": false,
|
||||
"inGroup": false,
|
||||
"text": child.text,
|
||||
"disabled": child.disabled,
|
||||
"selected": child.selected,
|
||||
"optionIndex": optionIndex++
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
@ -123,11 +123,11 @@ var shell = {
|
||||
addPermissions(domains.split(","));
|
||||
|
||||
// Load webapi.js as a frame script
|
||||
let frameScriptUrl = 'chrome://browser/content/webapi.js';
|
||||
let webapiUrl = 'chrome://browser/content/webapi.js';
|
||||
try {
|
||||
messageManager.loadFrameScript(frameScriptUrl, true);
|
||||
messageManager.loadFrameScript(webapiUrl, true);
|
||||
} catch (e) {
|
||||
dump('Error loading ' + frameScriptUrl + ' as a frame script: ' + e + '\n');
|
||||
dump('Error loading ' + webapiUrl + ' as a frame script: ' + e + '\n');
|
||||
}
|
||||
|
||||
CustomEventManager.init();
|
||||
@ -406,17 +406,20 @@ var CustomEventManager = {
|
||||
|
||||
handleEvent: function custevt_handleEvent(evt) {
|
||||
let detail = evt.detail;
|
||||
dump("XXX FIXME : Got a mozContentEvent: " + detail.type);
|
||||
dump('XXX FIXME : Got a mozContentEvent: ' + detail.type);
|
||||
|
||||
switch(detail.type) {
|
||||
case "desktop-notification-click":
|
||||
case "desktop-notification-close":
|
||||
case 'desktop-notification-click':
|
||||
case 'desktop-notification-close':
|
||||
AlertsHelper.handleEvent(detail);
|
||||
break;
|
||||
case "webapps-install-granted":
|
||||
case "webapps-install-denied":
|
||||
case 'webapps-install-granted':
|
||||
case 'webapps-install-denied':
|
||||
WebappsHelper.handleEvent(detail);
|
||||
break;
|
||||
case 'select-choicechange':
|
||||
FormsHelper.handleEvent(detail);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ chrome.jar:
|
||||
% content browser %content/
|
||||
|
||||
content/dbg-browser-actors.js (content/dbg-browser-actors.js)
|
||||
content/forms.js (content/forms.js)
|
||||
content/settings.js (content/settings.js)
|
||||
* content/shell.xul (content/shell.xul)
|
||||
* content/shell.js (content/shell.js)
|
||||
|
@ -2,14 +2,19 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const messageManager = Cc["@mozilla.org/globalmessagemanager;1"]
|
||||
.getService(Ci.nsIChromeFrameMessageManager);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// MozKeyboard
|
||||
// -----------------------------------------------------------------------
|
||||
@ -18,35 +23,90 @@ function MozKeyboard() { }
|
||||
|
||||
MozKeyboard.prototype = {
|
||||
classID: Components.ID("{397a7fdf-2254-47be-b74e-76625a1a66d5}"),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIB2GKeyboard, Ci.nsIDOMGlobalPropertyInitializer, Ci.nsIObserver]),
|
||||
classInfo: XPCOMUtils.generateCI({classID: Components.ID("{397a7fdf-2254-47be-b74e-76625a1a66d5}"),
|
||||
contractID: "@mozilla.org/b2g-keyboard;1",
|
||||
interfaces: [Ci.nsIB2GKeyboard],
|
||||
flags: Ci.nsIClassInfo.DOM_OBJECT,
|
||||
classDescription: "B2G Virtual Keyboard"}),
|
||||
|
||||
init: function(aWindow) {
|
||||
this._utils = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsIB2GKeyboard, Ci.nsIDOMGlobalPropertyInitializer, Ci.nsIObserver
|
||||
]),
|
||||
|
||||
classInfo: XPCOMUtils.generateCI({
|
||||
"classID": Components.ID("{397a7fdf-2254-47be-b74e-76625a1a66d5}"),
|
||||
"contractID": "@mozilla.org/b2g-keyboard;1",
|
||||
"interfaces": [Ci.nsIB2GKeyboard],
|
||||
"flags": Ci.nsIClassInfo.DOM_OBJECT,
|
||||
"classDescription": "B2G Virtual Keyboard"
|
||||
}),
|
||||
|
||||
init: function mozKeyboardInit(win) {
|
||||
messageManager.loadFrameScript("chrome://browser/content/forms.js", true);
|
||||
messageManager.addMessageListener("Forms:Input", this);
|
||||
|
||||
Services.obs.addObserver(this, "inner-window-destroyed", false);
|
||||
|
||||
this._window = win;
|
||||
this._utils = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
this.innerWindowID = this._utils.currentInnerWindowID;
|
||||
|
||||
this._focusHandler = null;
|
||||
},
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
if (aTopic == "inner-window-destroyed") {
|
||||
let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
|
||||
if (wId == this.innerWindowID) {
|
||||
Services.obs.removeObserver(this, "inner-window-destroyed");
|
||||
this._utils = null;
|
||||
}
|
||||
}
|
||||
uninit: function mozKeyboardUninit() {
|
||||
Services.obs.removeObserver(this, "inner-window-destroyed");
|
||||
messageManager.removeMessageListener("Forms:Input", this);
|
||||
this._window = null;
|
||||
this._utils = null;
|
||||
this._focusHandler = null;
|
||||
},
|
||||
|
||||
sendKey: function mozKeyboardSendKey(keyCode, charCode) {
|
||||
charCode = (charCode == undefined) ? keyCode : charCode;
|
||||
['keydown', 'keypress', 'keyup'].forEach((function sendKey(type) {
|
||||
["keydown", "keypress", "keyup"].forEach((function sendKey(type) {
|
||||
this._utils.sendKeyEvent(type, keyCode, charCode, null);
|
||||
}).bind(this));
|
||||
},
|
||||
|
||||
setSelectedOption: function mozKeyboardSetSelectedOption(index) {
|
||||
messageManager.sendAsyncMessage("Forms:Select:Choice", {
|
||||
"index": index
|
||||
});
|
||||
},
|
||||
|
||||
setSelectedOptions: function mozKeyboardSetSelectedOptions(indexes) {
|
||||
messageManager.sendAsyncMessage("Forms:Select:Choice", {
|
||||
"indexes": indexes || []
|
||||
});
|
||||
},
|
||||
|
||||
set onfocuschange(val) {
|
||||
this._focusHandler = val;
|
||||
},
|
||||
|
||||
get onfocuschange() {
|
||||
return this._focusHandler;
|
||||
},
|
||||
|
||||
receiveMessage: function mozKeyboardReceiveMessage(msg) {
|
||||
let handler = this._focusHandler;
|
||||
if (!handler || !(handler instanceof Ci.nsIDOMEventListener))
|
||||
return;
|
||||
|
||||
let detail = {
|
||||
"detail": msg.json
|
||||
};
|
||||
|
||||
let evt = new this._window.CustomEvent("focuschanged", detail);
|
||||
handler.handleEvent(evt);
|
||||
},
|
||||
|
||||
observe: function mozKeyboardObserve(subject, topic, data) {
|
||||
if (topic == "inner-window-destroyed") {
|
||||
let wId = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
|
||||
if (wId == this.innerWindowID) {
|
||||
this.uninit();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const NSGetFactory = XPCOMUtils.generateNSGetFactory([MozKeyboard]);
|
||||
|
||||
|
@ -7,12 +7,28 @@
|
||||
[scriptable, uuid(3615a616-571d-4194-bf54-ccf546067b14)]
|
||||
interface nsIB2GCameraContent : nsISupports
|
||||
{
|
||||
/* temporary solution, waiting for getUserMedia */
|
||||
DOMString getCameraURI([optional] in jsval options);
|
||||
/* temporary solution, waiting for getUserMedia */
|
||||
DOMString getCameraURI([optional] in jsval options);
|
||||
};
|
||||
|
||||
[scriptable, uuid(80ad05f8-e5f6-4a36-b25d-5d5a969b365d)]
|
||||
[scriptable, uuid(53990d7a-ab2a-11e1-8543-7767e4cbcbff)]
|
||||
interface nsIB2GKeyboard : nsISupports
|
||||
{
|
||||
void sendKey(in long aKeyCode, in long aCharCode);
|
||||
void sendKey(in long keyCode, in long charCode);
|
||||
|
||||
// Select the <select> option specified by index.
|
||||
// If this method is called on a <select> that support multiple
|
||||
// selection, then the option specified by index will be added to
|
||||
// the selection.
|
||||
// If this method is called for a select that does not support multiple
|
||||
// selection the previous element will be unselected.
|
||||
void setSelectedOption(in jsval index);
|
||||
|
||||
// Select the <select> options specified by indexes. All other options
|
||||
// will be deselected.
|
||||
// If this method is called for a <select> that does not support multiple
|
||||
// selection, then the last index specified in indexes will be selected.
|
||||
void setSelectedOptions(in jsval indexes);
|
||||
|
||||
attribute nsIDOMEventListener onfocuschange;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user