Bug 683954 - [Layout] Implement an abstract view of the layout of the selected node. r=dcamp, r=jwalker

This commit is contained in:
Paul Rouget 2012-03-12 14:39:56 +01:00
parent 88b854e8ff
commit 624cd1f396
25 changed files with 1215 additions and 1 deletions

View File

@ -1049,6 +1049,10 @@ pref("devtools.inspector.htmlPanelOpen", false);
pref("devtools.inspector.sidebarOpen", false);
pref("devtools.inspector.activeSidebar", "ruleview");
// Enable the Layout View
pref("devtools.layoutview.enabled", false);
pref("devtools.layoutview.open", false);
// Enable the Debugger
pref("devtools.debugger.enabled", false);

View File

@ -100,3 +100,15 @@ html|*#highlighter-nodeinfobar-tagname {
.devtools-toolbarbutton:not([label]) > .toolbarbutton-text {
display: none;
}
#inspector-layoutview-container > iframe {
-moz-transition-property: height;
-moz-transition-duration: 0.1s;
/* header size */
height: 22px;
}
#inspector-layoutview-container > iframe[open] {
/* header size + layout view size: 22px + 155px */
height: 177px;
}

View File

@ -55,6 +55,7 @@ DIRS = \
tilt \
scratchpad \
debugger \
layoutview \
shared \
$(NULL)

View File

@ -56,6 +56,7 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource:///modules/TreePanel.jsm");
Cu.import("resource:///modules/highlighter.jsm");
Cu.import("resource:///modules/devtools/LayoutView.jsm");
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
// Inspector notifications dispatched through the nsIObserverService.
@ -1405,6 +1406,12 @@ InspectorStyleSidebar.prototype = {
destroy: function ISS_destroy()
{
// close the Layout View
if (this._layoutview) {
this._layoutview.destroy();
this._layoutview = null;
}
for each (let toolID in Object.getOwnPropertyNames(this._tools)) {
this.removeTool(toolID);
}
@ -1514,10 +1521,19 @@ InspectorStyleSidebar.prototype = {
this._inspector._sidebarOpen = true;
Services.prefs.setBoolPref("devtools.inspector.sidebarOpen", true);
// Instantiate the Layout View if needed.
if (Services.prefs.getBoolPref("devtools.layoutview.enabled")
&& !this._layoutview) {
this._layoutview = new LayoutView({
document: this._chromeDoc,
inspector: this._inspector,
});
}
},
/**
* Hides the sidebar, updating the stored visiblity pref.
* Hides the sidebar, updating the stored visibility pref.
*/
hide: function ISS_hide()
{

View File

@ -9,6 +9,8 @@ browser.jar:
content/browser/devtools/csshtmltree.xul (styleinspector/csshtmltree.xul)
content/browser/devtools/cssruleview.xul (styleinspector/cssruleview.xul)
content/browser/devtools/styleinspector.css (styleinspector/styleinspector.css)
* content/browser/devtools/layoutview/view.xhtml (layoutview/view.xhtml)
content/browser/devtools/layoutview/view.css (layoutview/view.css)
content/browser/orion.js (sourceeditor/orion/orion.js)
* content/browser/source-editor-overlay.xul (sourceeditor/source-editor-overlay.xul)
* content/browser/debugger.xul (debugger/debugger.xul)

View File

@ -0,0 +1,317 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Mozilla Layout Module.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2012
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Paul Rouget <paul@mozilla.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
"use strict";
const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/inspector.jsm");
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
var EXPORTED_SYMBOLS = ["LayoutView"];
function LayoutView(aOptions)
{
this.chromeDoc = aOptions.document;
this.inspector = aOptions.inspector;
this.browser = this.inspector.chromeWindow.gBrowser;
this.init();
}
LayoutView.prototype = {
init: function LV_init() {
this.update = this.update.bind(this);
this.onMessage = this.onMessage.bind(this);
this.isOpen = false;
this.documentReady = false;
// Is the layout view was open before?
if (!("_layoutViewIsOpen" in this.inspector)) {
this.inspector._layoutViewIsOpen =
Services.prefs.getBoolPref("devtools.layoutview.open");
}
// We update the values when:
// a node is locked
// we get the MozAfterPaint event and the node is locked
function onLock() {
this.undim();
this.update();
// We make sure we never add 2 listeners.
if (!this.trackingPaint) {
this.browser.addEventListener("MozAfterPaint", this.update, true);
this.trackingPaint = true;
}
}
function onUnlock() {
this.browser.removeEventListener("MozAfterPaint", this.update, true);
this.trackingPaint = false;
this.dim();
}
this.onLock = onLock.bind(this);
this.onUnlock = onUnlock.bind(this);
this.inspector.on("locked", this.onLock);
this.inspector.on("unlocked", this.onUnlock);
// Build the layout view in the sidebar.
this.buildView();
// Get messages from the iframe.
this.inspector.chromeWindow.addEventListener("message", this.onMessage, true);
// Store for the different dimensions of the node.
// 'selector' refers to the element that holds the value in view.xhtml;
// 'property' is what we are measuring;
// 'value' is the computed dimension, computed in update().
this.map = {
marginTop: {selector: ".margin.top > span",
property: "margin-top",
value: undefined},
marginBottom: {selector: ".margin.bottom > span",
property: "margin-bottom",
value: undefined},
marginLeft: {selector: ".margin.left > span",
property: "margin-left",
value: undefined},
marginRight: {selector: ".margin.right > span",
property: "margin-right",
value: undefined},
paddingTop: {selector: ".padding.top > span",
property: "padding-top",
value: undefined},
paddingBottom: {selector: ".padding.bottom > span",
property: "padding-bottom",
value: undefined},
paddingLeft: {selector: ".padding.left > span",
property: "padding-left",
value: undefined},
paddingRight: {selector: ".padding.right > span",
property: "padding-right",
value: undefined},
borderTop: {selector: ".border.top > span",
property: "border-top-width",
value: undefined},
borderBottom: {selector: ".border.bottom > span",
property: "border-bottom-width",
value: undefined},
borderLeft: {selector: ".border.left > span",
property: "border-left-width",
value: undefined},
borderRight: {selector: ".border.right > span",
property: "border-right-width",
value: undefined},
};
},
/**
* Destroy the nodes. Remove listeners.
*/
destroy: function LV_destroy() {
this.inspector.removeListener("locked", this.onLock);
this.inspector.removeListener("unlocked", this.onUnlock);
this.browser.removeEventListener("MozAfterPaint", this.update, true);
this.inspector.chromeWindow.removeEventListener("message", this.onMessage, true);
this.close();
this.iframe = null;
this.view.parentNode.removeChild(this.view);
},
/**
* Build the Layout container:
*
* <vbox id="inspector-layoutview-container">
* <iframe src="chrome://browser/content/devtools/layoutview/view.xhtml"/>
* </vbox>
*/
buildView: function LV_buildPanel() {
this.iframe = this.chromeDoc.createElement("iframe");
this.iframe.setAttribute("src", "chrome://browser/content/devtools/layoutview/view.xhtml");
this.view = this.chromeDoc.createElement("vbox");
this.view.id = "inspector-layoutview-container";
this.view.appendChild(this.iframe);
let sidebar = this.chromeDoc.getElementById("devtools-sidebar-box");
sidebar.appendChild(this.view);
},
/**
* Called when the iframe is loaded.
*/
onDocumentReady: function LV_onDocumentReady() {
this.documentReady = true;
this.doc = this.iframe.contentDocument;
// We can't do that earlier because open() and close() need to do stuff
// inside the iframe.
if (this.inspector.locked)
this.onLock();
else
this.onUnlock();
if (this.inspector._layoutViewIsOpen) {
this.open();
} else {
this.close();
}
},
/**
* This is where we get messages from the layout view iframe.
*/
onMessage: function LV_onMessage(e) {
switch (e.data) {
case "layoutview-toggle-view":
this.toggle(true);
break;
case "layoutview-ready":
this.onDocumentReady();
break;
default:
break;
}
},
/**
* Open the view container.
*
* @param aUserAction Is the action triggered by the user (click on the
* open/close button in the view)
*/
open: function LV_open(aUserAction) {
this.isOpen = true;
if (this.documentReady)
this.doc.body.classList.add("open");
if (aUserAction) {
this.inspector._layoutViewIsOpen = true;
Services.prefs.setBoolPref("devtools.layoutview.open", true);
}
this.iframe.setAttribute("open", "true");
this.update();
},
/**
* Close the view container.
*
* @param aUserAction Is the action triggered by the user (click on the
* open/close button in the view)
*/
close: function LV_close(aUserAction) {
this.isOpen = false;
if (this.documentReady)
this.doc.body.classList.remove("open");
if (aUserAction) {
this.inspector._layoutViewIsOpen = false;
Services.prefs.setBoolPref("devtools.layoutview.open", false);
}
this.iframe.removeAttribute("open");
},
/**
* Toggle view container state (open/close).
*
* @param aUserAction Is the action triggered by the user (click on the
* open/close button in the view)
*/
toggle: function LV_toggle(aUserAction) {
this.isOpen ? this.close(aUserAction):this.open(aUserAction);
},
/**
* Hide the layout boxes. No node are selected.
*/
dim: function LV_dim() {
if (!this.documentReady) return;
this.doc.body.classList.add("dim");
},
/**
* Show the layout boxes. A node is selected.
*/
undim: function LV_dim() {
if (!this.documentReady) return;
this.doc.body.classList.remove("dim");
},
/**
* Compute the dimensions of the node and update the values in
* the layoutview/view.xhtml document.
*/
update: function LV_update() {
let node = this.inspector.selection;
if (!node || !this.documentReady) return;
// First, we update the first part of the layout view, with
// the size of the element.
let clientRect = node.getBoundingClientRect();
let width = Math.round(clientRect.width);
let height = Math.round(clientRect.height);
this.doc.querySelector("#element-size").textContent = width + "x" + height;
// If the view is closed, no need to do anything more.
if (!this.isOpen) return;
// We compute and update the values of margins & co.
let style = this.browser.contentWindow.getComputedStyle(node);;
for (let i in this.map) {
let selector = this.map[i].selector;
let property = this.map[i].property;
this.map[i].value = parseInt(style.getPropertyValue(property));
let span = this.doc.querySelector(selector);
span.textContent = this.map[i].value;
}
width -= this.map.borderLeft.value + this.map.borderRight.value +
this.map.paddingLeft.value + this.map.paddingRight.value;
height -= this.map.borderTop.value + this.map.borderBottom.value +
this.map.paddingTop.value + this.map.paddingBottom.value;
this.doc.querySelector(".size > span").textContent = width + "x" + height;
},
}

View File

@ -0,0 +1,53 @@
#
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (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.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is LayoutView Build Code.
#
# The Initial Developer of the Original Code is The Mozilla Foundation.
#
# Portions created by the Initial Developer are Copyright (C) 2012
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Paul Rouget <paul@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
ifdef ENABLE_TESTS
DIRS += test
endif
include $(topsrcdir)/config/rules.mk
libs::
$(NSINSTALL) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools

View File

@ -0,0 +1,53 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (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.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is
# Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2012
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Paul Rouget <paul@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either of the GNU General Public License Version 2 or later (the "GPL"),
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = browser/devtools/layoutview/test
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_BROWSER_FILES = \
browser_layoutview.js \
$(NULL)
libs:: $(_BROWSER_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)

View File

@ -0,0 +1,134 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
Services.prefs.setBoolPref("devtools.layoutview.enabled", true);
Services.prefs.setBoolPref("devtools.inspector.sidebarOpen", true);
let doc;
let node;
let view;
// Expected values:
let res1 = [
{selector: "#element-size", value: "160x160"},
{selector: ".size > span", value: "100x100"},
{selector: ".margin.top > span", value: 30},
{selector: ".margin.left > span", value: 30},
{selector: ".margin.bottom > span", value: 30},
{selector: ".margin.right > span", value: 30},
{selector: ".padding.top > span", value: 20},
{selector: ".padding.left > span", value: 20},
{selector: ".padding.bottom > span", value: 20},
{selector: ".padding.right > span", value: 20},
{selector: ".border.top > span", value: 10},
{selector: ".border.left > span", value: 10},
{selector: ".border.bottom > span", value: 10},
{selector: ".border.right > span", value: 10},
];
let res2 = [
{selector: "#element-size", value: "160x210"},
{selector: ".size > span", value: "100x150"},
{selector: ".margin.top > span", value: 30},
{selector: ".margin.left > span", value: 30},
{selector: ".margin.bottom > span", value: 30},
{selector: ".margin.right > span", value: 50},
{selector: ".padding.top > span", value: 20},
{selector: ".padding.left > span", value: 20},
{selector: ".padding.bottom > span", value: 20},
{selector: ".padding.right > span", value: 20},
{selector: ".border.top > span", value: 10},
{selector: ".border.left > span", value: 10},
{selector: ".border.bottom > span", value: 10},
{selector: ".border.right > span", value: 10},
];
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onload() {
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
doc = content.document;
waitForFocus(setupTest, content);
}, true);
let style = "div { position: absolute; top: 42px; left: 42px; height: 100px; width: 100px; border: 10px solid black; padding: 20px; margin: 30px; }";
let html = "<style>" + style + "</style><div></div>"
content.location = "data:text/html," + encodeURIComponent(html);
function setupTest() {
node = doc.querySelector("div");
ok(node, "node found");
Services.obs.addObserver(openLayoutView,
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.toggleInspectorUI();
}
function openLayoutView() {
Services.obs.removeObserver(openLayoutView,
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
info("Inspector open");
let highlighter = InspectorUI.highlighter;
highlighter.highlight(node);
highlighter.lock();
window.addEventListener("message", viewReady, true);
}
function viewReady(e) {
if (e.data != "layoutview-ready") return;
info("Layout view ready");
view = InspectorUI._sidebar._layoutview;
ok(!!view, "LayoutView document is alive.");
view.open();
ok(view.iframe.getAttribute("open"), "true", "View is open.");
test1();
}
function test1() {
let viewdoc = view.iframe.contentDocument;
for (let i = 0; i < res1.length; i++) {
let elt = viewdoc.querySelector(res1[i].selector);
is(elt.textContent, res1[i].value, res1[i].selector + " has the right value.");
}
InspectorUI.selection.style.height = "150px";
InspectorUI.selection.style.marginRight = "50px";
setTimeout(test2, 200); // Should be enough to get a MozAfterPaint event
}
function test2() {
let viewdoc = view.iframe.contentDocument;
for (let i = 0; i < res2.length; i++) {
let elt = viewdoc.querySelector(res2[i].selector);
is(elt.textContent, res2[i].value, res2[i].selector + " has the right value after style update.");
}
executeSoon(function() {
Services.obs.addObserver(finishUp,
InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
InspectorUI.closeInspectorUI();
});
}
function finishUp() {
Services.prefs.clearUserPref("devtools.layoutview.enabled");
Services.prefs.clearUserPref("devtools.inspector.sidebarOpen");
Services.obs.removeObserver(finishUp, InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED);
gBrowser.removeCurrentTab();
finish();
}
}

View File

@ -0,0 +1,176 @@
body, html {
height: 100%;
width: 100%;
overflow: hidden;
}
body {
margin: 0;
padding: 0;
}
#header {
-moz-box-sizing: border-box;
font: 12px/14px monospace;
width: 100%;
padding: 3px 4px;
display: -moz-box;
}
body[dir=rtl] > #header {
-moz-box-direction: reverse;
}
#header > span {
display: -moz-box;
}
#element-size {
-moz-box-flex: 1;
}
body[dir=rtl] > #header > #element-size {
-moz-box-pack: end;
}
#header:focus {
outline: none;
}
#main {
margin: 10px;
-moz-box-sizing: border-box;
width: -moz-calc(100% - 2 * 10px);
position: absolute;
border-width: 1px;
font: 10px/12px monospace;
}
#margins {
padding: 28px;
}
#content {
height: 20px;
border-width: 1px;
}
#padding {
border-width: 25px;
}
#borders {
border-width: 2px;
box-shadow: 0 0 16px black;
}
#main > p {
position: absolute;
pointer-events: none;
}
#main > p {
margin: 0;
text-align: center;
}
#main > p > span {
vertical-align: middle;
pointer-events: auto;
cursor: default;
}
.border.top {
left: 0; top: 23px;
width: 98px;
}
.border.bottom {
right: 0; bottom: 22px;
width: 98px;
top: auto;
}
.border.left {
top: 42px; left: 0;
width: 56px;
}
.border.right{
bottom: 42px; right: 0;
width: 56px;
top: auto;
}
.top, .bottom {
width: -moz-calc(100% - 2px);
text-align: center;
}
.margin.top {
top: 8px;
}
.margin.bottom {
bottom: 6px;
}
.padding.top {
top: 35px;
}
.padding.bottom {
bottom: 35px;
}
.size,
.margin.left,
.margin.right,
.padding.left,
.padding.right {
top: 0;
line-height: 132px;
}
.size {
width: -moz-calc(100% - 2px);
}
.margin.right,
.margin.left {
width: 28px;
}
.padding.right,
.padding.left {
width: 25px;
}
.margin.right {
right: 0;
}
.margin.left {
left: 0;
}
.padding.left {
left: 30px;
}
.padding.right {
right: 30px;
}
.tooltip {
position: absolute;
bottom: 0;
right: 2px;
pointer-events: none;
}
body.dim > #main,
body.dim > #header > #element-size {
visibility: hidden;
}

