Bug 582596 - Style view centered around answering common CSS questions, f=l10n, r=dolske, msucan

This commit is contained in:
Mike Ratcliffe 2011-08-30 09:12:02 -03:00
Родитель 7fdd00c2c2
Коммит 49aa83fb77
30 изменённых файлов: 4958 добавлений и 0 удалений

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

@ -1015,6 +1015,9 @@ pref("devtools.errorconsole.enabled", false);
// Enable the Inspector
pref("devtools.inspector.enabled", true);
// Enable the style inspector
pref("devtools.styleinspector.enabled", true);
// Enable the Scratchpad tool.
pref("devtools.scratchpad.enabled", true);

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

@ -21,6 +21,7 @@
#
# Contributor(s):
# Rob Campbell <rcampbell@mozilla.com>
# Mike Ratcliffe <mratcliffe@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
@ -49,6 +50,8 @@ DIRS = \
webconsole \
scratchpad \
sourceeditor \
styleinspector \
shared \
$(NULL)
ifdef ENABLE_TESTS

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

@ -2,5 +2,6 @@ browser.jar:
content/browser/NetworkPanel.xhtml (webconsole/NetworkPanel.xhtml)
* content/browser/scratchpad.xul (scratchpad/scratchpad.xul)
* content/browser/scratchpad.js (scratchpad/scratchpad.js)
content/browser/csshtmltree.xhtml (styleinspector/csshtmltree.xhtml)
content/browser/orion.js (sourceeditor/orion/orion.js)
content/browser/orion.css (sourceeditor/orion/orion.css)

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

@ -0,0 +1,55 @@
#
# ***** 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 HUDService code.
#
# The Initial Developer of the Original Code is Mozilla Corporation.
#
# Portions created by the Initial Developer are Copyright (C) 2010
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Mike Ratcliffe <mratcliffe@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 *****
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
ifdef ENABLE_TESTS
ifneq (mobile,$(MOZ_BUILD_APP))
# DIRS += test # no tests yet
endif
endif
include $(topsrcdir)/config/rules.mk
libs::
$(NSINSTALL) $(srcdir)/Templater.jsm $(FINAL_TARGET)/modules/devtools

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

@ -0,0 +1,398 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set 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 Bespin.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Joe Walker (jwalker@mozilla.com) (original author)
* Mike Ratcliffe (mratcliffe@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 ***** */
// WARNING: do not 'use_strict' without reading the notes in envEval;
var EXPORTED_SYMBOLS = ["Templater"];
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
/**
* A templater that allows one to quickly template DOM nodes.
*/
function Templater() {
this.scope = [];
}
/**
* Recursive function to walk the tree processing the attributes as it goes.
* @param node the node to process.
* @param data the data to use for node processing.
*/
Templater.prototype.processNode = function(node, data) {
this.scope.push(node.nodeName + (node.id ? '#' + node.id : ''));
try {
// Process attributes
if (node.attributes && node.attributes.length) {
// We need to handle 'foreach' and 'if' first because they might stop
// some types of processing from happening, and foreach must come first
// because it defines new data on which 'if' might depend.
if (node.hasAttribute('foreach')) {
this.processForEach(node, data);
return;
}
if (node.hasAttribute('if')) {
if (!this.processIf(node, data)) {
return;
}
}
// Only make the node available once we know it's not going away
data.__element = node;
// It's good to clean up the attributes when we've processed them,
// but if we do it straight away, we mess up the array index
var attrs = Array.prototype.slice.call(node.attributes);
for (let i = 0, attLen = attrs.length; i < attLen; i++) {
var value = attrs[i].value;
var name = attrs[i].name;
this.scope.push(name);
try {
if (name === 'save') {
// Save attributes are a setter using the node
value = this.stripBraces(value);
this.property(value, data, node);
node.removeAttribute('save');
} else if (name.substring(0, 2) === 'on') {
// Event registration relies on property doing a bind
value = this.stripBraces(value);
var func = this.property(value, data);
if (typeof func !== 'function') {
this.handleError('Expected ' + value +
' to resolve to a function, but got ' + typeof func);
}
node.removeAttribute(name);
var capture = node.hasAttribute('capture' + name.substring(2));
node.addEventListener(name.substring(2), func, capture);
if (capture) {
node.removeAttribute('capture' + name.substring(2));
}
} else {
// Replace references in all other attributes
var self = this;
var newValue = value.replace(/\$\{[^}]*\}/g, function(path) {
return self.envEval(path.slice(2, -1), data, value);
});
// Remove '_' prefix of attribute names so the DOM won't try
// to use them before we've processed the template
if (name.charAt(0) === '_') {
node.removeAttribute(name);
node.setAttribute(name.substring(1), newValue);
} else if (value !== newValue) {
attrs[i].value = newValue;
}
}
} finally {
this.scope.pop();
}
}
}
// Loop through our children calling processNode. First clone them, so the
// set of nodes that we visit will be unaffected by additions or removals.
var children = Array.prototype.slice.call(node.childNodes);
for (let j = 0, numChildren = children.length; j < numChildren; j++) {
this.processNode(children[j], data);
}
if (node.nodeType === Ci.nsIDOMNode.TEXT_NODE) {
this.processTextNode(node, data);
}
} finally {
this.scope.pop();
}
};
/**
* Handle <x if="${...}">
* @param node An element with an 'if' attribute
* @param data The data to use with envEval
* @returns true if processing should continue, false otherwise
*/
Templater.prototype.processIf = function(node, data) {
this.scope.push('if');
try {
var originalValue = node.getAttribute('if');
var value = this.stripBraces(originalValue);
var recurse = true;
try {
var reply = this.envEval(value, data, originalValue);
recurse = !!reply;
} catch (ex) {
this.handleError('Error with \'' + value + '\'', ex);
recurse = false;
}
if (!recurse) {
node.parentNode.removeChild(node);
}
node.removeAttribute('if');
return recurse;
} finally {
this.scope.pop();
}
};
/**
* Handle <x foreach="param in ${array}"> and the special case of
* <loop foreach="param in ${array}">
* @param node An element with a 'foreach' attribute
* @param data The data to use with envEval
*/
Templater.prototype.processForEach = function(node, data) {
this.scope.push('foreach');
try {
var originalValue = node.getAttribute('foreach');
var value = originalValue;
var paramName = 'param';
if (value.charAt(0) === '$') {
// No custom loop variable name. Use the default: 'param'
value = this.stripBraces(value);
} else {
// Extract the loop variable name from 'NAME in ${ARRAY}'
var nameArr = value.split(' in ');
paramName = nameArr[0].trim();
value = this.stripBraces(nameArr[1].trim());
}
node.removeAttribute('foreach');
try {
var self = this;
// Process a single iteration of a loop
var processSingle = function(member, node, ref) {
var clone = node.cloneNode(true);
clone.removeAttribute('foreach');
ref.parentNode.insertBefore(clone, ref);
data[paramName] = member;
self.processNode(clone, data);
delete data[paramName];
};
// processSingle is no good for <loop> nodes where we want to work on
// the children rather than the node itself
var processAll = function(scope, member) {
self.scope.push(scope);
try {
if (node.nodeName === 'loop') {
for (let i = 0, numChildren = node.children.length; i < numChildren; i++) {
processSingle(member, node.children[i], node);
}
} else {
processSingle(member, node, node);
}
} finally {
self.scope.pop();
}
};
let reply = this.envEval(value, data, originalValue);
if (Array.isArray(reply)) {
reply.forEach(function(data, i) {
processAll('' + i, data)
}, this);
} else {
for (let param in reply) {
if (reply.hasOwnProperty(param)) {
processAll(param, param);
}
}
}
node.parentNode.removeChild(node);
} catch (ex) {
this.handleError('Error with \'' + value + '\'', ex);
}
} finally {
this.scope.pop();
}
};
/**
* Take a text node and replace it with another text node with the ${...}
* sections parsed out. We replace the node by altering node.parentNode but
* we could probably use a DOM Text API to achieve the same thing.
* @param node The Text node to work on
* @param data The data to use in calls to envEval
*/
Templater.prototype.processTextNode = function(node, data) {
// Replace references in other attributes
var value = node.data;
// We can't use the string.replace() with function trick (see generic
// attribute processing in processNode()) because we need to support
// functions that return DOM nodes, so we can't have the conversion to a
// string.
// Instead we process the string as an array of parts. In order to split
// the string up, we first replace '${' with '\uF001$' and '}' with '\uF002'
// We can then split using \uF001 or \uF002 to get an array of strings
// where scripts are prefixed with $.
// \uF001 and \uF002 are just unicode chars reserved for private use.
value = value.replace(/\$\{([^}]*)\}/g, '\uF001$$$1\uF002');
var parts = value.split(/\uF001|\uF002/);
if (parts.length > 1) {
parts.forEach(function(part) {
if (part === null || part === undefined || part === '') {
return;
}
if (part.charAt(0) === '$') {
part = this.envEval(part.slice(1), data, node.data);
}
// It looks like this was done a few lines above but see envEval
if (part === null) {
part = "null";
}
if (part === undefined) {
part = "undefined";
}
// if (isDOMElement(part)) { ... }
if (typeof part.cloneNode !== 'function') {
part = node.ownerDocument.createTextNode(part.toString());
}
node.parentNode.insertBefore(part, node);
}, this);
node.parentNode.removeChild(node);
}
};
/**
* Warn of string does not begin '${' and end '}'
* @param str the string to check.
* @return The string stripped of ${ and }, or untouched if it does not match
*/
Templater.prototype.stripBraces = function(str) {
if (!str.match(/\$\{.*\}/g)) {
this.handleError('Expected ' + str + ' to match ${...}');
return str;
}
return str.slice(2, -1);
};
/**
* Combined getter and setter that works with a path through some data set.
* For example:
* <ul>
* <li>property('a.b', { a: { b: 99 }}); // returns 99
* <li>property('a', { a: { b: 99 }}); // returns { b: 99 }
* <li>property('a', { a: { b: 99 }}, 42); // returns 99 and alters the
* input data to be { a: { b: 42 }}
* </ul>
* @param path An array of strings indicating the path through the data, or
* a string to be cut into an array using <tt>split('.')</tt>
* @param data An object to look in for the <tt>path</tt> argument
* @param newValue (optional) If defined, this value will replace the
* original value for the data at the path specified.
* @return The value pointed to by <tt>path</tt> before any
* <tt>newValue</tt> is applied.
*/
Templater.prototype.property = function(path, data, newValue) {
this.scope.push(path);
try {
if (typeof path === 'string') {
path = path.split('.');
}
var value = data[path[0]];
if (path.length === 1) {
if (newValue !== undefined) {
data[path[0]] = newValue;
}
if (typeof value === 'function') {
return value.bind(data);
}
return value;
}
if (!value) {
this.handleError('Can\'t find path=' + path);
return null;
}
return this.property(path.slice(1), value, newValue);
} finally {
this.scope.pop();
}
};
/**
* Like eval, but that creates a context of the variables in <tt>env</tt> in
* which the script is evaluated.
* WARNING: This script uses 'with' which is generally regarded to be evil.
* The alternative is to create a Function at runtime that takes X parameters
* according to the X keys in the env object, and then call that function using
* the values in the env object. This is likely to be slow, but workable.
* @param script The string to be evaluated.
* @param env The environment in which to eval the script.
* @param context Optional debugging string in case of failure
* @return The return value of the script, or the error message if the script
* execution failed.
*/
Templater.prototype.envEval = function(script, env, context) {
with (env) {
try {
this.scope.push(context);
return eval(script);
} catch (ex) {
this.handleError('Template error evaluating \'' + script + '\'', ex);
return script;
} finally {
this.scope.pop();
}
}
};
/**
* A generic way of reporting errors, for easy overloading in different
* environments.
* @param message the error message to report.
* @param ex optional associated exception.
*/
Templater.prototype.handleError = function(message, ex) {
this.logError(message);
this.logError('In: ' + this.scope.join(' > '));
if (ex) {
this.logError(ex);
}
};
/**
* A generic way of reporting errors, for easy overloading in different
* environments.
* @param message the error message to report.
*/
Templater.prototype.logError = function(message) {
Services.console.logStringMessage(message);
};

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

