Bug 1155493 - Part 2: Event hook for mozbrowser element. r=kanru

This commit is contained in:
Morris Tseng 2015-05-28 01:57:00 -04:00
Родитель 974788b953
Коммит fc201e0ae1
6 изменённых файлов: 163 добавлений и 5 удалений

Просмотреть файл

@ -350,6 +350,7 @@ var shell = {
this.contentBrowser.addEventListener('mozbrowserloadstart', this, true);
this.contentBrowser.addEventListener('mozbrowserselectionstatechanged', this, true);
this.contentBrowser.addEventListener('mozbrowserscrollviewchange', this, true);
this.contentBrowser.addEventListener('mozbrowsercaretstatechanged', this);
CustomEventManager.init();
WebappsHelper.init();
@ -380,6 +381,7 @@ var shell = {
this.contentBrowser.removeEventListener('mozbrowserloadstart', this, true);
this.contentBrowser.removeEventListener('mozbrowserselectionstatechanged', this, true);
this.contentBrowser.removeEventListener('mozbrowserscrollviewchange', this, true);
this.contentBrowser.removeEventListener('mozbrowsercaretstatechanged', this);
ppmm.removeMessageListener("content-handler", this);
UserAgentOverrides.uninit();
@ -490,6 +492,28 @@ var shell = {
detail: data,
});
break;
case 'mozbrowsercaretstatechanged':
{
let elt = evt.target;
let win = elt.ownerDocument.defaultView;
let offsetX = win.mozInnerScreenX - window.mozInnerScreenX;
let offsetY = win.mozInnerScreenY - window.mozInnerScreenY;
let rect = elt.getBoundingClientRect();
offsetX += rect.left;
offsetY += rect.top;
let data = evt.detail;
data.offsetX = offsetX;
data.offsetY = offsetY;
data.sendDoCommandMsg = null;
shell.sendChromeEvent({
type: 'caretstatechanged',
detail: data,
});
}
break;
case 'MozApplicationManifest':
try {
@ -718,6 +742,10 @@ var CustomEventManager = {
case 'do-command':
DoCommandHelper.handleEvent(detail.cmd);
break;
case 'copypaste-do-command':
Services.obs.notifyObservers({ wrappedJSObject: shell.contentBrowser },
'ask-children-to-execute-copypaste-command', detail.cmd);
break;
}
}
}

Просмотреть файл

@ -34,12 +34,15 @@ function isTopBrowserElement(docShell) {
}
if (!('BrowserElementIsPreloaded' in this)) {
if (isTopBrowserElement(docShell) &&
Services.prefs.getBoolPref("dom.mozInputMethod.enabled")) {
try {
Services.scriptloader.loadSubScript("chrome://global/content/forms.js");
} catch (e) {
if (isTopBrowserElement(docShell)) {
if (Services.prefs.getBoolPref("dom.mozInputMethod.enabled")) {
try {
Services.scriptloader.loadSubScript("chrome://global/content/forms.js");
} catch (e) {
}
}
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementCopyPaste.js");
}
if (Services.prefs.getIntPref("dom.w3c_touch_events.enabled") == 1) {

Просмотреть файл

@ -0,0 +1,90 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 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/. */
"use strict";
dump("###################################### BrowserElementCopyPaste.js loaded\n");
let CopyPasteAssistent = {
COMMAND_MAP: {
'cut': 'cmd_cut',
'copy': 'cmd_copyAndCollapseToEnd',
'paste': 'cmd_paste',
'selectall': 'cmd_selectAll'
},
init: function() {
addEventListener('mozcaretstatechanged',
this._caretStateChangedHandler.bind(this),
/* useCapture = */ true,
/* wantsUntrusted = */ false);
addMessageListener('browser-element-api:call', this._browserAPIHandler.bind(this));
},
_browserAPIHandler: function(e) {
switch (e.data.msg_name) {
case 'copypaste-do-command':
if (this._isCommandEnabled(e.data.command)) {
docShell.doCommand(COMMAND_MAP[e.data.command]);
}
break;
}
},
_isCommandEnabled: function(cmd) {
let command = this.COMMAND_MAP[cmd];
if (!command) {
return false;
}
return docShell.isCommandEnabled(command);
},
_caretStateChangedHandler: function(e) {
e.stopPropagation();
let boundingClientRect = e.boundingClientRect;
let canPaste = this._isCommandEnabled("paste");
let zoomFactor = content.innerWidth == 0 ? 1 : content.screen.width / content.innerWidth;
let detail = {
rect: {
width: boundingClientRect ? boundingClientRect.width : 0,
height: boundingClientRect ? boundingClientRect.height : 0,
top: boundingClientRect ? boundingClientRect.top : 0,
bottom: boundingClientRect ? boundingClientRect.bottom : 0,
left: boundingClientRect ? boundingClientRect.left : 0,
right: boundingClientRect ? boundingClientRect.right : 0,
},
commands: {
canSelectAll: this._isCommandEnabled("selectall"),
canCut: this._isCommandEnabled("cut"),
canCopy: this._isCommandEnabled("copy"),
canPaste: this._isCommandEnabled("paste"),
},
zoomFactor: zoomFactor,
reason: e.reason,
collapsed: e.collapsed,
caretVisible: e.caretVisible,
selectionVisible: e.selectionVisible
};
// Get correct geometry information if we have nested iframe.
let currentWindow = e.target.defaultView;
while (currentWindow.realFrameElement) {
let currentRect = currentWindow.realFrameElement.getBoundingClientRect();
detail.rect.top += currentRect.top;
detail.rect.bottom += currentRect.top;
detail.rect.left += currentRect.left;
detail.rect.right += currentRect.left;
currentWindow = currentWindow.realFrameElement.ownerDocument.defaultView;
}
sendAsyncMsg('caretstatechanged', detail);
},
};
CopyPasteAssistent.init();

Просмотреть файл

@ -87,6 +87,7 @@ function BrowserElementParent() {
Services.obs.addObserver(this, 'oop-frameloader-crashed', /* ownsWeak = */ true);
Services.obs.addObserver(this, 'copypaste-docommand', /* ownsWeak = */ true);
Services.obs.addObserver(this, 'ask-children-to-execute-copypaste-command', /* ownsWeak = */ true);
}
BrowserElementParent.prototype = {
@ -203,6 +204,7 @@ BrowserElementParent.prototype = {
"got-set-input-method-active": this._gotDOMRequestResult,
"selectionstatechanged": this._handleSelectionStateChanged,
"scrollviewchange": this._handleScrollViewChange,
"caretstatechanged": this._handleCaretStateChanged,
};
let mmSecuritySensitiveCalls = {
@ -438,6 +440,34 @@ BrowserElementParent.prototype = {
this._frameElement.dispatchEvent(evt);
},
// Called when state of accessible caret in child has changed.
// The fields of data is as following:
// - rect: Contains bounding rectangle of selection, Include width, height,
// top, bottom, left and right.
// - commands: Describe what commands can be executed in child. Include canSelectAll,
// canCut, canCopy and canPaste. For example: if we want to check if cut
// command is available, using following code, if (data.commands.canCut) {}.
// - zoomFactor: Current zoom factor in child frame.
// - reason: The reason causes the state changed. Include "visibilitychange",
// "updateposition", "longpressonemptycontent", "taponcaret", "presscaret",
// "releasecaret".
// - collapsed: Indicate current selection is collapsed or not.
// - caretVisible: Indicate the caret visiibility.
// - selectionVisible: Indicate current selection is visible or not.
_handleCaretStateChanged: function(data) {
let evt = this._createEvent('caretstatechanged', data.json,
/* cancelable = */ false);
let self = this;
function sendDoCommandMsg(cmd) {
let data = { command: cmd };
self._sendAsyncMsg('copypaste-do-command', data);
}
Cu.exportFunction(sendDoCommandMsg, evt.detail, { defineAs: 'sendDoCommandMsg' });
this._frameElement.dispatchEvent(evt);
},
_handleScrollViewChange: function(data) {
let evt = this._createEvent("scrollviewchange", data.json,
/* cancelable = */ false);
@ -979,6 +1009,11 @@ BrowserElementParent.prototype = {
this._sendAsyncMsg('do-command', { command: data });
}
break;
case 'ask-children-to-execute-copypaste-command':
if (this._isAlive() && this._frameElement == subject.wrappedJSObject) {
this._sendAsyncMsg('copypaste-do-command', { command: data });
}
break;
default:
debug('Unknown topic: ' + topic);
break;

Просмотреть файл

@ -7,6 +7,7 @@ toolkit.jar:
content/global/remote-test-ipc.js (remote-test.js)
content/global/BrowserElementChild.js (../browser-element/BrowserElementChild.js)
content/global/BrowserElementChildPreload.js (../browser-element/BrowserElementChildPreload.js)
content/global/BrowserElementCopyPaste.js (../browser-element/BrowserElementCopyPaste.js)
content/global/BrowserElementPanning.js (../browser-element/BrowserElementPanning.js)
* content/global/BrowserElementPanningAPZDisabled.js (../browser-element/BrowserElementPanningAPZDisabled.js)
content/global/manifestMessages.js (manifestMessages.js)

Просмотреть файл

@ -103,6 +103,7 @@ const BrowserElementIsPreloaded = true;
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementPanning.js", global);
}
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementCopyPaste.js", global);
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementChildPreload.js", global);
Services.io.getProtocolHandler("app");