View File

@ -0,0 +1,149 @@
<?xml version="1.0" encoding="UTF-8"?>
#ifdef 0
<!-- ***** BEGIN LICENSE BLOCK *****
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (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.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
-
- The Original Code is LayoutView.
-
- The Initial Developer of the Original Code is
- The Mozilla Foundation.
- Portions created by the Initial Developer are Copyright (C) 2012
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Paul Rouget <paul@mozilla.com> (original author)
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the GPL or the LGPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
- ***** END LICENSE BLOCK ***** -->
#endif
<!DOCTYPE html [
<!ENTITY % layoutviewDTD SYSTEM "chrome://browser/locale/devtools/layoutview.dtd" >
%layoutviewDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<head>
<title>Layout View</title>
<script type="application/javascript;version=1.8">
<![CDATA[
let elts;
let tooltip;
const Ci = Components.interfaces;
const Cc = Components.classes;
window.onload = function() {
// Tooltip mechanism
elts = document.querySelectorAll("*[tooltip]");
tooltip = document.querySelector(".tooltip");
for (let i = 0; i < elts.length; i++) {
let elt = elts[i];
elt.addEventListener("mouseover", onmouseover, true);
elt.addEventListener("mouseout", onmouseout, true);
}
// Mark document as RTL or LTR:
let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].
getService(Ci.nsIXULChromeRegistry);
let dir = chromeReg.isLocaleRTL("global");
document.body.setAttribute("dir", dir ? "rtl" : "ltr");
window.parent.postMessage("layoutview-ready", "*");
}
window.onunload = function() {
if (elts) {
for (let i = 0; i < elts.length; i++) {
let elt = elts[i];
elt.removeEventListener("mouseover", onmouseover, true);
elt.removeEventListener("mouseout", onmouseout, true);
}
}
}
function onmouseover(e) {
tooltip.textContent = e.target.getAttribute("tooltip");
}
function onmouseout(e) {
tooltip.textContent = "";
}
function toggleView() {
window.parent.postMessage("layoutview-toggle-view", "*");
}
]]>
</script>
<link rel="stylesheet" href="chrome://browser/skin/devtools/layoutview.css" type="text/css"/>
<link rel="stylesheet" href="view.css" type="text/css"/>
</head>
<body>
<!-- Header: always visible, even when the view is closed. -->
<a onclick="toggleView()" href="#" id="header">
<span>&elementSize.label;</span>
<span id="element-size"></span>
<span id="togglebutton"></span>
</a>
<!-- Boxes: hidden when the view is closed. -->
<div id="main">
<div id="margins" tooltip="&margins.tooltip;">
<div id="borders" tooltip="&borders.tooltip;">
<div id="padding" tooltip="&padding.tooltip;">
<div id="content" tooltip="&content.tooltip;">
</div>
</div>
</div>
</div>
<p class="border top"><span tooltip="border-top"></span></p>
<p class="border right"><span tooltip="border-right"></span></p>
<p class="border bottom"><span tooltip="border-bottom"></span></p>
<p class="border left"><span tooltip="border-left"></span></p>
<p class="margin top"><span tooltip="margin-top"></span></p>
<p class="margin right"><span tooltip="margin-right"></span></p>
<p class="margin bottom"><span tooltip="margin-bottom"></span></p>
<p class="margin left"><span tooltip="margin-left"></span></p>
<p class="padding top"><span tooltip="padding-top"></span></p>
<p class="padding right"><span tooltip="padding-right"></span></p>
<p class="padding bottom"><span tooltip="padding-bottom"></span></p>
<p class="padding left"><span tooltip="padding-left"></span></p>
<p class="size"><span tooltip="&content.tooltip;"></span></p>
<span class="tooltip"></span>
</div>
</body>
</html>

View File

@ -0,0 +1,21 @@
<!-- LOCALIZATION NOTE : FILE This file contains the Layout View strings.
- The Layout View is the panel accessible at the bottom of the Inspector
- sidebar. -->
<!-- LOCALIZATION NOTE : FILE The correct localization of this file might be to
- keep it in English, or another language commonly spoken among web developers.
- You want to make that choice consistent across the developer tools.
- A good criteria is the language in which you'd find the best
- documentation on web development on the web. -->
<!ENTITY elementSize.label "Element Size: ">
<!-- LOCALIZATION NOTE (*.tooltip): These tooltips are not regular tooltips.
- The text appears on the bottom right corner of the layout view when
- the corresponding box is hovered. -->
<!ENTITY margins.tooltip "margins">
<!ENTITY borders.tooltip "borders">
<!ENTITY padding.tooltip "padding">
<!ENTITY content.tooltip "content">

View File

@ -31,6 +31,7 @@
locale/browser/devtools/webConsole.dtd (%chrome/browser/devtools/webConsole.dtd)
locale/browser/devtools/sourceeditor.properties (%chrome/browser/devtools/sourceeditor.properties)
locale/browser/devtools/sourceeditor.dtd (%chrome/browser/devtools/sourceeditor.dtd)
locale/browser/devtools/layoutview.dtd (%chrome/browser/devtools/layoutview.dtd)
locale/browser/newTab.dtd (%chrome/browser/newTab.dtd)
locale/browser/newTab.properties (%chrome/browser/newTab.properties)
locale/browser/openLocation.dtd (%chrome/browser/openLocation.dtd)

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,87 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is LayoutView.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2012
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Paul Rouget <paul@mozilla.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
body {
background: url(layout-background.png), -moz-radial-gradient(50% 70%, circle cover, hsl(210,53%,45%) 0%, hsl(210,54%,33%) 100%);
color: hsl(210,100%,85%);
border-top: 1px solid black;
-moz-box-sizing: border-box;
}
#element-size {
color: hsl(210,100%,95%);
}
#main {
border-color: hsla(210,100%,85%,0.7);
border-style: dotted;
}
#main > .border {
color: hsl(210,53%,45%);
}
.border > span {
background-color: hsl(210,100%,85%);
border-radius: 2px;
padding: 0 4px;
}
#content {
border-color: hsla(210,100%,85%,0.7);
border-style: dotted
}
#padding {
border-color: hsla(210,100%,85%,0.2);
border-style: solid;
}
#borders {
border-style: solid;
border-color: hsl(210,100%,85%);
}
#togglebutton {
background-image: url(layout-buttons.png);
width: 18px;
height: 18px;
margin-top: -3px;
}
body.open > #header > #togglebutton {
background-position: -18px 0;
}

View File

@ -138,6 +138,9 @@ browser.jar:
skin/classic/browser/devtools/inspect-button.png (devtools/inspect-button.png)
skin/classic/browser/devtools/dropmarker.png (devtools/dropmarker.png)
skin/classic/browser/devtools/treepanel-button.png (devtools/treepanel-button.png)
skin/classic/browser/devtools/layout-background.png (devtools/layout-background.png)
skin/classic/browser/devtools/layoutview.css (devtools/layoutview.css)
skin/classic/browser/devtools/layout-buttons.png (devtools/layout-buttons.png)
#ifdef MOZ_SERVICES_SYNC
skin/classic/browser/sync-16-throbber.png
skin/classic/browser/sync-16.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,88 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is LayoutView.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2012
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Paul Rouget <paul@mozilla.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
body {
background: url(layout-background.png), -moz-radial-gradient(50% 70%, circle cover, hsl(210,53%,45%) 0%, hsl(210,54%,33%) 100%);
color: hsl(210,100%,85%);
border-top: 1px solid black;
-moz-box-sizing: border-box;
}
#element-size {
color: hsl(210,100%,95%);
}
#main {
border-color: hsla(210,100%,85%,0.7);
border-style: dotted;
}
#main > .border {
color: hsl(210,53%,45%);
}
.border > span {
background-color: hsl(210,100%,85%);
border-radius: 2px;
padding: 0 4px;
}
#content {
border-color: hsla(210,100%,85%,0.7);
border-style: dotted
}
#padding {
border-color: hsla(210,100%,85%,0.2);
border-style: solid;
}
#borders {
border-style: solid;
border-color: hsl(210,100%,85%);
}
#togglebutton {
background-image: url(layout-buttons.png);
width: 18px;
height: 18px;
margin-top: -3px;
}
body.open > #header > #togglebutton {
background-position: -18px 0;
}