@ -0,0 +1,842 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set 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 Inspector Module.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Joe Walker (jwalker@mozilla.com) (original author)
* Mihai Șucan <mihai.sucan@gmail.com>
* Michael Ratcliffe <mratcliffe@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 ***** */
const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/PluralForm.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource:///modules/devtools/CssLogic.jsm");
Cu.import("resource:///modules/devtools/Templater.jsm");
var EXPORTED_SYMBOLS = ["CssHtmlTree"];
/**
* CssHtmlTree is a panel that manages the display of a table sorted by style.
* There should be one instance of CssHtmlTree per style display (of which there
* will generally only be one).
*
* @params {Document} aStyleWin The main XUL browser document
* @params {CssLogic} aCssLogic How we dig into the CSS. See CssLogic.jsm
* @constructor
*/
function CssHtmlTree(aStyleWin, aCssLogic, aPanel)
{
this.styleWin = aStyleWin;
this.cssLogic = aCssLogic;
this.doc = aPanel.ownerDocument;
this.win = this.doc.defaultView;
this.getRTLAttr = CssHtmlTree.getRTLAttr;
// The document in which we display the results (csshtmltree.xhtml).
this.styleDocument = this.styleWin.contentWindow.document;
// Nodes used in templating
this.root = this.styleDocument.getElementById("root");
this.templateRoot = this.styleDocument.getElementById("templateRoot");
this.panel = aPanel;
// The element that we're inspecting, and the document that it comes from.
this.viewedElement = null;
this.viewedDocument = null;
this.createStyleGroupViews();
}
/**
* Memonized lookup of a l10n string from a string bundle.
* @param {string} aName The key to lookup.
* @returns A localized version of the given key.
*/
CssHtmlTree.l10n = function CssHtmlTree_l10n(aName)
{
try {
return CssHtmlTree._strings.GetStringFromName(aName);
} catch (ex) {
Services.console.logStringMessage("Error reading '" + aName + "'");
throw new Error("l10n error with " + aName);
}
};
/**
* Clone the given template node, and process it by resolving ${} references
* in the template.
*
* @param {nsIDOMElement} aTemplate the template note to use.
* @param {nsIDOMElement} aDestination the destination node where the
* processed nodes will be displayed.
* @param {object} aData the data to pass to the template.
*/
CssHtmlTree.processTemplate = function CssHtmlTree_processTemplate(aTemplate, aDestination, aData)
{
aDestination.innerHTML = "";
// All the templater does is to populate a given DOM tree with the given
// values, so we need to clone the template first.
let duplicated = aTemplate.cloneNode(true);
new Templater().processNode(duplicated, aData);
while (duplicated.firstChild) {
aDestination.appendChild(duplicated.firstChild);
}
};
/**
* Checks whether the UI is RTL
* @return {Boolean} true or false
*/
CssHtmlTree.isRTL = function CssHtmlTree_isRTL()
{
return CssHtmlTree.getRTLAttr == "rtl";
};
/**
* Checks whether the UI is RTL
* @return {String} "ltr" or "rtl"
*/
XPCOMUtils.defineLazyGetter(CssHtmlTree, "getRTLAttr", function() {
let mainWindow = Services.wm.getMostRecentWindow("navigator:browser");
return mainWindow.getComputedStyle(mainWindow.gBrowser).direction;
});
XPCOMUtils.defineLazyGetter(CssHtmlTree, "_strings", function() Services.strings
.createBundle("chrome://browser/locale/styleinspector.properties"));
CssHtmlTree.prototype = {
/**
* Focus the output display on a specific element.
* @param {nsIDOMElement} aElement The highlighted node to get styles for.
*/
highlight: function CssHtmlTree_highlight(aElement)
{
this.viewedElement = aElement;
// Reset the style groups. Without this previously expanded groups
// will fail to expand when inspecting subsequent nodes
let close = !aElement;
this.styleGroups.forEach(function(group) group.reset(close));
if (this.viewedElement) {
this.viewedDocument = this.viewedElement.ownerDocument;
CssHtmlTree.processTemplate(this.templateRoot, this.root, this);
} else {
this.viewedDocument = null;
this.root.innerHTML = "";
}
},
/**
* Called when the user clicks on a parent element in the "current element"
* path.
*
* @param {Event} aEvent the DOM Event object.
*/
pathClick: function CssHtmlTree_pathClick(aEvent)
{
aEvent.preventDefault();
if (aEvent.target && aEvent.target.pathElement) {
if (this.win.InspectorUI.selection) {
if (aEvent.target.pathElement != this.win.InspectorUI.selection) {
this.win.InspectorUI.inspectNode(aEvent.target.pathElement);
}
} else {
this.panel.selectNode(aEvent.target.pathElement);
}
}
},
/**
* Provide access to the path to get from document.body to the selected
* element.
*
* @return {array} the array holding the path from document.body to the
* selected element.
*/
get pathElements()
{
return CssLogic.getShortNamePath(this.viewedElement);
},
/**
* Returns arrays of categorized properties.
*/
_getPropertiesByGroup: function CssHtmlTree_getPropertiesByGroup()
{
return {
text: [
"color", // inherit http://www.w3.org/TR/CSS21/propidx.html
"color-interpolation", //
"color-interpolation-filters", //
"direction", // inherit http://www.w3.org/TR/CSS21/propidx.html
"fill", //
"fill-opacity", //
"fill-rule", //
"filter", //
"flood-color", //
"flood-opacity", //
"font-family", // inherit http://www.w3.org/TR/CSS21/propidx.html
"font-size", // inherit http://www.w3.org/TR/CSS21/propidx.html
"font-size-adjust", // inherit http://www.w3.org/TR/WD-font/#font-size-props
"font-stretch", // inherit http://www.w3.org/TR/WD-font/#font-stretch
"font-style", // inherit http://www.w3.org/TR/CSS21/propidx.html
"font-variant", // inherit http://www.w3.org/TR/CSS21/propidx.html
"font-weight", // inherit http://www.w3.org/TR/CSS21/propidx.html
"ime-mode", //
"letter-spacing", // inherit http://www.w3.org/TR/CSS21/propidx.html
"lighting-color", //
"line-height", // inherit http://www.w3.org/TR/CSS21/propidx.html
"opacity", // no http://www.w3.org/TR/css3-color/#transparency
"quotes", // inherit http://www.w3.org/TR/CSS21/propidx.html
"stop-color", //
"stop-opacity", //
"stroke-opacity", //
"text-align", // inherit http://www.w3.org/TR/CSS21/propidx.html
"text-anchor", //
"text-decoration", // no http://www.w3.org/TR/CSS21/propidx.html
"text-indent", // inherit http://www.w3.org/TR/CSS21/propidx.html
"text-overflow", //
"text-rendering", // inherit http://www.w3.org/TR/SVG/painting.html#TextRenderingProperty !
"text-shadow", // inherit http://www.w3.org/TR/css3-text/#text-shadow
"text-transform", // inherit http://www.w3.org/TR/CSS21/propidx.html
"vertical-align", // no http://www.w3.org/TR/CSS21/propidx.html
"white-space", // inherit http://www.w3.org/TR/CSS21/propidx.html
"word-spacing", // inherit http://www.w3.org/TR/css3-text/#word-spacing
"word-wrap", // inherit http://www.w3.org/TR/css3-text/#word-wrap
"-moz-column-count", // no http://www.w3.org/TR/css3-multicol/#column-count
"-moz-column-gap", // no http://www.w3.org/TR/css3-multicol/#column-gap
"-moz-column-rule-color", // no http://www.w3.org/TR/css3-multicol/#crc
"-moz-column-rule-style", // no http://www.w3.org/TR/css3-multicol/#column-rule-style
"-moz-column-rule-width", // no http://www.w3.org/TR/css3-multicol/#column-rule-width
"-moz-column-width", // no http://www.w3.org/TR/css3-multicol/#column-width
"-moz-font-feature-settings", //
"-moz-font-language-override", //
"-moz-hyphens", //
"-moz-text-decoration-color", //
"-moz-text-decoration-style", //
"-moz-text-decoration-line", //
"-moz-text-blink", //
"-moz-tab-size", //
],
list: [
"list-style-image", // inherit http://www.w3.org/TR/CSS21/propidx.html
"list-style-position", // inherit http://www.w3.org/TR/CSS21/propidx.html
"list-style-type", // inherit http://www.w3.org/TR/CSS21/propidx.html
"marker-end", //
"marker-mid", //
"marker-offset", //
"marker-start", //
],
background: [
"background-attachment", // no http://www.w3.org/TR/css3-background/#background-attachment
"background-clip", // no http://www.w3.org/TR/css3-background/#background-clip
"background-color", // no http://www.w3.org/TR/css3-background/#background-color
"background-image", // no http://www.w3.org/TR/css3-background/#background-image
"background-origin", // no http://www.w3.org/TR/css3-background/#background-origin
"background-position", // no http://www.w3.org/TR/css3-background/#background-position
"background-repeat", // no http://www.w3.org/TR/css3-background/#background-repeat
"background-size", // no http://www.w3.org/TR/css3-background/#background-size
"-moz-appearance", //
"-moz-background-inline-policy", //
],
dims: [
"width", // no http://www.w3.org/TR/CSS21/propidx.html
"height", // no http://www.w3.org/TR/CSS21/propidx.html
"max-width", // no http://www.w3.org/TR/CSS21/propidx.html
"max-height", // no http://www.w3.org/TR/CSS21/propidx.html
"min-width", // no http://www.w3.org/TR/CSS21/propidx.html
"min-height", // no http://www.w3.org/TR/CSS21/propidx.html
"margin-top", // no http://www.w3.org/TR/CSS21/propidx.html
"margin-right", // no http://www.w3.org/TR/CSS21/propidx.html
"margin-bottom", // no http://www.w3.org/TR/CSS21/propidx.html
"margin-left", // no http://www.w3.org/TR/CSS21/propidx.html
"padding-top", // no http://www.w3.org/TR/CSS21/propidx.html
"padding-right", // no http://www.w3.org/TR/CSS21/propidx.html
"padding-bottom", // no http://www.w3.org/TR/CSS21/propidx.html
"padding-left", // no http://www.w3.org/TR/CSS21/propidx.html
"clip", // no http://www.w3.org/TR/CSS21/propidx.html
"clip-path", //
"clip-rule", //
"resize", // no http://www.w3.org/TR/css3-ui/#resize
"stroke-width", //
"-moz-box-flex", //
"-moz-box-sizing", // no http://www.w3.org/TR/css3-ui/#box-sizing
],
pos: [
"top", // no http://www.w3.org/TR/CSS21/propidx.html
"right", // no http://www.w3.org/TR/CSS21/propidx.html
"bottom", // no http://www.w3.org/TR/CSS21/propidx.html
"left", // no http://www.w3.org/TR/CSS21/propidx.html
"display", // no http://www.w3.org/TR/CSS21/propidx.html
"float", // no http://www.w3.org/TR/CSS21/propidx.html
"clear", // no http://www.w3.org/TR/CSS21/propidx.html
"position", // no http://www.w3.org/TR/CSS21/propidx.html
"visibility", // inherit http://www.w3.org/TR/CSS21/propidx.html
"overflow", //
"overflow-x", // no http://www.w3.org/TR/CSS21/propidx.html
"overflow-y", // no http://www.w3.org/TR/CSS21/propidx.html
"z-index", // no http://www.w3.org/TR/CSS21/propidx.html
"dominant-baseline", //
"page-break-after", //
"page-break-before", //
"stroke-dashoffset", //
"unicode-bidi", //
"-moz-box-align", //
"-moz-box-direction", //
"-moz-box-ordinal-group", //
"-moz-box-orient", //
"-moz-box-pack", //
"-moz-float-edge", //
"-moz-orient", //
"-moz-stack-sizing", //
],
border: [
"border-top-width", // no http://www.w3.org/TR/CSS21/propidx.html
"border-right-width", // no http://www.w3.org/TR/CSS21/propidx.html
"border-bottom-width", // no http://www.w3.org/TR/CSS21/propidx.html
"border-left-width", // no http://www.w3.org/TR/CSS21/propidx.html
"border-top-color", // no http://www.w3.org/TR/CSS21/propidx.html
"border-right-color", // no http://www.w3.org/TR/CSS21/propidx.html
"border-bottom-color", // no http://www.w3.org/TR/CSS21/propidx.html
"border-left-color", // no http://www.w3.org/TR/CSS21/propidx.html
"border-top-style", // no http://www.w3.org/TR/CSS21/propidx.html
"border-right-style", // no http://www.w3.org/TR/CSS21/propidx.html
"border-bottom-style", // no http://www.w3.org/TR/CSS21/propidx.html
"border-left-style", // no http://www.w3.org/TR/CSS21/propidx.html
"border-collapse", // no http://www.w3.org/TR/CSS21/propidx.html
"border-spacing", // no http://www.w3.org/TR/CSS21/propidx.html
"outline-offset", // no http://www.w3.org/TR/CSS21/propidx.html
"outline-style", //
"outline-color", //
"outline-width", //
"border-top-left-radius", // no http://www.w3.org/TR/css3-background/#border-radius
"border-top-right-radius", // no http://www.w3.org/TR/css3-background/#border-radius
"border-bottom-right-radius", // no http://www.w3.org/TR/css3-background/#border-radius
"border-bottom-left-radius", // no http://www.w3.org/TR/css3-background/#border-radius
"-moz-border-bottom-colors", //
"-moz-border-image", //
"-moz-border-left-colors", //
"-moz-border-right-colors", //
"-moz-border-top-colors", //
"-moz-outline-radius-topleft", // no http://www.w3.org/TR/CSS2/ui.html#dynamic-outlines ?
"-moz-outline-radius-topright", // no http://www.w3.org/TR/CSS2/ui.html#dynamic-outlines ?
"-moz-outline-radius-bottomright", // no http://www.w3.org/TR/CSS2/ui.html#dynamic-outlines ?
"-moz-outline-radius-bottomleft", // no http://www.w3.org/TR/CSS2/ui.html#dynamic-outlines ?
],
other: [
"box-shadow", // no http://www.w3.org/TR/css3-background/#box-shadow
"caption-side", // inherit http://www.w3.org/TR/CSS21/propidx.html
"content", // no http://www.w3.org/TR/CSS21/propidx.html
"counter-increment", // no http://www.w3.org/TR/CSS21/propidx.html
"counter-reset", // no http://www.w3.org/TR/CSS21/propidx.html
"cursor", // inherit http://www.w3.org/TR/CSS21/propidx.html
"empty-cells", // inherit http://www.w3.org/TR/CSS21/propidx.html
"image-rendering", // inherit http://www.w3.org/TR/SVG/painting.html#ImageRenderingProperty
"mask", //
"pointer-events", // inherit http://www.w3.org/TR/SVG11/interact.html#PointerEventsProperty
"shape-rendering", //
"stroke", //
"stroke-dasharray", //
"stroke-linecap", //
"stroke-linejoin", //
"stroke-miterlimit", //
"table-layout", // no http://www.w3.org/TR/CSS21/propidx.html
"-moz-animation-delay", //
"-moz-animation-direction", //
"-moz-animation-duration", //
"-moz-animation-fill-mode", //
"-moz-animation-iteration-count", //
"-moz-animation-name", //
"-moz-animation-play-state", //
"-moz-animation-timing-function", //
"-moz-backface-visibility", //
"-moz-binding", //
"-moz-force-broken-image-icon", //
"-moz-image-region", //
"-moz-perspective", //
"-moz-perspective-origin", //
"-moz-transform", // no http://www.w3.org/TR/css3-2d-transforms/#transform-property
"-moz-transform-origin", //
"-moz-transition-delay", //
"-moz-transition-duration", //
"-moz-transition-property", //
"-moz-transition-timing-function", //
"-moz-user-focus", // inherit http://www.w3.org/TR/2000/WD-css3-userint-20000216#user-focus
"-moz-user-input", // inherit http://www.w3.org/TR/2000/WD-css3-userint-20000216#user-input
"-moz-user-modify", // inherit http://www.w3.org/TR/2000/WD-css3-userint-20000216#user-modify
"-moz-user-select", // no http://www.w3.org/TR/2000/WD-css3-userint-20000216#user-select
"-moz-window-shadow", //
],
};
},
/**
* The CSS groups as displayed by the UI.
*/
createStyleGroupViews: function CssHtmlTree_createStyleGroupViews()
{
if (!CssHtmlTree.propertiesByGroup) {
let pbg = CssHtmlTree.propertiesByGroup = this._getPropertiesByGroup();
// Add any supported properties that are not categorized to the "other" group
let mergedArray = Array.concat(
pbg.text,
pbg.list,
pbg.background,
pbg.dims,
pbg.pos,
pbg.border,
pbg.other
);
// Here we build and cache a list of css properties supported by the browser
// and store a list to check against. We could use any element but let's
// use the inspector style panel
let styles = this.styleWin.contentWindow.getComputedStyle(this.styleDocument.body);
CssHtmlTree.supportedPropertyLookup = {};
for (let i = 0, numStyles = styles.length; i < numStyles; i++) {
let prop = styles.item(i);
CssHtmlTree.supportedPropertyLookup[prop] = true;
if (mergedArray.indexOf(prop) == -1) {
pbg.other.push(prop);
}
}
this.propertiesByGroup = CssHtmlTree.propertiesByGroup;
}
let pbg = CssHtmlTree.propertiesByGroup;
// These group titles are localized by their ID. See the styleinspector.properties file.
this.styleGroups = [
new StyleGroupView(this, "Text_Fonts_and_Color", pbg.text),
new StyleGroupView(this, "Lists", pbg.list),
new StyleGroupView(this, "Background", pbg.background),
new StyleGroupView(this, "Dimensions", pbg.dims),
new StyleGroupView(this, "Positioning_and_Page_Flow", pbg.pos),
new StyleGroupView(this, "Borders", pbg.border),
new StyleGroupView(this, "Effects_and_Other", pbg.other),
];
},
};
/**
* A container to give easy access to style group data from the template engine.
*
* @constructor
* @param {CssHtmlTree} aTree the instance of the CssHtmlTree object that we are
* working with.
* @param {string} aId the style group ID.
* @param {array} aPropertyNames the list of property names associated to this
* style group view.
*/
function StyleGroupView(aTree, aId, aPropertyNames)
{
this.tree = aTree;
this.id = aId;
this.getRTLAttr = CssHtmlTree.getRTLAttr;
this.localName = CssHtmlTree.l10n("group." + this.id);
this.propertyViews = [];
aPropertyNames.forEach(function(aPropertyName) {
if (this.isPropertySupported(aPropertyName)) {
this.propertyViews.push(new PropertyView(this.tree, this, aPropertyName));
}
}, this);
this.populated = false;
this.templateProperties = this.tree.styleDocument.getElementById("templateProperties");
// Populated by templater: parent element containing the open attribute
this.element = null;
// Destination for templateProperties.
this.properties = null;
}
StyleGroupView.prototype = {
/**
* The click event handler for the title of the style group view.
*/
click: function StyleGroupView_click()
{
// TODO: Animate opening/closing. See bug 587752.
if (this.element.hasAttribute("open")) {
this.element.removeAttribute("open");
return;
}
if (!this.populated) {
CssHtmlTree.processTemplate(this.templateProperties, this.properties, this);
this.populated = true;
}
this.element.setAttribute("open", "");
},
/**
* Close the style group view.
*/
close: function StyleGroupView_close()
{
if (this.element) {
this.element.removeAttribute("open");
}
},
/**
* Reset the style group view and its property views.
*
* @param {boolean} aClosePanel tells if the style panel is closing or not.
*/
reset: function StyleGroupView_reset(aClosePanel)
{
this.close();
this.populated = false;
for (let i = 0, numViews = this.propertyViews.length; i < numViews; i++) {
this.propertyViews[i].reset();
}
if (this.properties) {
if (aClosePanel) {
if (this.element) {
this.element.removeChild(this.properties);
}
this.properties = null;
} else {
while (this.properties.hasChildNodes()) {
this.properties.removeChild(this.properties.firstChild);
}
}
}
},
/**
* Check if a CSS property is supported
*
* @param {string} aProperty the CSS property to check for
*
* @return {boolean} true or false
*/
isPropertySupported: function(aProperty) {
return aProperty && aProperty in CssHtmlTree.supportedPropertyLookup;
},
};
/**
* A container to give easy access to property data from the template engine.
*
* @constructor
* @param {CssHtmlTree} aTree the CssHtmlTree instance we are working with.
* @param {StyleGroupView} aGroup the StyleGroupView instance we are working
* with.
* @param {string} aName the CSS property name for which this PropertyView
* instance will render the rules.
*/
function PropertyView(aTree, aGroup, aName)
{
this.tree = aTree;
this.group = aGroup;
this.name = aName;
this.getRTLAttr = CssHtmlTree.getRTLAttr;
this.populated = false;
this.showUnmatched = false;
this.link = "https://developer.mozilla.org/en/CSS/" + aName;
this.templateRules = this.tree.styleDocument.getElementById("templateRules");
// The parent element which contains the open attribute
this.element = null;
// Destination for templateRules.
this.rules = null;
this.str = {};
}
PropertyView.prototype = {
/**
* The click event handler for the property name of the property view. If
* there are >0 rules then the rules are expanded. If there are 0 rules and
* >0 unmatched rules then the unmatched rules are expanded instead.
*
* @param {Event} aEvent the DOM event
*/
click: function PropertyView_click(aEvent)
{
// Clicking on the property link itself is already handled
if (aEvent.target.tagName.toLowerCase() == "a") {
return;
}
// TODO: Animate opening/closing. See bug 587752.
if (this.element.hasAttribute("open")) {
this.element.removeAttribute("open");
return;
}
if (!this.populated) {
let matchedRuleCount = this.propertyInfo.matchedRuleCount;
if (matchedRuleCount == 0 && this.showUnmatchedLink) {
this.showUnmatchedLinkClick(aEvent);
} else {
CssHtmlTree.processTemplate(this.templateRules, this.rules, this);
}
this.populated = true;
}
this.element.setAttribute("open", "");
},
/**
* Get the computed style for the current property.
*
* @return {string} the computed style for the current property of the
* currently highlighted element.
*/
get value()
{
return this.propertyInfo.value;
},
/**
* An easy way to access the CssPropertyInfo behind this PropertyView
*/
get propertyInfo()
{
return this.tree.cssLogic.getPropertyInfo(this.name);
},
/**
* Compute the title of the property view. The title includes the number of
* rules that hold the current property.
*
* @param {nsIDOMElement} aElement reference to the DOM element where the rule
* title needs to be displayed.
* @return {string} The rule title.
*/
ruleTitle: function PropertyView_ruleTitle(aElement)
{
let result = "";
let matchedRuleCount = this.propertyInfo.matchedRuleCount;
if (matchedRuleCount > 0) {
aElement.classList.add("rule-count");
let str = CssHtmlTree.l10n("property.numberOfRules");
result = PluralForm.get(matchedRuleCount, str).replace("#1", matchedRuleCount);
} else if (this.showUnmatchedLink) {
aElement.classList.add("rule-unmatched");
let unmatchedRuleCount = this.propertyInfo.unmatchedRuleCount;
let str = CssHtmlTree.l10n("property.numberOfUnmatchedRules");
result = PluralForm.get(unmatchedRuleCount, str).replace("#1", unmatchedRuleCount);
}
return result;
},
/**
* Close the property view.
*/
close: function PropertyView_close()
{
if (this.rules && this.element) {
this.element.removeAttribute("open");
}
},
/**
* Reset the property view.
*/
reset: function PropertyView_reset()
{
this.close();
this.populated = false;
this.showUnmatched = false;
this.element = false;
},
/**
* Provide access to the SelectorViews that we are currently displaying
*/
get selectorViews()
{
var all = [];
function convert(aSelectorInfo) {
all.push(new SelectorView(aSelectorInfo));
}
this.propertyInfo.matchedSelectors.forEach(convert);
if (this.showUnmatched) {
this.propertyInfo.unmatchedSelectors.forEach(convert);
}
return all;
},
/**
* Should we display a 'X unmatched rules' link?
* @return {boolean} false if we are already showing the unmatched links or
* if there are none to display, true otherwise.
*/
get showUnmatchedLink()
{
return !this.showUnmatched && this.propertyInfo.unmatchedRuleCount > 0;
},
/**
* The UI has a link to allow the user to display unmatched selectors.
* This provides localized link text.
*/
get showUnmatchedLinkText()
{
let smur = CssHtmlTree.l10n("rule.showUnmatchedLink");
let plural = PluralForm.get(this.propertyInfo.unmatchedRuleCount, smur);
return plural.replace("#1", this.propertyInfo.unmatchedRuleCount);
},
/**
* The action when a user clicks the 'show unmatched' link.
*/
showUnmatchedLinkClick: function PropertyView_showUnmatchedLinkClick(aEvent)
{
this.showUnmatched = true;
CssHtmlTree.processTemplate(this.templateRules, this.rules, this);
aEvent.preventDefault();
},
};
/**
* A container to view us easy access to display data from a CssRule
*/
function SelectorView(aSelectorInfo)
{
this.selectorInfo = aSelectorInfo;
this._cacheStatusNames();
}
/**
* Decode for cssInfo.rule.status
* @see SelectorView.prototype._cacheStatusNames
* @see CssLogic.STATUS
*/
SelectorView.STATUS_NAMES = [
// "Unmatched", "Parent Match", "Matched", "Best Match"
];
SelectorView.CLASS_NAMES = [
"unmatched", "parentmatch", "matched", "bestmatch"
];
SelectorView.prototype = {
/**
* Cache localized status names.
*
* These statuses are localized inside the styleinspector.properties string bundle.
* @see CssLogic.jsm - the CssLogic.STATUS array.
*
* @return {void}
*/
_cacheStatusNames: function SelectorView_cacheStatusNames()
{
if (SelectorView.STATUS_NAMES.length) {
return;
}
for (let status in CssLogic.STATUS) {
let i = CssLogic.STATUS[status];
if (i > -1) {
let value = CssHtmlTree.l10n("rule.status." + status);
// Replace normal spaces with non-breaking spaces
SelectorView.STATUS_NAMES[i] = value.replace(/ /g, '\u00A0');
}
}
},
/**
* A localized version of cssRule.status
*/
get statusText()
{
return SelectorView.STATUS_NAMES[this.selectorInfo.status];
},
/**
* Get class name for selector depending on status
*/
get statusClass()
{
return SelectorView.CLASS_NAMES[this.selectorInfo.status];
},
/**
* A localized Get localized human readable info
*/
humanReadableText: function SelectorView_humanReadableText(aElement)
{
if (CssHtmlTree.isRTL()) {
return this.selectorInfo.value + " \u2190 " + this.text(aElement);
} else {
return this.text(aElement) + " \u2192 " + this.selectorInfo.value;
}
},
text: function SelectorView_text(aElement) {
let result = this.selectorInfo.selector.text;
if (this.selectorInfo.elementStyle) {
if (this.selectorInfo.sourceElement == this.win.InspectorUI.selection) {
result = "this";
} else {
result = CssLogic.getShortName(this.selectorInfo.sourceElement);
aElement.parentNode.querySelector(".rule-link > a").
addEventListener("click", function(aEvent) {
this.win.InspectorUI.inspectNode(this.selectorInfo.sourceElement);
aEvent.preventDefault();
}, false);
}
result += ".style";
}
return result;
},
};

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -0,0 +1,55 @@
#
# ***** 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 HUDService code.
#
# The Initial Developer of the Original Code is Mozilla Corporation.
#
# Portions created by the Initial Developer are Copyright (C) 2010
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Mike Ratcliffe <mratcliffe@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 *****
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
ifdef ENABLE_TESTS
ifneq (mobile,$(MOZ_BUILD_APP))
DIRS += test
endif
endif
include $(topsrcdir)/config/rules.mk
libs::
$(NSINSTALL) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools

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

@ -0,0 +1,182 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set 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 Inspector Module.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mike Ratcliffe <mratcliffe@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 ***** */
const Cu = Components.utils;
const Ci = Components.interfaces;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
var EXPORTED_SYMBOLS = ["StyleInspector"];
var StyleInspector = {
/**
* Is the Style Inspector enabled?
* @returns {Boolean} true or false
*/
get isEnabled()
{
return Services.prefs.getBoolPref("devtools.styleinspector.enabled");
},
createPanel: function SI_createPanel()
{
let win = Services.wm.getMostRecentWindow("navigator:browser");
let popupSet = win.document.getElementById("mainPopupSet");
let ns = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
let panel = win.document.createElementNS(ns, "panel");
panel.setAttribute("orient", "vertical");
panel.setAttribute("ignorekeys", "true");
panel.setAttribute("noautofocus", "true");
panel.setAttribute("noautohide", "true");
panel.setAttribute("titlebar", "normal");
panel.setAttribute("close", "true");
panel.setAttribute("label", StyleInspector.l10n("panelTitle"));
// size panel to 200px wide by half browser height - 60.
let contentWindow = win.gBrowser.selectedBrowser.contentWindow;
panel.setAttribute("width", 200);
panel.setAttribute("height", contentWindow.outerHeight / 2 - 60);
let vbox = win.document.createElement("vbox");
vbox.setAttribute("flex", "1");
panel.appendChild(vbox);
let iframe = win.document.createElementNS(ns, "iframe");
iframe.setAttribute("flex", "1");
iframe.setAttribute("tooltip", "aHTMLTooltip");
iframe.setAttribute("src", "chrome://browser/content/csshtmltree.xhtml");
vbox.appendChild(iframe);
let hbox = win.document.createElement("hbox");
hbox.setAttribute("class", "resizerbox");
vbox.appendChild(hbox);
let spacer = win.document.createElement("spacer");
spacer.setAttribute("flex", "1");
hbox.appendChild(spacer);
let resizer = win.document.createElement("resizer");
resizer.setAttribute("dir", "bottomend");
hbox.appendChild(resizer);
popupSet.appendChild(panel);
panel.addEventListener("popupshown", function SI_popup_shown() {
if (!this.cssHtmlTree) {
this.cssLogic = new CssLogic();
this.cssHtmlTree = new CssHtmlTree(iframe, this.cssLogic, this);
}
this.cssLogic.highlight(this.selectedNode);
this.cssHtmlTree.highlight(this.selectedNode);
Services.obs.notifyObservers(null, "StyleInspector-opened", null);
}, false);
panel.addEventListener("popuphidden", function SI_popup_hidden() {
Services.obs.notifyObservers(null, "StyleInspector-closed", null);
}, false);
/**
* Check if the style inspector is open
*/
panel.isOpen = function SI_isOpen()
{
return this.state && this.state == "open";
};
/**
* Select a node to inspect in the Style Inspector panel
*
* @param aNode The node to inspect
*/
panel.selectNode = function SI_selectNode(aNode)
{
this.selectedNode = aNode;
if (this.isOpen()) {
this.cssLogic.highlight(aNode);
this.cssHtmlTree.highlight(aNode);
} else {
let win = Services.wm.getMostRecentWindow("navigator:browser");
this.openPopup(win.gBrowser.selectedBrowser, "end_before", 0, 0, false, false);
}
};
/**
* Is the Style Inspector initialized?
* @returns {Boolean} true or false
*/
function isInitialized()
{
return panel.cssLogic && panel.cssHtmlTree;
}
return panel;
},
/**
* Memonized lookup of a l10n string from a string bundle.
* @param {string} aName The key to lookup.
* @returns A localized version of the given key.
*/
l10n: function SI_l10n(aName)
{
try {
return _strings.GetStringFromName(aName);
} catch (ex) {
Services.console.logStringMessage("Error reading '" + aName + "'");
throw new Error("l10n error with " + aName);
}
},
};
XPCOMUtils.defineLazyGetter(this, "_strings", function() Services.strings
.createBundle("chrome://browser/locale/styleinspector.properties"));
XPCOMUtils.defineLazyGetter(this, "CssLogic", function() {
let tmp = {};
Cu.import("resource:///modules/devtools/CssLogic.jsm", tmp);
return tmp.CssLogic;
});
XPCOMUtils.defineLazyGetter(this, "CssHtmlTree", function() {
let tmp = {};
Cu.import("resource:///modules/devtools/CssHtmlTree.jsm", tmp);
return tmp.CssHtmlTree;
});

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

@ -0,0 +1,158 @@
<!DOCTYPE html [
<!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
%htmlDTD;
<!ENTITY % inspectorDTD SYSTEM "chrome://browser/locale/styleinspector.dtd">
%inspectorDTD;
<!ELEMENT loop ANY>
<!ATTLIST li foreach CDATA #IMPLIED>
<!ATTLIST div foreach CDATA #IMPLIED>
<!ATTLIST loop foreach CDATA #IMPLIED>
<!ATTLIST a target CDATA #IMPLIED>
<!ATTLIST a __pathElement CDATA #IMPLIED>
<!ATTLIST div _id CDATA #IMPLIED>
<!ATTLIST div save CDATA #IMPLIED>
<!ATTLIST table save CDATA #IMPLIED>
<!ATTLIST loop if CDATA #IMPLIED>
<!ATTLIST tr if CDATA #IMPLIED>
]>
<!-- ***** 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 Inspector Module.
-
- The Initial Developer of the Original Code is The Mozilla Foundation.
- Portions created by the Initial Developer are Copyright (C) 2011
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Joe Walker (jwalker@mozilla.com) (original author)
- Mihai Șucan <mihai.sucan@gmail.com>
- Michael Ratcliffe <mratcliffe@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 LGPL or the GPL. 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 ***** -->
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<head>
<meta http-equiv="Content-Type"
content="application/xhtml+xml; charset=UTF-8" />
<link rel="stylesheet" type="text/css"
href="chrome://browser/skin/devtools/csshtmltree.css" />
</head>
<body role="application">
<!-- The output from #templateRoot (below) is inserted here. -->
<div id="root">
</div>
<!--
To visually debug the templates without running firefox, alter the display:none
-->
<div style="display:none;">
<!--
templateRoot sits at the top of the window showing what we're looking at.
For data it needs an instance of CssHtmlTree.
-->
<div id="templateRoot">
<p class="path">
<label dir="${getRTLAttr}">&lookingAtLabel;</label>
<ol>
<li foreach="item in ${pathElements}" dir="${getRTLAttr}">
<a href="#" onclick="${pathClick}" __pathElement="${item.element}">
${__element.pathElement = item.element; item.display}
</a>
</li>
</ol>
</p>
<div _id="groups">
<div foreach="group in ${styleGroups}" class="group" save="${group.element}" dir="${getRTLAttr}">
<h1 onclick="${group.click}" dir="${getRTLAttr}">
${group.localName}
<div class="groupexpander"></div>
</h1>
<div save="${group.properties}"></div>
</div>
</div>
</div>
<!--
A templateProperties sits inside each templateGroups to show the properties
themselves. Each needs data like this:
{
property: [ ..., ] // Array of PropertyViews from CssHtmlTree.jsm
}
-->
<div id="templateProperties">
<div foreach="property in ${propertyViews}" class="property-view" save="${property.element}" dir="${getRTLAttr}">
<div class="property-header" onclick="${property.click}">
<span class="property-name" dir="${getRTLAttr}">
<a class="link" target="_blank" title="&helpLinkTitle;"
href="${property.link}">${property.name}</a>
</span>
<span class="property-value" dir="ltr">${property.value}</span>
<span class="link" dir="${getRTLAttr}">
${property.ruleTitle(__element)}<div class="expander"></div>
</span>
</div>
<table class="rules" save="${property.rules}" dir="${getRTLAttr}"></table>
</div>
</div>
<!--
A templateRules sits inside each templateProperties showing the list of rules
that affect that property. Each needs data like this:
{
selectors: ..., // from cssLogic.getPropertyInfo(x).[un]matchedSelectors
statusText: function(status) {}, // convert rule.status to readable text
showUnmatchedRules: true / false, // show a "more unmatched rules" link
showUnmatchedRulesClick: function() {}, // click event handler for the
"show more unmatched rules"
}
This is a template so the parent does not need to be a table, except that
using a div as the parent causes the DOM to muck with the tr elements
-->
<table id="templateRules">
<loop foreach="selector in ${selectorViews}" if="${selector.selectorInfo.sheetAllowed}">
<tr>
<td dir="ltr" class="rule-text ${selector.statusClass}">
${selector.humanReadableText(__element)}
</td>
<td class="rule-link">
<a target="_blank" href="view-source:${selector.selectorInfo.href}" class="link"
title="${selector.selectorInfo.href}">${selector.selectorInfo.source}</a>
</td>
</tr>
</loop>
<tr if="${showUnmatchedLink}">
<td colspan="4">
<a href="#" onclick="${showUnmatchedLinkClick}"
class="link">${showUnmatchedLinkText}</a>
</td>
</tr>
</table>
</div>
</body>
</html>

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

@ -0,0 +1,48 @@
#
# ***** 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 Style Inspector code.
#
# The Initial Developer of the Original Code is
# Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2010
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Mike Ratcliffe <mratcliffe@mozilla.com> (Original author)
#
# 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@
include $(DEPTH)/config/autoconf.mk
DIRS = browser
include $(topsrcdir)/config/rules.mk

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

@ -0,0 +1,62 @@
#
# ***** 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 Style Inspector code.
#
# The Initial Developer of the Original Code is
# Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2010
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Mike Ratcliffe <mratcliffe@mozilla.com> (Original author)
#
# 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/styleinspector/test/browser
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_BROWSER_TEST_FILES = \
browser_styleinspector.js \
browser_styleinspector_webconsole.js \
head.js \
$(NULL)
_BROWSER_TEST_PAGES = \
browser_styleinspector_webconsole.htm \
$(NULL)
libs:: $(_BROWSER_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
libs:: $(_BROWSER_TEST_PAGES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)

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

@ -0,0 +1,145 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that the style inspector works properly
let doc;
let stylePanel;
function createDocument()
{
doc.body.innerHTML = '<style type="text/css"> ' +
'span { font-variant: small-caps; color: #000000; } ' +
'.nomatches {color: #ff0000;}</style> <div id="first" style="margin: 10em; ' +
'font-size: 14pt; font-family: helvetica, sans-serif; color: #AAA">\n' +
'<h1>Some header text</h1>\n' +
'<p id="salutation" style="font-size: 12pt">hi.</p>\n' +
'<p id="body" style="font-size: 12pt">I am a test-case. This text exists ' +
'solely to provide some things to <span style="color: yellow">' +
'highlight</span> and <span style="font-weight: bold">count</span> ' +
'style list-items in the box at right. If you are reading this, ' +
'you should go do something else instead. Maybe read a book. Or better ' +
'yet, write some test-cases for another bit of code. ' +
'<span style="font-style: italic">Maybe more inspector test-cases!</span></p>\n' +
'<p id="closing">end transmission</p>\n' +
'<p>Inspect using inspectstyle(document.querySelectorAll("span")[0])</p>' +
'</div>';
doc.title = "Style Inspector Test";
ok(window.StyleInspector, "StyleInspector exists");
ok(StyleInspector.isEnabled, "style inspector preference is enabled");
stylePanel = StyleInspector.createPanel();
Services.obs.addObserver(runStyleInspectorTests, "StyleInspector-opened", false);
stylePanel.openPopup(gBrowser.selectedBrowser, "end_before", 0, 0, false, false);
}
function runStyleInspectorTests()
{
Services.obs.removeObserver(runStyleInspectorTests, "StyleInspector-opened", false);
ok(stylePanel.isOpen(), "style inspector is open");
checkForNewProperties();
var spans = doc.querySelectorAll("span");
ok(spans, "captain, we have the spans");
let htmlTree = stylePanel.cssHtmlTree;
for (var i = 0, numSpans = spans.length; i < numSpans; i++) {
stylePanel.selectNode(spans[i]);
is(spans[i], htmlTree.viewedElement,
"style inspector node matches the selected node");
is(htmlTree.viewedElement, stylePanel.cssLogic.viewedElement,
"cssLogic node matches the cssHtmlTree node");
// The Fonts and Color group.
ok(groupRuleCount(0) > 0, "we have rules for the current span");
}
SI_CheckProperty();
Services.obs.addObserver(finishUp, "StyleInspector-closed", false);
stylePanel.hidePopup();
}
function checkForNewProperties()
{
let htmlTree = stylePanel.cssHtmlTree;
htmlTree.createStyleGroupViews();
let otherProps = htmlTree._getPropertiesByGroup().other;
let otherPlusUnknownProps = htmlTree.propertiesByGroup.other;
let missingProps = [];
for each (let prop in otherPlusUnknownProps) {
if (otherProps.indexOf(prop) == -1) {
missingProps.push(prop);
}
}
if (missingProps.length > 0) {
let n = 1;
let msg = "The following css properties need to be categorized in " +
"CssHtmlTree.getPropertiesByGroup():\r\n";
missingProps.forEach(function BSI_buildMissingProps(aProp) {
msg += " " + (n++) + ". " + aProp + "\n";
});
ok(false, msg);
}
}
function SI_CheckProperty()
{
let group = stylePanel.cssHtmlTree.styleGroups[0];
let cssLogic = stylePanel.cssLogic;
let propertyInfo = cssLogic.getPropertyInfo("color");
ok(propertyInfo.matchedRuleCount > 0, "color property has matching rules");
ok(propertyInfo.unmatchedRuleCount > 0, "color property has unmatched rules");
}
function groupRuleCount(groupId)
{
let groupRules = 0;
let group = stylePanel.cssHtmlTree.styleGroups[groupId];
ok(group, "we have a StyleGroupView");
ok(group.tree, "we have the CssHtmlTree object");
let cssLogic = stylePanel.cssLogic;
ok(cssLogic, "we have the CssLogic object");
// we use the click method to populate the groups properties
group.click();
ok(group.properties.childElementCount > 0, "the StyleGroupView has properties");
group.propertyViews.forEach(function(property) {
groupRules += cssLogic.getPropertyInfo(property.name).matchedRuleCount;
});
return groupRules;
}
function finishUp()
{
Services.obs.removeObserver(finishUp, "StyleInspector-closed", false);
ok(!stylePanel.isOpen(), "style inspector is closed");
doc = stylePanel = null;
gBrowser.removeCurrentTab();
finish();
}
function test()
{
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function(evt) {
gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
doc = content.document;
waitForFocus(createDocument, content);
}, true);
content.location = "data:text/html,basic style inspector tests";
}

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

@ -0,0 +1,185 @@
<!DOCTYPE HTML>
<html dir="ltr" xml:lang="en-US" lang="en-US"><head>
<title>Style inspector test</title>
<style>
.text {
font-family: sans-serif;
}
.container > .text {
font-family: serif;
}
.text2 {
font-family: sans-serif;
}
.text3 {
font-size: 100px;
}
.text[dir=rtl] {
font-family: monospace;
}
.container .text {
font-family: fantasy;
}
#container .text {
font-family: fantasy;
}
.container > .text {
font-family: cursive;
}
#container > .text {
font-family: cursive;
}
#container > .dummy, #container > .dummy2 {
font-family: cursive;
}
div {
font-family: fantasy;
}
#container {
font-family: fantasy;
}
#container > span {
font-family: cursive;
}
#container .dummy {
font-family: fantasy;
}
html + .dummy {
font-family: fantasy;
}
span + span {
font-family: fantasy;
}
span[id=text] {
font-family: cursive;
}
span[att=glue] {
font-family: cursive;
}
span::before {
font-family: cursive;
content: "START ";
}
span::after {
font-family: cursive;
content: " END";
}
spawn::before {
font-family: cursive;
content: "START ";
}
spawn::after {
font-family: cursive;
content: " END";
}
a:link {
font-family: sans-serif;
}
.link:link {
font-family: fantasy;
}
a:visited {
font-family: sans-serif;
}
.link:visited {
font-family: fantasy;
}
a:active {
font-family: sans-serif;
}
.link:active {
font-family: fantasy;
}
a:hover {
font-family: sans-serif;
}
.link:hover {
font-family: fantasy;
}
a:focus {
font-family: sans-serif;
outline: 5px solid #0f0;
}
.link:focus {
font-family: fantasy;
}
span::first-letter {
font-family: sans-serif;
}
.text::first-letter {
font-family: fantasy;
}
span::first-line {
font-family: sans-serif;
}
.text::first-line {
font-family: fantasy;
}
#container:first-child {
font-family: sans-serif;
}
div:first-child {
font-family: fantasy;
}
span:lang(en) {
font-family: sans-serif;
}
span:lang(it) {
font-family: fantasy;
}
html::selection {
background-color: #f00;
font-family: fantasy;
}
</style>
</head>
<body>
<h2>font-size</h2>
<div id="container">
<span id="text" lang="en" class="text">Use inspectstyle($('text')) to inspect me</span><br />
<span id="text2" class="text2">Use inspectstyle($('text2'))</span><br />
<a class="link" href="#">Some Link</a>
<h2>font-family has a single unmatched rule</h2>
</div>
</body>
</html>

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

@ -0,0 +1,194 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* ***** 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 DevTools test code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Michael Ratcliffe <mratcliffe@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 ***** */
// Tests that inspectstyle(node) works properly
const TEST_URI = "http://example.com/browser/browser/devtools/styleinspector/test/browser/browser_styleinspector_webconsole.htm";
let doc;
let jsterm;
let hudBox;
let stylePanels = [];
function test() {
addTab(TEST_URI);
browser.addEventListener("DOMContentLoaded", prepConsole, false);
}
function prepConsole() {
browser.removeEventListener("DOMContentLoaded", prepConsole, false);
doc = content.document;
openConsole();
ok(window.StyleInspector, "StyleInspector exists");
let hud = HUDService.getHudByWindow(content);
ok(hud, "we have a console");
hudBox = hud.HUDBox;
ok(hudBox, "we have the console display");
jsterm = hud.jsterm;
ok(jsterm, "we have a jsterm");
openStyleInspector1();
}
function openStyleInspector1() {
info("opening style inspector instance 1");
Services.obs.addObserver(openStyleInspector2, "StyleInspector-opened", false);
jsterm.execute("inspectstyle($('text'))");
}
function openStyleInspector2() {
Services.obs.removeObserver(openStyleInspector2, "StyleInspector-opened", false);
info("opening style inspector instance 2");
Services.obs.addObserver(openStyleInspector3, "StyleInspector-opened", false);
jsterm.execute("inspectstyle($('text2'))");
}
function openStyleInspector3() {
Services.obs.removeObserver(openStyleInspector3, "StyleInspector-opened", false);
info("opening style inspector instance 3");
Services.obs.addObserver(teststylePanels, "StyleInspector-opened", false);
jsterm.execute("inspectstyle($('container'))");
}
function teststylePanels() {
Services.obs.removeObserver(teststylePanels, "StyleInspector-opened", false);
info("adding style inspector instances to stylePanels array");
let popupSet = document.getElementById("mainPopupSet");
let len = popupSet.childNodes.length - 3;
stylePanels.push(popupSet.childNodes[len++]);
stylePanels.push(popupSet.childNodes[len++]);
stylePanels.push(popupSet.childNodes[len++]);
let eltArray = [
doc.getElementById("text"),
doc.getElementById("text2"),
doc.getElementById("container")
];
info("looping through array to check initialization");
for (let i = 0, max = stylePanels.length; i < max; i++) {
ok(stylePanels[i], "style inspector instance " + i +
" correctly initialized");
ok(stylePanels[i].isOpen(), "style inspector " + i + " is open");
let htmlTree = stylePanels[i].cssHtmlTree;
is(eltArray[i], htmlTree.viewedElement,
"style inspector node matches the selected node (id=" +
eltArray[i].id + ")");
is(htmlTree.viewedElement, stylePanels[i].cssLogic.viewedElement,
"cssLogic node matches the cssHtmlTree node (id=" + eltArray[i].id + ")");
ok(groupRuleCount(0, stylePanels[i]) > 0,
"we have rules for the current node (id=" + eltArray[i].id + ")");
}
info("hiding stylePanels[1]");
Services.obs.addObserver(styleInspectorClosedByHide,
"StyleInspector-closed", false);
stylePanels[1].hidePopup();
}
function styleInspectorClosedByHide()
{
Services.obs.removeObserver(styleInspectorClosedByHide, "StyleInspector-closed", false);
ok(stylePanels[0].isOpen(), "instance stylePanels[0] is still open");
ok(!stylePanels[1].isOpen(), "instance stylePanels[1] is hidden");
ok(stylePanels[2].isOpen(), "instance stylePanels[2] is still open");
info("closing web console");
Services.obs.addObserver(styleInspectorClosedFromConsole1,
"StyleInspector-closed", false);
closeConsole();
}
function styleInspectorClosedFromConsole1()
{
Services.obs.removeObserver(styleInspectorClosedFromConsole1,
"StyleInspector-closed", false);
info("Style Inspector 1 closed");
Services.obs.addObserver(styleInspectorClosedFromConsole2,
"StyleInspector-closed", false);
}
function styleInspectorClosedFromConsole2()
{
Services.obs.removeObserver(styleInspectorClosedFromConsole2,
"StyleInspector-closed", false);
info("Style Inspector 2 closed");
executeSoon(cleanUp);
}
function cleanUp()
{
let popupSet = document.getElementById("mainPopupSet");
ok(!popupSet.lastChild.hasAttribute("hudToolId"),
"all style inspector panels are now detached and ready for garbage collection");
info("cleaning up");
doc = hudBox = stylePanels = jsterm = null;
finishTest();
}
function groupRuleCount(groupId, aStylePanel)
{
let groupRules = 0;
let group = aStylePanel.cssHtmlTree.styleGroups[groupId];
ok(group, "we have a StyleGroupView");
ok(group.tree, "we have the CssHtmlTree object");
let cssLogic = aStylePanel.cssLogic;
ok(cssLogic, "we have the CssLogic object");
// we use the click event to populate the groups properties
group.click();
ok(group.properties.childElementCount > 0, "the StyleGroupView has properties");
group.propertyViews.forEach(function(property) {
groupRules += cssLogic.getPropertyInfo(property.name).matchedRuleCount;
});
return groupRules;
}

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

@ -0,0 +1,185 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* ***** 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 DevTools test code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mike Ratcliffe <mratcliffe@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 ***** */
Cu.import("resource:///modules/devtools/StyleInspector.jsm");
Cu.import("resource://gre/modules/HUDService.jsm");
function log(aMsg)
{
dump("*** WebConsoleTest: " + aMsg + "\n");
}
function pprint(aObj)
{
for (let prop in aObj) {
if (typeof aObj[prop] == "function") {
log("function " + prop);
}
else {
log(prop + ": " + aObj[prop]);
}
}
}
let tab, browser, hudId, hud, hudBox, filterBox, outputNode, cs;
function addTab(aURL)
{
gBrowser.selectedTab = gBrowser.addTab();
content.location = aURL;
tab = gBrowser.selectedTab;
browser = gBrowser.getBrowserForTab(tab);
}
function afterAllTabsLoaded(callback, win) {
win = win || window;
let stillToLoad = 0;
function onLoad() {
this.removeEventListener("load", onLoad, true);
stillToLoad--;
if (!stillToLoad)
callback();
}
for (let a = 0; a < win.gBrowser.tabs.length; a++) {
let browser = win.gBrowser.tabs[a].linkedBrowser;
if (browser.contentDocument.readyState != "complete") {
stillToLoad++;
browser.addEventListener("load", onLoad, true);
}
}
if (!stillToLoad)
callback();
}
/**
* Check if a log entry exists in the HUD output node.
*
* @param {Element} aOutputNode
* the HUD output node.
* @param {string} aMatchString
* the string you want to check if it exists in the output node.
* @param {string} aMsg
* the message describing the test
* @param {boolean} [aOnlyVisible=false]
* find only messages that are visible, not hidden by the filter.
* @param {boolean} [aFailIfFound=false]
* fail the test if the string is found in the output node.
* @param {string} aClass [optional]
* find only messages with the given CSS class.
*/
function testLogEntry(aOutputNode, aMatchString, aMsg, aOnlyVisible,
aFailIfFound, aClass)
{
let selector = ".hud-msg-node";
// Skip entries that are hidden by the filter.
if (aOnlyVisible) {
selector += ":not(.hud-filtered-by-type)";
}
if (aClass) {
selector += "." + aClass;
}
let msgs = aOutputNode.querySelectorAll(selector);
let found = false;
for (let i = 0, n = msgs.length; i < n; i++) {
let message = msgs[i].textContent.indexOf(aMatchString);
if (message > -1) {
found = true;
break;
}
// Search the labels too.
let labels = msgs[i].querySelectorAll("label");
for (let j = 0; j < labels.length; j++) {
if (labels[j].getAttribute("value").indexOf(aMatchString) > -1) {
found = true;
break;
}
}
}
is(found, !aFailIfFound, aMsg);
}
/**
* A convenience method to call testLogEntry().
*
* @param string aString
* The string to find.
*/
function findLogEntry(aString)
{
testLogEntry(outputNode, aString, "found " + aString);
}
function openConsole()
{
HUDService.activateHUDForContext(tab);
}
function closeConsole()
{
HUDService.deactivateHUDForContext(tab);
}
function finishTest()
{
finish();
}
function tearDown()
{
try {
HUDService.deactivateHUDForContext(gBrowser.selectedTab);
}
catch (ex) {
log(ex);
}
while (gBrowser.tabs.length > 1) {
gBrowser.removeCurrentTab();
}
tab = browser = hudId = hud = filterBox = outputNode = cs = null;
}
registerCleanupFunction(tearDown);
waitForExplicitFinish();

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

