Bug 677930 - Style Inspector: make URLs clickable.

This commit is contained in:
Brian Grinstead 2013-04-19 16:30:33 -05:00
Родитель c094610e66
Коммит 71085f2b8c
8 изменённых файлов: 226 добавлений и 9 удалений

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

@ -744,6 +744,24 @@ CssLogic.isContentStylesheet = function CssLogic_isContentStylesheet(aSheet)
return false;
};
/**
* Get a source for a stylesheet, taking into account embedded stylesheets
* for which we need to use document.defaultView.location.href rather than
* sheet.href
*
* @param {CSSStyleSheet} aSheet the DOM object for the style sheet.
* @return {string} the address of the stylesheet.
*/
CssLogic.href = function CssLogic_href(aSheet)
{
let href = aSheet.href;
if (!href) {
href = aSheet.ownerNode.ownerDocument.location;
}
return href;
};
/**
* Return a shortened version of a style sheet's source.
*
@ -927,21 +945,17 @@ CssSheet.prototype = {
},
/**
* Get a source for a stylesheet, taking into account embedded stylesheets
* for which we need to use document.defaultView.location.href rather than
* sheet.href
* Get a source for a stylesheet, using CssLogic.href
*
* @return {string} the address of the stylesheet.
*/
get href()
{
if (!this._href) {
this._href = this.domSheet.href;
if (!this._href) {
this._href = this.domSheet.ownerNode.ownerDocument.location;
}
if (this._href) {
return this._href;
}
this._href = CssLogic.href(this.domSheet);
return this._href;
},

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

@ -24,6 +24,12 @@ const CSS_LINE_RE = /(?:[^;\(]*(?:\([^\)]*?\))?[^;\(]*)*;?/g;
// Used to parse a single property line.
const CSS_PROP_RE = /\s*([^:\s]*)\s*:\s*(.*?)\s*(?:! (important))?;?$/;
// Used to parse an external resource from a property value
const CSS_RESOURCE_RE = /url\([\'\"]?(.*?)[\'\"]?\)/;
const IOService = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/devtools/CssLogic.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
@ -1321,6 +1327,12 @@ function TextPropertyEditor(aRuleEditor, aProperty)
this.prop = aProperty;
this.prop.editor = this;
let sheet = this.prop.rule.sheet;
let href = sheet ? CssLogic.href(sheet) : null;
if (href) {
this.sheetURI = IOService.newURI(href, null, null);
}
this._onEnableClicked = this._onEnableClicked.bind(this);
this._onExpandClicked = this._onExpandClicked.bind(this);
this._onStartEditing = this._onStartEditing.bind(this);
@ -1436,6 +1448,36 @@ TextPropertyEditor.prototype = {
});
},
/**
* Resolve a URI based on the rule stylesheet
* @param {string} relativePath the path to resolve
* @return {string} the resolved path.
*/
resolveURI: function(relativePath)
{
if (this.sheetURI) {
relativePath = this.sheetURI.resolve(relativePath);
}
return relativePath;
},
/**
* Check the property value to find an external resource (if any).
* @return {string} the URI in the property value, or null if there is no match.
*/
getResourceURI: function()
{
let val = this.prop.value;
let uriMatch = CSS_RESOURCE_RE.exec(val);
let uri = null;
if (uriMatch && uriMatch[1]) {
uri = uriMatch[1];
}
return uri;
},
/**
* Populate the span based on changes to the TextProperty.
*/
@ -1464,7 +1506,32 @@ TextPropertyEditor.prototype = {
if (this.prop.priority) {
val += " !" + this.prop.priority;
}
this.valueSpan.textContent = val;
// Treat URLs differently than other properties.
// Allow the user to click a link to the resource and open it.
let resourceURI = this.getResourceURI();
if (resourceURI) {
this.valueSpan.textContent = "";
appendText(this.valueSpan, val.split(resourceURI)[0]);
let a = createChild(this.valueSpan, "a", {
target: "_blank",
class: "theme-link",
textContent: resourceURI,
href: this.resolveURI(resourceURI)
});
a.addEventListener("click", function(aEvent) {
// Clicks within the link shouldn't trigger editing.
aEvent.stopPropagation();
}, false);
appendText(this.valueSpan, val.split(resourceURI)[1]);
} else {
this.valueSpan.textContent = val;
}
this.warning.hidden = this._validate();
let store = this.prop.rule.elementStyle.store;

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

@ -28,6 +28,10 @@
padding-right: 15px;
}
.ruleview-propertycontainer a {
cursor: pointer;
}
.ruleview-computedlist:not(.styleinspector-open),
.ruleview-warning[hidden] {
display: none;

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

@ -37,6 +37,7 @@ MOCHITEST_BROWSER_FILES = \
browser_bug722691_rule_view_increment.js \
browser_computedview_734259_style_editor_link.js \
browser_computedview_copy.js\
browser_styleinspector_bug_677930_urls_clickable.js \
head.js \
$(NULL)
@ -50,6 +51,10 @@ MOCHITEST_BROWSER_FILES += \
browser_bug705707_is_content_stylesheet.xul \
browser_bug705707_is_content_stylesheet_xul.css \
browser_bug722196_identify_media_queries.html \
browser_styleinspector_bug_677930_urls_clickable.html \
browser_styleinspector_bug_677930_urls_clickable \
browser_styleinspector_bug_677930_urls_clickable/browser_styleinspector_bug_677930_urls_clickable.css \
test-image.png \
$(NULL)
include $(topsrcdir)/config/rules.mk

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

@ -0,0 +1,21 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<head>
<link href="./browser_styleinspector_bug_677930_urls_clickable/browser_styleinspector_bug_677930_urls_clickable.css" rel="stylesheet" type="text/css">
</head>
<body>
<div class="relative">Background image with relative path (loaded from external css)</div>
<div class="absolute">Background image with absolute path (loaded from external css)</div>
<div class="base64">Background image with base64 url (loaded from external css)</div>
<div class="inline" style="background: url(test-image.png);">Background image with relative path (loaded from style attribute)</div>';
<div class="noimage">No background image :(</div>
</body>
</html>

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

@ -0,0 +1,97 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests to make sure that URLs are clickable in the rule view
let doc;
let computedView;
let inspector;
const BASE_URL = "http://example.com/browser/browser/" +
"devtools/styleinspector/test/";
const TEST_URI = BASE_URL +
"browser_styleinspector_bug_677930_urls_clickable.html";
const TEST_IMAGE = BASE_URL + "test-image.png";
const BASE_64_URL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
function createDocument()
{
doc.title = "Style Inspector URL Clickable test";
openInspector(function(aInspector) {
inspector = aInspector;
executeSoon(selectNode);
});
}
function selectNode(aInspector)
{
let sidebar = inspector.sidebar;
let iframe = sidebar._tabbox.querySelector(".iframe-ruleview");
let contentDoc = iframe.contentWindow.document;
let relative = doc.querySelector(".relative");
let absolute = doc.querySelector(".absolute");
let inline = doc.querySelector(".inline");
let base64 = doc.querySelector(".base64");
let noimage = doc.querySelector(".noimage");
ok(relative, "captain, we have the relative div");
ok(absolute, "captain, we have the absolute div");
ok(inline, "captain, we have the inline div");
ok(base64, "captain, we have the base64 div");
ok(noimage, "captain, we have the noimage div");
inspector.selection.setNode(relative);
is(inspector.selection.node, relative, "selection matches the relative element");
let relativeLink = contentDoc.querySelector(".ruleview-propertycontainer a");
ok (relativeLink, "Link exists for relative node");
ok (relativeLink.getAttribute("href"), TEST_IMAGE);
inspector.selection.setNode(absolute);
is(inspector.selection.node, absolute, "selection matches the absolute element");
let absoluteLink = contentDoc.querySelector(".ruleview-propertycontainer a");
ok (absoluteLink, "Link exists for absolute node");
ok (absoluteLink.getAttribute("href"), TEST_IMAGE);
inspector.selection.setNode(inline);
is(inspector.selection.node, inline, "selection matches the inline element");
let inlineLink = contentDoc.querySelector(".ruleview-propertycontainer a");
ok (inlineLink, "Link exists for inline node");
ok (inlineLink.getAttribute("href"), TEST_IMAGE);
inspector.selection.setNode(base64);
is(inspector.selection.node, base64, "selection matches the base64 element");
let base64Link = contentDoc.querySelector(".ruleview-propertycontainer a");
ok (base64Link, "Link exists for base64 node");
ok (base64Link.getAttribute("href"), BASE_64_URL);
inspector.selection.setNode(noimage);
is(inspector.selection.node, noimage, "selection matches the inline element");
let noimageLink = contentDoc.querySelector(".ruleview-propertycontainer a");
ok (!noimageLink, "There is no link for the node with no background image");
finishUp();
}
function finishUp()
{
doc = computedView = inspector = null;
gBrowser.removeCurrentTab();
finish();
}
function test()
{
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
doc = content.document;
waitForFocus(createDocument, content);
}, true);
content.location = TEST_URI;
}

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

@ -0,0 +1,9 @@
.relative {
background-image: url(../test-image.png);
}
.absolute {
background: url("http://example.com/browser/browser/devtools/styleinspector/test/test-image.png");
}
.base64 {
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==');
}

Двоичные данные
browser/devtools/styleinspector/test/test-image.png Normal file

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

После

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