View File

@ -179,6 +179,9 @@ browser.jar:
skin/classic/browser/devtools/inspect-button.png (devtools/inspect-button.png)
skin/classic/browser/devtools/dropmarker.png (devtools/dropmarker.png)
skin/classic/browser/devtools/treepanel-button.png (devtools/treepanel-button.png)
skin/classic/browser/devtools/layout-background.png (devtools/layout-background.png)
skin/classic/browser/devtools/layoutview.css (devtools/layoutview.css)
skin/classic/browser/devtools/layout-buttons.png (devtools/layout-buttons.png)
#ifdef MOZ_SERVICES_SYNC
skin/classic/browser/sync-throbber.png
skin/classic/browser/sync-16.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,88 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is LayoutView.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2012
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Paul Rouget <paul@mozilla.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
body {
background: url(layout-background.png), -moz-radial-gradient(50% 70%, circle cover, hsl(210,53%,45%) 0%, hsl(210,54%,33%) 100%);
color: hsl(210,100%,85%);
border-top: 1px solid black;
-moz-box-sizing: border-box;
}
#element-size {
color: hsl(210,100%,95%);
}
#main {
border-color: hsla(210,100%,85%,0.7);
border-style: dotted;
}
#main > .border {
color: hsl(210,53%,45%);
}
.border > span {
background-color: hsl(210,100%,85%);
border-radius: 2px;
padding: 0 4px;
}
#content {
border-color: hsla(210,100%,85%,0.7);
border-style: dotted
}
#padding {
border-color: hsla(210,100%,85%,0.2);
border-style: solid;
}
#borders {
border-style: solid;
border-color: hsl(210,100%,85%);
}
#togglebutton {
background-image: url(layout-buttons.png);
width: 18px;
height: 18px;
margin-top: -3px;
}
body.open > #header > #togglebutton {
background-position: -18px 0;
}