@ -27,6 +27,7 @@
* Patrick Walton <pcwalton@mozilla.com>
* Julian Viereck <jviereck@mozilla.com>
* Mihai Șucan <mihai.sucan@gmail.com>
* Michael Ratcliffe <mratcliffe@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
@ -71,6 +72,12 @@ XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper",
"@mozilla.org/widget/clipboardhelper;1",
"nsIClipboardHelper");
XPCOMUtils.defineLazyGetter(this, "StyleInspector", function () {
var obj = {};
Cu.import("resource:///modules/devtools/StyleInspector.jsm", obj);
return obj.StyleInspector;
});
XPCOMUtils.defineLazyGetter(this, "NetUtil", function () {
var obj = {};
Cu.import("resource://gre/modules/NetUtil.jsm", obj);
@ -1776,6 +1783,11 @@ HUD_SERVICE.prototype =
for (let i = 0; i < panels.length; i++) {
panels[i].hidePopup();
}
panels = popupset.querySelectorAll("panel[hudToolId=" + aHUDId + "]");
for (let i = 0; i < panels.length; i++) {
panels[i].hidePopup();
popupset.removeChild(panels[i]);
}
let id = ConsoleUtils.supString(aHUDId);
Services.obs.notifyObservers(id, "web-console-destroyed", null);
@ -4396,6 +4408,37 @@ function JSTermHelper(aJSTerm)
propPanel.panel.setAttribute("hudId", aJSTerm.hudId);
};
/**
* Inspects the passed aNode in the style inspector.
*
* @param object aNode
* aNode to inspect.
* @returns void
*/
aJSTerm.sandbox.inspectstyle = function JSTH_inspectstyle(aNode)
{
let errstr = null;
aJSTerm.helperEvaluated = true;
if (!Services.prefs.getBoolPref("devtools.styleinspector.enabled")) {
errstr = HUDService.getStr("inspectStyle.styleInspectorNotEnabled");
} else if (!aNode) {
errstr = HUDService.getStr("inspectStyle.nullObjectPassed");
} else if (!(aNode instanceof Ci.nsIDOMNode)) {
errstr = HUDService.getStr("inspectStyle.mustBeDomNode");
} else if (!(aNode.style instanceof Ci.nsIDOMCSSStyleDeclaration)) {
errstr = HUDService.getStr("inspectStyle.nodeHasNoStyleProps");
}
if (!errstr) {
let stylePanel = StyleInspector.createPanel();
stylePanel.setAttribute("hudToolId", aJSTerm.hudId);
stylePanel.selectNode(aNode, true);
} else {
aJSTerm.writeOutput(errstr + "\n", CATEGORY_OUTPUT, SEVERITY_ERROR);
}
};
/**
* Prints aObject to the output.
*

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

@ -0,0 +1,10 @@
<!-- LOCALIZATION NOTE (lookingAtLabel): This is the label for the path of
- the highlighted element in the web page. This path is based on the document
- tree. -->
<!ENTITY lookingAtLabel "Looking at:">
<!-- LOCALIZATION NOTE (helpLinkTitle): For each style property
- the user can hover it and get a help link button which allows one to
- quickly jump to the documentation from the Mozilla Developer Network site.
- This is the link title shown in the hover tooltip. -->
<!ENTITY helpLinkTitle "Read the documentation for this property">

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

@ -0,0 +1,53 @@
# LOCALIZATION NOTE These strings are used inside the Style Inspector.
# LOCALIZATION NOTE (panelTitle): This is the panel title
panelTitle=Style Inspector
# LOCALIZATION NOTE (property.numberOfRules): For each style property the panel
# shows the number of rules which hold that specific property, counted from all
# of the stylesheets in the web page inspected.
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
property.numberOfRules=#1 rule;#1 rules
# LOCALIZATION NOTE (property.numberOfUnmatchedRules): Each style property is
# inside a rule. A rule is a selector that can match (or not) the highlighted
# element in the web page. The property view shows no unmatched rules. If the
# user wants to expand the property to view unmatched rules, he/she must click
# this link displayed to the right of each property.
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
property.numberOfUnmatchedRules=One unmatched rule;#1 unmatched rules
# LOCALIZATION NOTE (rule.status): For each style property the panel shows
# the rules which hold that specific property. For every rule, the rule status
# is also displayed: a rule can be the best match, a match, a parent match, or a
# rule did not match the element the user has highlighted.
rule.status.BEST=Best Match
rule.status.MATCHED=Matched
rule.status.PARENT_MATCH=Parent Match
rule.status.UNMATCHED=Unmatched
# LOCALIZATION NOTE (rule.sourceElement, rule.sourceInline): For each
# style property the panel shows the rules which hold that specific property.
# For every rule, the rule source is also displayed: a rule can come from a
# file, from the same page (inline), or from the element itself (element).
rule.sourceInline=inline
rule.sourceElement=element
# LOCALIZATION NOTE (rule.showUnmatchedLink): Each style property
# is inside a rule. A rule is a selector that can match (or not) the highlighted
# element in the web page. The property view shows only a few of the unmatched
# rules. If the user wants to see all of the unmatched rules, he/she must click
# the link displayed at the bottom of the rules table. That link shows how many
# rules are not displayed. This is the string used when the link is generated.
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
rule.showUnmatchedLink=One unmatched rule...;#1 unmatched rules...
# LOCALIZATION NOTE (group): Style properties are displayed in categories and
# these are the category names.
group.Text_Fonts_and_Color=Text, Fonts & Color
group.Background=Background
group.Dimensions=Dimensions
group.Positioning_and_Page_Flow=Positioning and Page Flow
group.Borders=Borders
group.Lists=Lists
group.Effects_and_Other=Effects and Other

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

@ -14,6 +14,8 @@
* locale/browser/browser.dtd (%chrome/browser/browser.dtd)
locale/browser/baseMenuOverlay.dtd (%chrome/browser/baseMenuOverlay.dtd)
locale/browser/browser.properties (%chrome/browser/browser.properties)
locale/browser/styleinspector.properties (%chrome/browser/styleinspector.properties)
locale/browser/styleinspector.dtd (%chrome/browser/styleinspector.dtd)
locale/browser/scratchpad.properties (%chrome/browser/scratchpad.properties)
locale/browser/scratchpad.dtd (%chrome/browser/scratchpad.dtd)
locale/browser/inspector.properties (%chrome/browser/inspector.properties)

Двоичные данные
browser/themes/gnomestripe/browser/devtools/arrows.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 933 B

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

@ -0,0 +1,236 @@
/* ***** 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 Inspector Module.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Joe Walker <jwalker@mozilla.com> (original author)
* Mihai Șucan <mihai.sucan@gmail.com>
* Michael Ratcliffe <mratcliffe@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 ***** */
body {
font-family: Lucida Grande, sans-serif;
font-size: 11px;
background: #EEE;
}
.path {
font-size: 11px;
word-spacing: -1px;
}
.path ol {
list-style: none;
margin: 0;
padding: 0;
}
.path li {
border-radius: 3px;
padding: 2px 3px;
text-shadow: #FFF 0 1px 0;
font-weight: bold;
font-size: 11px;
background: -moz-linear-gradient(top, #F6F6FF, #E3E3FF);
display: inline-block;
}
.path li:after {
content: " > ";
}
.path li:last-child {
background: -moz-linear-gradient(top, #FFC, #DD8);
}
.path li:last-child:after {
color: red;
content: "";
}
#sheetList, #sheetList menuitem {
font-size: 1em;
font-weight: normal;
}
.sheet_line input {
vertical-align: middle;
}
.sheet_line label {
cursor: pointer;
}
#header, #footer {
padding: 5px;
}
#header label {
font-weight: bold;
}
#sheets {
-moz-margin-end: 10px;
margin-top: 5px;
}
h1 {
font-size: 13px;
padding: 2px 10px;
margin: 0;
background: -moz-linear-gradient(top, #CCC, #AAA);
border-radius: 3px;
text-shadow: #FFF 0 1px 0;
cursor: pointer;
}
.property-header {
padding: 2px 5px;
background: -moz-linear-gradient(top, #F8F8F8, #E8E8E8);
color: #666;
}
.property-name, .property-value, .rule-count, .rule-unmatched {
cursor: pointer;
}
/* Take away these two :visited rules to get a core dumper */
/* See https://bugzilla.mozilla.org/show_bug.cgi?id=575675#c30 */
.link { color: #55A; }
.link:visited { color: #55A; }
a.link { text-decoration: none; cursor: pointer }
a.link:visited { text-decoration: none; }
.rule-count, .rule-unmatched {
float: right;
}
.rule-count[dir="rtl"], .rule-unmatched[dir="rtl"] {
float: left;
}
.property-view .rule-count .expander,
.property-view .rule-unmatched .expander {
width: 8px;
height: 8px;
-moz-margin-start: 5px;
display: inline-block;
background: url("chrome://browser/skin/devtools/arrows.png");
}
.property-view .rule-count .expander,
.property-view .rule-unmatched .expander {
background-position: 24px 0;
}
.property-view[dir="rtl"] .rule-count .expander,
.property-view[dir="rtl"] .rule-unmatched .expander {
background-position: 16px 0;
}
.property-view[open] .rule-count .expander,
.property-view[open] .rule-unmatched .expander {
background-position: 8px 0;
}
.property-name {
font-size: 12px;
font-weight: bold;
-moz-padding-end: 4px;
color: #000;
}
span.property-value {
-moz-padding-end: 5px;
font-size: 10px;
}
.group {
margin-top: 10px;
}
.group > h1 {
color: #333;
font-size: 11px;
}
.group .groupexpander {
width: 8px;
height: 8px;
margin-top: 2px;
background: url("chrome://browser/skin/devtools/arrows.png");
}
.group > div {
display: none;
}
.group[open] > div {
display: block;
}
.group .groupexpander {
background-position: 48px 0;
float: right;
}
.group[dir="rtl"] .groupexpander {
background-position: 40px 0;
float: left;
}
.group[open] .groupexpander {
background-position: 32px 0;
float: right;
}
.group[open][dir="rtl"] .groupexpander {
background-position: 32px 0;
float: left;
}
.group, #header, #footer {
background: #FFF;
border: 1px solid #E1E1E1;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
border-radius: 4px 4px 4px 4px;
}
.property-view > .rules {
display: none;
}
.property-view[open] > .rules {
display: table;
}
.rules {
max-height: 350px;
overflow-y: auto;
}
.rule-specificty, .rule-status {
white-space: nowrap;
}
.rule-link {
text-align: end;
}
/* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
.rule-text {
direction: ltr;
}
.resizerbox {
background-color: window;
}
.bestmatch { color: black; }
.matched { text-decoration: line-through; }
.parentmatch { color: #666; }
.unmatched { color: brown; }

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

@ -84,6 +84,8 @@ browser.jar:
skin/classic/browser/tabview/stack-expander.png (tabview/stack-expander.png)
skin/classic/browser/tabview/tabview.png (tabview/tabview.png)
skin/classic/browser/tabview/tabview.css (tabview/tabview.css)
skin/classic/browser/devtools/arrows.png (devtools/arrows.png)
skin/classic/browser/devtools/csshtmltree.css (devtools/csshtmltree.css)
#ifdef MOZ_SERVICES_SYNC
skin/classic/browser/sync-16-throbber.png
skin/classic/browser/sync-16.png

Двоичные данные
browser/themes/pinstripe/browser/devtools/arrows.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 933 B

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

@ -0,0 +1,236 @@
/* ***** 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 Inspector Module.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Joe Walker <jwalker@mozilla.com> (original author)
* Mihai Șucan <mihai.sucan@gmail.com>
* Michael Ratcliffe <mratcliffe@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 ***** */
body {
font-family: Lucida Grande, sans-serif;
font-size: 11px;
background: #EEE;
}
.path {
font-size: 11px;
word-spacing: -1px;
}
.path ol {
list-style: none;
margin: 0;
padding: 0;
}
.path li {
border-radius: 3px;
padding: 2px 3px;
text-shadow: #FFF 0 1px 0;
font-weight: bold;
font-size: 11px;
background: -moz-linear-gradient(top, #F6F6FF, #E3E3FF);
display: inline-block;
}
.path li:after {
content: " > ";
}
.path li:last-child {
background: -moz-linear-gradient(top, #FFC, #DD8);
}
.path li:last-child:after {
color: red;
content: "";
}
#sheetList, #sheetList menuitem {
font-size: 1em;
font-weight: normal;
}
.sheet_line input {
vertical-align: middle;
}
.sheet_line label {
cursor: pointer;
}
#header, #footer {
padding: 5px;
}
#header label {
font-weight: bold;
}
#sheets {
-moz-margin-end: 10px;
margin-top: 5px;
}
h1 {
font-size: 13px;
padding: 2px 10px;
margin: 0;
background: -moz-linear-gradient(top, #CCC, #AAA);
border-radius: 3px;
text-shadow: #FFF 0 1px 0;
cursor: pointer;
}
.property-header {
padding: 2px 5px;
background: -moz-linear-gradient(top, #F8F8F8, #E8E8E8);
color: #666;
}
.property-name, .property-value, .rule-count, .rule-unmatched {
cursor: pointer;
}
/* Take away these two :visited rules to get a core dumper */
/* See https://bugzilla.mozilla.org/show_bug.cgi?id=575675#c30 */
.link { color: #55A; }
.link:visited { color: #55A; }
a.link { text-decoration: none; cursor: pointer }
a.link:visited { text-decoration: none; }
.rule-count, .rule-unmatched {
float: right;
}
.rule-count[dir="rtl"], .rule-unmatched[dir="rtl"] {
float: left;
}
.property-view .rule-count .expander,
.property-view .rule-unmatched .expander {
width: 8px;
height: 8px;
-moz-margin-start: 5px;
display: inline-block;
background: url("chrome://browser/skin/devtools/arrows.png");
}
.property-view .rule-count .expander,
.property-view .rule-unmatched .expander {
background-position: 24px 0;
}
.property-view[dir="rtl"] .rule-count .expander,
.property-view[dir="rtl"] .rule-unmatched .expander {
background-position: 16px 0;
}
.property-view[open] .rule-count .expander,
.property-view[open] .rule-unmatched .expander {
background-position: 8px 0;
}
.property-name {
font-size: 12px;
font-weight: bold;
-moz-padding-end: 4px;
color: #000;
}
span.property-value {
-moz-padding-end: 5px;
font-size: 10px;
}
.group {
margin-top: 10px;
}
.group > h1 {
color: #333;
font-size: 11px;
}
.group .groupexpander {
width: 8px;
height: 8px;
margin-top: 2px;
background: url("chrome://browser/skin/devtools/arrows.png");
}
.group > div {
display: none;
}
.group[open] > div {
display: block;
}
.group .groupexpander {
background-position: 48px 0;
float: right;
}
.group[dir="rtl"] .groupexpander {
background-position: 40px 0;
float: left;
}
.group[open] .groupexpander {
background-position: 32px 0;
float: right;
}
.group[open][dir="rtl"] .groupexpander {
background-position: 32px 0;
float: left;
}
.group, #header, #footer {
background: #FFF;
border: 1px solid #E1E1E1;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
border-radius: 4px 4px 4px 4px;
}
.property-view > .rules {
display: none;
}
.property-view[open] > .rules {
display: table;
}
.rules {
max-height: 350px;
overflow-y: auto;
}
.rule-specificty, .rule-status {
white-space: nowrap;
}
.rule-link {
text-align: end;
}
/* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
.rule-text {
direction: ltr;
}
.resizerbox {
background-color: window;
}
.bestmatch { color: black; }
.matched { text-decoration: line-through; }
.parentmatch { color: #666; }
.unmatched { color: brown; }

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

@ -123,6 +123,8 @@ browser.jar:
skin/classic/browser/tabview/stack-expander.png (tabview/stack-expander.png)
skin/classic/browser/tabview/tabview.png (tabview/tabview.png)
skin/classic/browser/tabview/tabview.css (tabview/tabview.css)
skin/classic/browser/devtools/arrows.png (devtools/arrows.png)
skin/classic/browser/devtools/csshtmltree.css (devtools/csshtmltree.css)
#ifdef MOZ_SERVICES_SYNC
skin/classic/browser/sync-throbber.png
skin/classic/browser/sync-16.png

Двоичные данные
browser/themes/winstripe/browser/devtools/arrows.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 933 B

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

@ -0,0 +1,236 @@
/* ***** 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 Inspector Module.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Joe Walker <jwalker@mozilla.com> (original author)
* Mihai Șucan <mihai.sucan@gmail.com>
* Michael Ratcliffe <mratcliffe@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 ***** */
body {
font-family: Lucida Grande, sans-serif;
font-size: 11px;
background: #EEE;
}
.path {
font-size: 11px;
word-spacing: -1px;
}
.path ol {
list-style: none;
margin: 0;
padding: 0;
}
.path li {
border-radius: 3px;
padding: 2px 3px;
text-shadow: #FFF 0 1px 0;
font-weight: bold;
font-size: 11px;
background: -moz-linear-gradient(top, #F6F6FF, #E3E3FF);
display: inline-block;
}
.path li:after {
content: " > ";
}
.path li:last-child {
background: -moz-linear-gradient(top, #FFC, #DD8);
}
.path li:last-child:after {
color: red;
content: "";
}
#sheetList, #sheetList menuitem {
font-size: 1em;
font-weight: normal;
}
.sheet_line input {
vertical-align: middle;
}
.sheet_line label {
cursor: pointer;
}
#header, #footer {
padding: 5px;
}
#header label {
font-weight: bold;
}
#sheets {
-moz-margin-end: 10px;
margin-top: 5px;
}
h1 {
font-size: 13px;
padding: 2px 10px;
margin: 0;
background: -moz-linear-gradient(top, #CCC, #AAA);
border-radius: 3px;
text-shadow: #FFF 0 1px 0;
cursor: pointer;
}
.property-header {
padding: 2px 5px;
background: -moz-linear-gradient(top, #F8F8F8, #E8E8E8);
color: #666;
}
.property-name, .property-value, .rule-count, .rule-unmatched {
cursor: pointer;
}
/* Take away these two :visited rules to get a core dumper */
/* See https://bugzilla.mozilla.org/show_bug.cgi?id=575675#c30 */
.link { color: #55A; }
.link:visited { color: #55A; }
a.link { text-decoration: none; cursor: pointer }
a.link:visited { text-decoration: none; }
.rule-count, .rule-unmatched {
float: right;
}
.rule-count[dir="rtl"], .rule-unmatched[dir="rtl"] {
float: left;
}
.property-view .rule-count .expander,
.property-view .rule-unmatched .expander {
width: 8px;
height: 8px;
-moz-margin-start: 5px;
display: inline-block;
background: url("chrome://browser/skin/devtools/arrows.png");
}
.property-view .rule-count .expander,
.property-view .rule-unmatched .expander {
background-position: 24px 0;
}
.property-view[dir="rtl"] .rule-count .expander,
.property-view[dir="rtl"] .rule-unmatched .expander {
background-position: 16px 0;
}
.property-view[open] .rule-count .expander,
.property-view[open] .rule-unmatched .expander {
background-position: 8px 0;
}
.property-name {
font-size: 12px;
font-weight: bold;
-moz-padding-end: 4px;
color: #000;
}
span.property-value {
-moz-padding-end: 5px;
font-size: 10px;
}
.group {
margin-top: 10px;
}
.group > h1 {
color: #333;
font-size: 11px;
}
.group .groupexpander {
width: 8px;
height: 8px;
margin-top: 2px;
background: url("chrome://browser/skin/devtools/arrows.png");
}
.group > div {
display: none;
}
.group[open] > div {
display: block;
}
.group .groupexpander {
background-position: 48px 0;
float: right;
}
.group[dir="rtl"] .groupexpander {
background-position: 40px 0;
float: left;
}
.group[open] .groupexpander {
background-position: 32px 0;
float: right;
}
.group[open][dir="rtl"] .groupexpander {
background-position: 32px 0;
float: left;
}
.group, #header, #footer {
background: #FFF;
border: 1px solid #E1E1E1;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
border-radius: 4px 4px 4px 4px;
}
.property-view > .rules {
display: none;
}
.property-view[open] > .rules {
display: table;
}
.rules {
max-height: 350px;
overflow-y: auto;
}
.rule-specificty, .rule-status {
white-space: nowrap;
}
.rule-link {
text-align: end;
}
/* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
.rule-text {
direction: ltr;
}
.resizerbox {
background-color: window;
}
.bestmatch { color: black; }
.matched { text-decoration: line-through; }
.parentmatch { color: #666; }
.unmatched { color: brown; }

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

@ -106,6 +106,8 @@ browser.jar:
skin/classic/browser/tabview/tabview.png (tabview/tabview.png)
skin/classic/browser/tabview/tabview-inverted.png (tabview/tabview-inverted.png)
skin/classic/browser/tabview/tabview.css (tabview/tabview.css)
skin/classic/browser/devtools/arrows.png (devtools/arrows.png)
skin/classic/browser/devtools/csshtmltree.css (devtools/csshtmltree.css)
#ifdef MOZ_SERVICES_SYNC
skin/classic/browser/sync-throbber.png
skin/classic/browser/sync-16.png

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

@ -115,6 +115,23 @@ NetworkPanel.imageSizeDeltaDurationMS=%Sx%Spx, Δ%Sms
NetworkPanel.responseBodyUnableToDisplay.content=Unable to display responses of type "%S"
ConsoleAPIDisabled=The Web Console logging API (console.log, console.info, console.warn, console.error) has been disabled by a script on this page.
# LOCALIZATION NOTE (inspectStyle.nullObjectPassed):
# This message is returned when a null object is passed in to inspectstyle()
inspectStyle.nullObjectPassed=Object is null
# LOCALIZATION NOTE (inspectStyle.mustBeDomNode):
# This message is returned when a non-DOM node is passed in to inspectstyle()
inspectStyle.mustBeDomNode=Object must be a valid DOM node
# LOCALIZATION NOTE (inspectStyle.nodeHasNoStyleProps):
# This message is returned when an unstyleable object is passed in to inspectstyle()
inspectStyle.nodeHasNoStyleProps=Object cannot be styled
# LOCALIZATION NOTE (inspectStyle.styleInspectorNotEnabled):
# This message is returned when devtools.styleinspector.enabled is not set to
# true
inspectStyle.styleInspectorNotEnabled=The style inspector is not enabled. Please set the option devtools.styleinspector.enabled to true in about:config to use this command.
# LOCALIZATION NOTE (webConsolePosition): The label shown for the menu which
# allows the user to toggle between the Web Console positioning types.
webConsolePosition=Position