mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-30 05:35:31 +00:00
277 lines
9.9 KiB
JavaScript
277 lines
9.9 KiB
JavaScript
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
|
/* Any copyright is dedicated to the Public Domain.
|
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
"use strict";
|
|
|
|
// A helper frame-script for brower/devtools/inspector tests.
|
|
//
|
|
// Most listeners in the script expect "Test:"-namespaced messages from chrome,
|
|
// then execute code upon receiving, and immediately send back a message.
|
|
// This is so that chrome test code can execute code in content and wait for a
|
|
// response.
|
|
// Some listeners do not send a response message back.
|
|
|
|
let {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
|
let {LayoutHelpers} = Cu.import("resource://gre/modules/devtools/LayoutHelpers.jsm", {});
|
|
let DOMUtils = Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
|
|
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
|
|
.getService(Ci.mozIJSSubScriptLoader);
|
|
let EventUtils = {};
|
|
loader.loadSubScript("chrome://marionette/content/EventUtils.js", EventUtils);
|
|
|
|
/**
|
|
* If the test page creates and triggeres the custom event
|
|
* "test-page-processing-done", then the Test:TestPageProcessingDone message
|
|
* will be sent to the parent process for tests to wait for this event if needed.
|
|
*/
|
|
addEventListener("DOMWindowCreated", () => {
|
|
content.addEventListener("test-page-processing-done", () => {
|
|
sendAsyncMessage("Test:TestPageProcessingDone");
|
|
}, false);
|
|
});
|
|
|
|
/**
|
|
* Given an actorID and connection prefix, get the corresponding actor from the
|
|
* debugger-server connection.
|
|
* @param {String} actorID
|
|
* @param {String} connPrefix
|
|
*/
|
|
function getHighlighterActor(actorID, connPrefix) {
|
|
let {DebuggerServer} = Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
|
|
if (!DebuggerServer.initialized) {
|
|
return;
|
|
}
|
|
|
|
let conn = DebuggerServer._connections[connPrefix];
|
|
if (!conn) {
|
|
return;
|
|
}
|
|
|
|
return conn.getActor(actorID);
|
|
}
|
|
|
|
/**
|
|
* Get the instance of CanvasFrameAnonymousContentHelper used by a given
|
|
* highlighter actor.
|
|
* The instance provides methods to get/set attributes/text/style on nodes of
|
|
* the highlighter, inserted into the nsCanvasFrame.
|
|
* @see /toolkit/devtools/server/actors/highlighter.js
|
|
* @param {String} actorID
|
|
* @param {String} connPrefix
|
|
*/
|
|
function getHighlighterCanvasFrameHelper(actorID, connPrefix) {
|
|
let actor = getHighlighterActor(actorID, connPrefix);
|
|
if (actor && actor._highlighter) {
|
|
return actor._highlighter.markup;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a value for a given attribute name, on one of the elements of the box
|
|
* model highlighter, given its ID.
|
|
* @param {Object} msg The msg.data part expects the following properties
|
|
* - {String} nodeID The full ID of the element to get the attribute for
|
|
* - {String} name The name of the attribute to get
|
|
* - {String} actorID The highlighter actor ID
|
|
* - {String} connPrefix The highlighter actor ID's connection prefix
|
|
* @return {String} The value, if found, null otherwise
|
|
*/
|
|
addMessageListener("Test:GetHighlighterAttribute", function(msg) {
|
|
let {nodeID, name, actorID, connPrefix} = msg.data;
|
|
|
|
let value;
|
|
let helper = getHighlighterCanvasFrameHelper(actorID, connPrefix);
|
|
if (helper) {
|
|
value = helper.getAttributeForElement(nodeID, name);
|
|
}
|
|
|
|
sendAsyncMessage("Test:GetHighlighterAttribute", value);
|
|
});
|
|
|
|
/**
|
|
* Get the textcontent of one of the elements of the box model highlighter,
|
|
* given its ID.
|
|
* @param {Object} msg The msg.data part expects the following properties
|
|
* - {String} nodeID The full ID of the element to get the attribute for
|
|
* - {String} actorID The highlighter actor ID
|
|
* - {String} connPrefix The highlighter connection prefix
|
|
* @return {String} The textcontent value
|
|
*/
|
|
addMessageListener("Test:GetHighlighterTextContent", function(msg) {
|
|
let {nodeID, actorID, connPrefix} = msg.data;
|
|
|
|
let value;
|
|
let helper = getHighlighterCanvasFrameHelper(actorID, connPrefix);
|
|
if (helper) {
|
|
value = helper.getTextContentForElement(nodeID);
|
|
}
|
|
|
|
sendAsyncMessage("Test:GetHighlighterTextContent", value);
|
|
});
|
|
|
|
/**
|
|
* Get the number of box-model highlighters created by the SelectorHighlighter
|
|
* @param {Object} msg The msg.data part expects the following properties:
|
|
* - {String} actorID The highlighter actor ID
|
|
* - {String} connPrefix The highlighter connection prefix
|
|
* @return {Number} The number of box-model highlighters created, or null if the
|
|
* SelectorHighlighter was not found.
|
|
*/
|
|
addMessageListener("Test:GetSelectorHighlighterBoxNb", function(msg) {
|
|
let {actorID, connPrefix} = msg.data;
|
|
let {_highlighter: h} = getHighlighterActor(actorID, connPrefix);
|
|
if (!h || !h._highlighters) {
|
|
sendAsyncMessage("Test:GetSelectorHighlighterBoxNb", null);
|
|
} else {
|
|
sendAsyncMessage("Test:GetSelectorHighlighterBoxNb", h._highlighters.length);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Subscribe to the box-model highlighter's update event, modify an attribute of
|
|
* the currently highlighted node and send a message when the highlighter has
|
|
* updated.
|
|
* @param {Object} msg The msg.data part expects the following properties
|
|
* - {String} the name of the attribute to be changed
|
|
* - {String} the new value for the attribute
|
|
* - {String} actorID The highlighter actor ID
|
|
* - {String} connPrefix The highlighter connection prefix
|
|
*/
|
|
addMessageListener("Test:ChangeHighlightedNodeWaitForUpdate", function(msg) {
|
|
// The name and value of the attribute to be changed
|
|
let {name, value, actorID, connPrefix} = msg.data;
|
|
let {_highlighter: h} = getHighlighterActor(actorID, connPrefix);
|
|
|
|
h.once("updated", () => {
|
|
sendAsyncMessage("Test:ChangeHighlightedNodeWaitForUpdate");
|
|
});
|
|
|
|
h.currentNode.setAttribute(name, value);
|
|
});
|
|
|
|
/**
|
|
* Subscribe to a given highlighter event and respond when the event is received.
|
|
* @param {Object} msg The msg.data part expects the following properties
|
|
* - {String} event The name of the highlighter event to listen to
|
|
* - {String} actorID The highlighter actor ID
|
|
* - {String} connPrefix The highlighter connection prefix
|
|
*/
|
|
addMessageListener("Test:WaitForHighlighterEvent", function(msg) {
|
|
let {event, actorID, connPrefix} = msg.data;
|
|
let {_highlighter: h} = getHighlighterActor(actorID, connPrefix);
|
|
|
|
h.once(event, () => {
|
|
sendAsyncMessage("Test:WaitForHighlighterEvent");
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Change the zoom level of the page.
|
|
* Optionally subscribe to the box-model highlighter's update event and waiting
|
|
* for it to refresh before responding.
|
|
* @param {Object} msg The msg.data part expects the following properties
|
|
* - {Number} level The new zoom level
|
|
* - {String} actorID Optional. The highlighter actor ID
|
|
* - {String} connPrefix Optional. The highlighter connection prefix
|
|
*/
|
|
addMessageListener("Test:ChangeZoomLevel", function(msg) {
|
|
let {level, actorID, connPrefix} = msg.data;
|
|
dumpn("Zooming page to " + level);
|
|
|
|
if (actorID) {
|
|
let {_highlighter: h} = getHighlighterActor(actorID, connPrefix);
|
|
h.once("updated", () => {
|
|
sendAsyncMessage("Test:ChangeZoomLevel");
|
|
});
|
|
}
|
|
|
|
let docShell = content.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
.getInterface(Ci.nsIWebNavigation)
|
|
.QueryInterface(Ci.nsIDocShell);
|
|
docShell.contentViewer.fullZoom = level;
|
|
|
|
if (!actorID) {
|
|
sendAsyncMessage("Test:ChangeZoomLevel");
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Get the element at the given x/y coordinates.
|
|
* @param {Object} msg The msg.data part expects the following properties
|
|
* - {Number} x
|
|
* - {Number} y
|
|
* @return {DOMNode} The CPOW of the element
|
|
*/
|
|
addMessageListener("Test:ElementFromPoint", function(msg) {
|
|
let {x, y} = msg.data;
|
|
dumpn("Getting the element at " + x + "/" + y);
|
|
|
|
let helper = new LayoutHelpers(content);
|
|
let element = helper.getElementFromPoint(content.document, x, y);
|
|
sendAsyncMessage("Test:ElementFromPoint", null, {element});
|
|
});
|
|
|
|
/**
|
|
* Get all box-model regions' adjusted boxquads for the given element
|
|
* @param {Object} msg The msg.objects part should be the element
|
|
* @return {Object} An object with each property being a box-model region, each
|
|
* of them being an object with the p1/p2/p3/p4 properties
|
|
*/
|
|
addMessageListener("Test:GetAllAdjustedQuads", function(msg) {
|
|
let {node} = msg.objects;
|
|
let regions = {};
|
|
|
|
let helper = new LayoutHelpers(content);
|
|
for (let boxType of ["content", "padding", "border", "margin"]) {
|
|
regions[boxType] = helper.getAdjustedQuads(node, boxType);
|
|
}
|
|
|
|
sendAsyncMessage("Test:GetAllAdjustedQuads", regions);
|
|
});
|
|
|
|
/**
|
|
* Synthesize a mouse event on an element. This handler doesn't send a message
|
|
* back. Consumers should listen to specific events on the inspector/highlighter
|
|
* to know when the event got synthesized.
|
|
* @param {Object} msg The msg.data part expects the following properties:
|
|
* - {Number} x
|
|
* - {Number} y
|
|
* - {Boolean} center If set to true, x/y will be ignored and
|
|
* synthesizeMouseAtCenter will be used instead
|
|
* - {Object} options Other event options
|
|
* The msg.objects part should be the element.
|
|
* @param {Object} data Event detail properties:
|
|
*/
|
|
addMessageListener("Test:SynthesizeMouse", function(msg) {
|
|
let {node} = msg.objects;
|
|
let {x, y, center, options} = msg.data;
|
|
|
|
if (center) {
|
|
EventUtils.synthesizeMouseAtCenter(node, options, node.ownerDocument.defaultView);
|
|
} else {
|
|
EventUtils.synthesizeMouse(node, x, y, options, node.ownerDocument.defaultView);
|
|
}
|
|
|
|
// Most consumers won't need to listen to this message, unless they want to
|
|
// wait for the mouse event to be synthesized and don't have another event
|
|
// to listen to instead.
|
|
sendAsyncMessage("Test:SynthesizeMouse");
|
|
});
|
|
|
|
/**
|
|
* Check that an element currently has a pseudo-class lock.
|
|
* @param {Object} msg The msg.data part expects the following properties:
|
|
* - {String} pseudo The pseudoclass to check for
|
|
* The msg.objects part should be the element.
|
|
* @param {Object}
|
|
* @return {Boolean}
|
|
*/
|
|
addMessageListener("Test:HasPseudoClassLock", function(msg) {
|
|
let {node} = msg.objects;
|
|
let {pseudo} = msg.data
|
|
sendAsyncMessage("Test:HasPseudoClassLock", DOMUtils.hasPseudoClassLock(node, pseudo));
|
|
});
|
|
|
|
let dumpn = msg => dump(msg + "\n");
|