View File

@ -165,6 +165,9 @@ browser.jar:
skin/classic/browser/devtools/inspect-button.png (devtools/inspect-button.png)
skin/classic/browser/devtools/dropmarker.png (devtools/dropmarker.png)
skin/classic/browser/devtools/treepanel-button.png (devtools/treepanel-button.png)
skin/classic/browser/devtools/layout-background.png (devtools/layout-background.png)
skin/classic/browser/devtools/layoutview.css (devtools/layoutview.css)
skin/classic/browser/devtools/layout-buttons.png (devtools/layout-buttons.png)
#ifdef MOZ_SERVICES_SYNC
skin/classic/browser/sync-throbber.png
skin/classic/browser/sync-16.png
@ -345,6 +348,9 @@ browser.jar:
skin/classic/aero/browser/devtools/inspect-button.png (devtools/inspect-button.png)
skin/classic/aero/browser/devtools/dropmarker.png (devtools/dropmarker.png)
skin/classic/aero/browser/devtools/treepanel-button.png (devtools/treepanel-button.png)
skin/classic/aero/browser/devtools/layout-background.png (devtools/layout-background.png)
skin/classic/aero/browser/devtools/layoutview.css (devtools/layoutview.css)
skin/classic/aero/browser/devtools/layout-buttons.png (devtools/layout-buttons.png)
#ifdef MOZ_SERVICES_SYNC
skin/classic/aero/browser/sync-throbber.png
skin/classic/aero/browser/sync-16.png