-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Fix Live CSS with an iframe element #8144
Changes from 6 commits
b496f08
db16092
7546767
f99d852
0b39d2e
d81e380
a0fabf5
43e9ce6
f3206d3
1893696
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,19 +37,15 @@ define(function CSSAgent(require, exports, module) { | |
|
||
require("thirdparty/path-utils/path-utils.min"); | ||
|
||
var _ = require("thirdparty/lodash"); | ||
|
||
var Inspector = require("LiveDevelopment/Inspector/Inspector"); | ||
|
||
/** | ||
* Stylesheet urls | ||
* Stylesheet details | ||
* @type {Object.<string, CSS.CSSStyleSheetHeader>} | ||
*/ | ||
var _urlToStyle = {}; | ||
|
||
/** | ||
* Map of stylesheet ids to urls | ||
* @type {Object.<string, string>} | ||
*/ | ||
var _styleSheetIdToUrl; | ||
var _styleSheetDetails = {}; | ||
|
||
/** | ||
* Is getAllStyleSheets() API defined? - This is undefined until we test for API | ||
|
@@ -73,18 +69,26 @@ define(function CSSAgent(require, exports, module) { | |
* @param {frame: Frame} res | ||
*/ | ||
function _onFrameNavigated(event, res) { | ||
// Clear maps when navigating to a new page | ||
_urlToStyle = {}; | ||
_styleSheetIdToUrl = {}; | ||
// Clear maps when navigating to a new page, but not if an iframe was loaded | ||
if (!res.frame.parentId) { | ||
_styleSheetDetails = {}; | ||
} | ||
} | ||
|
||
/** | ||
* Get a style sheet for a url | ||
* @param {string} url | ||
* @return {CSS.CSSStyleSheetHeader} | ||
* @return {Array} Array of CSSStyleSheetHeaders | ||
*/ | ||
function styleForURL(url) { | ||
return _urlToStyle[_canonicalize(url)]; | ||
var styleSheetId, styles = {}; | ||
url = _canonicalize(url); | ||
for (styleSheetId in _styleSheetDetails) { | ||
if (_styleSheetDetails[styleSheetId].canonicalizedURL === url) { | ||
styles[styleSheetId] = _styleSheetDetails[styleSheetId]; | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this ever return more than 1 stylesheet for a url? If so, what's the use case? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that's the big problem we had. <html>
<head>
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<iframe>
<html>
<head>
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
Foo.
<body>
</html>
</iframe>
</body>
</html> In that case, you've got the exact same stylesheet used in two different documents on one page, and what this means is that the browser/inspector has two different stylesheet objects with the same URL. |
||
return styles; | ||
} | ||
|
||
/** | ||
|
@@ -93,13 +97,11 @@ define(function CSSAgent(require, exports, module) { | |
* @deprecated | ||
*/ | ||
function getStylesheetURLs() { | ||
var urls = [], url; | ||
for (url in _urlToStyle) { | ||
if (_urlToStyle.hasOwnProperty(url)) { | ||
urls.push(url); | ||
} | ||
var styleSheetId, urls = []; | ||
for (styleSheetId in _styleSheetDetails) { | ||
urls[_styleSheetDetails[styleSheetId].canonicalizedURL] = true; | ||
} | ||
return urls; | ||
return _.keys(urls); | ||
} | ||
|
||
/** | ||
|
@@ -108,9 +110,15 @@ define(function CSSAgent(require, exports, module) { | |
* @return {jQuery.Promise} | ||
*/ | ||
function reloadCSSForDocument(doc) { | ||
var style = styleForURL(doc.url); | ||
console.assert(style, "Style Sheet for document not loaded: " + doc.url); | ||
return Inspector.CSS.setStyleSheetText(style.styleSheetId, doc.getText()); | ||
var styles = styleForURL(doc.url), | ||
styleSheetId, | ||
deferreds = []; | ||
console.assert(styles, "Style Sheet for document not loaded: " + doc.url); | ||
for (styleSheetId in styles) { | ||
deferreds.push(Inspector.CSS.setStyleSheetText(styles[styleSheetId].styleSheetId, doc.getText())); | ||
} | ||
// return master deferred | ||
return $.when.apply($, deferreds); | ||
} | ||
|
||
/** | ||
|
@@ -119,9 +127,15 @@ define(function CSSAgent(require, exports, module) { | |
* @return {jQuery.Promise} | ||
*/ | ||
function clearCSSForDocument(doc) { | ||
var style = styleForURL(doc.url); | ||
console.assert(style, "Style Sheet for document not loaded: " + doc.url); | ||
return Inspector.CSS.setStyleSheetText(style.styleSheetId, ""); | ||
var styles = styleForURL(doc.url), | ||
styleSheetId, | ||
deferreds = []; | ||
console.assert(styles, "Style Sheet for document not loaded: " + doc.url); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
for (styleSheetId in styles) { | ||
deferreds.push(Inspector.CSS.setStyleSheetText(styles[styleSheetId].styleSheetId, "")); | ||
} | ||
// return master deferred | ||
return $.when.apply($, deferreds); | ||
} | ||
|
||
/** | ||
|
@@ -130,16 +144,20 @@ define(function CSSAgent(require, exports, module) { | |
* @param {header: CSSStyleSheetHeader} | ||
*/ | ||
function _styleSheetAdded(event, res) { | ||
var url = _canonicalize(res.header.sourceURL), | ||
existing = _urlToStyle[url]; | ||
var url = _canonicalize(res.header.sourceURL), | ||
existing = styleForURL(res.header.sourceURL), | ||
styleSheetId = res.header.styleSheetId; | ||
|
||
// detect duplicates | ||
if (existing && existing.styleSheetId === res.header.styleSheetId) { | ||
existing = _.some(existing, function (styleSheet) { | ||
return styleSheet && styleSheet.styleSheetId === styleSheetId; | ||
}); | ||
if (existing) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's confusing that you're re-using the |
||
return; | ||
} | ||
|
||
_urlToStyle[url] = res.header; | ||
_styleSheetIdToUrl[res.header.styleSheetId] = url; | ||
_styleSheetDetails[styleSheetId] = res.header; | ||
_styleSheetDetails[styleSheetId].canonicalizedURL = url; // canonicalized URL | ||
|
||
$(exports).triggerHandler("styleSheetAdded", [url, res.header]); | ||
} | ||
|
@@ -150,16 +168,11 @@ define(function CSSAgent(require, exports, module) { | |
* @param {styleSheetId: StyleSheetId} | ||
*/ | ||
function _styleSheetRemoved(event, res) { | ||
var url = _styleSheetIdToUrl[res.styleSheetId], | ||
header = url && _urlToStyle[url]; | ||
|
||
if (url) { | ||
delete _urlToStyle[url]; | ||
} | ||
var header = _styleSheetDetails[res.styleSheetId]; | ||
|
||
delete _styleSheetIdToUrl[res.styleSheetId]; | ||
delete _styleSheetDetails[res.styleSheetId]; | ||
|
||
$(exports).triggerHandler("styleSheetRemoved", [url, header]); | ||
$(exports).triggerHandler("styleSheetRemoved", [header.canonicalizedURL, header]); | ||
} | ||
|
||
/** | ||
|
@@ -233,4 +246,4 @@ define(function CSSAgent(require, exports, module) { | |
exports.clearCSSForDocument = clearCSSForDocument; | ||
exports.load = load; | ||
exports.unload = unload; | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -109,7 +109,8 @@ define(function CSSDocumentModule(require, exports, module) { | |
*/ | ||
CSSDocument.prototype.getSourceFromBrowser = function getSourceFromBrowser() { | ||
var deferred = new $.Deferred(), | ||
styleSheetId = this._getStyleSheetHeader().styleSheetId, | ||
styleSheetHeader = this._getStyleSheetHeader(), | ||
styleSheetId = styleSheetHeader[_.keys(styleSheetHeader)[0]].styleSheetId, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder whether there's a nicer method to determinate the first index of an object? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know this code well enough to know what it's trying to do, but just wanted to point out that there's no concept of "first" (or "index" for that matter) in associative arrays -- the keys are unordered. I'm guessing this code is assuming only one key exists, and it just wants its value, but it doesn't know what the one key is... If that's the case, you could do it more efficiently with a utiltiy like this:
Or, to fail fast when the single-key assumption is wrong:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nope, it can have multiple values (that's what this PR is all about - we assumed it can only have one value before), but they should all be the same, so it doesn't matter much which one to use. And as they are enumerated (but not beginning with 0), the first one should be ok... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @SAplayer When you say "they are enumerated (but not beginning with 0)," do you mean the keys are all numbers, but they're non-sequential? If so, still bear in mind that there's no guarantee on the order of Object.keys() -- the lowest number is not necessarily first in the array. If your code relies on always getting the lowest index/key, you should .sort() the keys array to ensure that'll always actually happen. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that's how the array is structured. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think it's safe accessing function getOnlyValue(obj) {
for (var key in obj) {
if (_.has(obj, key)) {
return obj[key];
}
}
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @marcelgerber You still haven't fixed this line. |
||
inspectorPromise = Inspector.CSS.getStyleSheetText(styleSheetId); | ||
|
||
inspectorPromise.then(function (res) { | ||
|
@@ -252,12 +253,12 @@ define(function CSSDocumentModule(require, exports, module) { | |
Inspector.CSS.getMatchedStylesForNode(node.nodeId, function onGetMatchesStyles(res) { | ||
// res = {matchedCSSRules, pseudoElements, inherited} | ||
var codeMirror = this.editor._codeMirror, | ||
styleSheetId = this._getStyleSheetHeader().styleSheetId; | ||
styleSheetIds = this._getStyleSheetHeader(); | ||
|
||
var i, rule, from, to; | ||
for (i in res.matchedCSSRules) { | ||
rule = res.matchedCSSRules[i]; | ||
if (rule.ruleId && rule.ruleId.styleSheetId === styleSheetId) { | ||
if (rule.ruleId && styleSheetIds && styleSheetIds[rule.ruleId.styleSheetId]) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
from = codeMirror.posFromIndex(rule.selectorRange.start); | ||
to = codeMirror.posFromIndex(rule.style.range.end); | ||
this._highlight.push(codeMirror.markText(from, to, { className: "highlight" })); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#testId { | ||
font-size: 20px; | ||
} | ||
|
||
.testClass { | ||
background-color:rgba(102,102,204,.5); | ||
color:rgba(255,255,255,1); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<!doctype html> | ||
<html> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<title>Simple Test</title> | ||
<link rel="stylesheet" href="simpleShared.css"> | ||
<link rel="stylesheet" href="simple1.css"> | ||
</head> | ||
|
||
<body> | ||
<p id="testId" class="testClass">iframes are cool.</p> | ||
<iframe src="iframe.html"></iframe> | ||
</body> | ||
</html> |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be: