Skip to content
This repository was archived by the owner on Sep 6, 2021. It is now read-only.

Commit e5e1f46

Browse files
committed
Merge pull request #8144 from MarcelGerber/live-css-iframe
Fix Live CSS with an iframe element
2 parents 45bbc38 + 1893696 commit e5e1f46

File tree

10 files changed

+126
-65
lines changed

10 files changed

+126
-65
lines changed

src/LiveDevelopment/Agents/CSSAgent.js

Lines changed: 55 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,15 @@ define(function CSSAgent(require, exports, module) {
3737

3838
require("thirdparty/path-utils/path-utils.min");
3939

40+
var _ = require("thirdparty/lodash");
41+
4042
var Inspector = require("LiveDevelopment/Inspector/Inspector");
4143

4244
/**
43-
* Stylesheet urls
45+
* Stylesheet details
4446
* @type {Object.<string, CSS.CSSStyleSheetHeader>}
4547
*/
46-
var _urlToStyle = {};
47-
48-
/**
49-
* Map of stylesheet ids to urls
50-
* @type {Object.<string, string>}
51-
*/
52-
var _styleSheetIdToUrl;
48+
var _styleSheetDetails = {};
5349

5450
/**
5551
* Is getAllStyleSheets() API defined? - This is undefined until we test for API
@@ -73,18 +69,26 @@ define(function CSSAgent(require, exports, module) {
7369
* @param {frame: Frame} res
7470
*/
7571
function _onFrameNavigated(event, res) {
76-
// Clear maps when navigating to a new page
77-
_urlToStyle = {};
78-
_styleSheetIdToUrl = {};
72+
// Clear maps when navigating to a new page, but not if an iframe was loaded
73+
if (!res.frame.parentId) {
74+
_styleSheetDetails = {};
75+
}
7976
}
8077

8178
/**
82-
* Get a style sheet for a url
79+
* Get the style sheets for a url
8380
* @param {string} url
84-
* @return {CSS.CSSStyleSheetHeader}
81+
* @return {Object.<string, CSSStyleSheetHeader>}
8582
*/
8683
function styleForURL(url) {
87-
return _urlToStyle[_canonicalize(url)];
84+
var styleSheetId, styles = {};
85+
url = _canonicalize(url);
86+
for (styleSheetId in _styleSheetDetails) {
87+
if (_styleSheetDetails[styleSheetId].canonicalizedURL === url) {
88+
styles[styleSheetId] = _styleSheetDetails[styleSheetId];
89+
}
90+
}
91+
return styles;
8892
}
8993

9094
/**
@@ -93,24 +97,36 @@ define(function CSSAgent(require, exports, module) {
9397
* @deprecated
9498
*/
9599
function getStylesheetURLs() {
96-
var urls = [], url;
97-
for (url in _urlToStyle) {
98-
if (_urlToStyle.hasOwnProperty(url)) {
99-
urls.push(url);
100-
}
100+
var styleSheetId, urls = [];
101+
for (styleSheetId in _styleSheetDetails) {
102+
urls[_styleSheetDetails[styleSheetId].canonicalizedURL] = true;
101103
}
102-
return urls;
104+
return _.keys(urls);
103105
}
104106

105107
/**
106108
* Reload a CSS style sheet from a document
107109
* @param {Document} document
110+
* @param {string=} newContent new content of every stylesheet. Defaults to doc.getText() if omitted
108111
* @return {jQuery.Promise}
109112
*/
110-
function reloadCSSForDocument(doc) {
111-
var style = styleForURL(doc.url);
112-
console.assert(style, "Style Sheet for document not loaded: " + doc.url);
113-
return Inspector.CSS.setStyleSheetText(style.styleSheetId, doc.getText());
113+
function reloadCSSForDocument(doc, newContent) {
114+
var styles = styleForURL(doc.url),
115+
styleSheetId,
116+
deferreds = [];
117+
118+
if (newContent === undefined) {
119+
newContent = doc.getText();
120+
}
121+
for (styleSheetId in styles) {
122+
deferreds.push(Inspector.CSS.setStyleSheetText(styles[styleSheetId].styleSheetId, newContent));
123+
}
124+
if (!deferreds.length) {
125+
console.error("Style Sheet for document not loaded: " + doc.url);
126+
return new $.Deferred().reject().promise();
127+
}
128+
// return master deferred
129+
return $.when.apply($, deferreds);
114130
}
115131

116132
/**
@@ -119,9 +135,7 @@ define(function CSSAgent(require, exports, module) {
119135
* @return {jQuery.Promise}
120136
*/
121137
function clearCSSForDocument(doc) {
122-
var style = styleForURL(doc.url);
123-
console.assert(style, "Style Sheet for document not loaded: " + doc.url);
124-
return Inspector.CSS.setStyleSheetText(style.styleSheetId, "");
138+
return reloadCSSForDocument(doc, "");
125139
}
126140

127141
/**
@@ -130,16 +144,21 @@ define(function CSSAgent(require, exports, module) {
130144
* @param {header: CSSStyleSheetHeader}
131145
*/
132146
function _styleSheetAdded(event, res) {
133-
var url = _canonicalize(res.header.sourceURL),
134-
existing = _urlToStyle[url];
147+
var url = _canonicalize(res.header.sourceURL),
148+
existing = styleForURL(res.header.sourceURL),
149+
styleSheetId = res.header.styleSheetId,
150+
duplicate;
135151

136152
// detect duplicates
137-
if (existing && existing.styleSheetId === res.header.styleSheetId) {
153+
duplicate = _.some(existing, function (styleSheet) {
154+
return styleSheet && styleSheet.styleSheetId === styleSheetId;
155+
});
156+
if (duplicate) {
138157
return;
139158
}
140159

141-
_urlToStyle[url] = res.header;
142-
_styleSheetIdToUrl[res.header.styleSheetId] = url;
160+
_styleSheetDetails[styleSheetId] = res.header;
161+
_styleSheetDetails[styleSheetId].canonicalizedURL = url; // canonicalized URL
143162

144163
$(exports).triggerHandler("styleSheetAdded", [url, res.header]);
145164
}
@@ -150,16 +169,11 @@ define(function CSSAgent(require, exports, module) {
150169
* @param {styleSheetId: StyleSheetId}
151170
*/
152171
function _styleSheetRemoved(event, res) {
153-
var url = _styleSheetIdToUrl[res.styleSheetId],
154-
header = url && _urlToStyle[url];
155-
156-
if (url) {
157-
delete _urlToStyle[url];
158-
}
172+
var header = _styleSheetDetails[res.styleSheetId];
159173

160-
delete _styleSheetIdToUrl[res.styleSheetId];
174+
delete _styleSheetDetails[res.styleSheetId];
161175

162-
$(exports).triggerHandler("styleSheetRemoved", [url, header]);
176+
$(exports).triggerHandler("styleSheetRemoved", [header.canonicalizedURL, header]);
163177
}
164178

165179
/**
@@ -233,4 +247,4 @@ define(function CSSAgent(require, exports, module) {
233247
exports.clearCSSForDocument = clearCSSForDocument;
234248
exports.load = load;
235249
exports.unload = unload;
236-
});
250+
});

src/LiveDevelopment/Agents/NetworkAgent.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,10 @@ define(function NetworkAgent(require, exports, module) {
7171
// WebInspector Event: Page.frameNavigated
7272
function _onFrameNavigated(event, res) {
7373
// res = {frame}
74-
_reset();
74+
// Clear log when navigating to a new page, but not if an iframe was loaded
75+
if (!res.frame.parentId) {
76+
_reset();
77+
}
7578
_logURL(res.frame.url);
7679
}
7780

@@ -101,4 +104,4 @@ define(function NetworkAgent(require, exports, module) {
101104
exports.enable = enable;
102105
exports.load = load;
103106
exports.unload = unload;
104-
});
107+
});

src/LiveDevelopment/Agents/RemoteAgent.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,12 @@ define(function RemoteAgent(require, exports, module) {
124124

125125
// WebInspector Event: Page.frameNavigated
126126
function _onFrameNavigated(event, res) {
127-
// res = {timestamp}
127+
// res = {frame}
128+
// Re-inject RemoteFunctions when navigating to a new page, but not if an iframe was loaded
129+
if (res.frame.parentId) {
130+
return;
131+
}
132+
128133
_stopKeepAliveInterval();
129134

130135
// inject RemoteFunctions

src/LiveDevelopment/Agents/ScriptAgent.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,10 @@ define(function ScriptAgent(require, exports, module) {
129129
* @param {frame: Frame} res
130130
*/
131131
function _onFrameNavigated(event, res) {
132-
// Clear maps when navigating to a new page
133-
_reset();
132+
// Clear maps when navigating to a new page, but not if an iframe was loaded
133+
if (!res.frame.parentId) {
134+
_reset();
135+
}
134136
}
135137

136138
/** Initialize the agent */
@@ -171,4 +173,4 @@ define(function ScriptAgent(require, exports, module) {
171173
exports.scriptForURL = scriptForURL;
172174
exports.load = load;
173175
exports.unload = unload;
174-
});
176+
});

src/LiveDevelopment/Documents/CSSDocument.js

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,27 @@ define(function CSSDocumentModule(require, exports, module) {
108108
* @return {jQuery.promise} Promise resolved with the text content of this CSS document
109109
*/
110110
CSSDocument.prototype.getSourceFromBrowser = function getSourceFromBrowser() {
111+
function getOnlyValue(obj) {
112+
var key;
113+
for (key in obj) {
114+
if (_.has(obj, key)) {
115+
return obj[key];
116+
}
117+
}
118+
return null;
119+
}
120+
111121
var deferred = new $.Deferred(),
112-
styleSheetId = this._getStyleSheetHeader().styleSheetId,
113-
inspectorPromise = Inspector.CSS.getStyleSheetText(styleSheetId);
122+
styleSheetHeader = this._getStyleSheetHeader(),
123+
styleSheet = getOnlyValue(styleSheetHeader);
114124

115-
inspectorPromise.then(function (res) {
116-
deferred.resolve(res.text);
117-
}, deferred.reject);
125+
if (styleSheet) {
126+
Inspector.CSS.getStyleSheetText(styleSheet.styleSheetId).then(function (res) {
127+
deferred.resolve(res.text);
128+
}, deferred.reject);
129+
} else {
130+
deferred.reject();
131+
}
118132

119133
return deferred.promise();
120134
};
@@ -252,12 +266,12 @@ define(function CSSDocumentModule(require, exports, module) {
252266
Inspector.CSS.getMatchedStylesForNode(node.nodeId, function onGetMatchesStyles(res) {
253267
// res = {matchedCSSRules, pseudoElements, inherited}
254268
var codeMirror = this.editor._codeMirror,
255-
styleSheetId = this._getStyleSheetHeader().styleSheetId;
269+
styleSheetIds = this._getStyleSheetHeader();
256270

257271
var i, rule, from, to;
258272
for (i in res.matchedCSSRules) {
259273
rule = res.matchedCSSRules[i];
260-
if (rule.ruleId && rule.ruleId.styleSheetId === styleSheetId) {
274+
if (rule.ruleId && styleSheetIds[rule.ruleId.styleSheetId]) {
261275
from = codeMirror.posFromIndex(rule.selectorRange.start);
262276
to = codeMirror.posFromIndex(rule.style.range.end);
263277
this._highlight.push(codeMirror.markText(from, to, { className: "highlight" }));
@@ -268,4 +282,4 @@ define(function CSSDocumentModule(require, exports, module) {
268282

269283
// Export the class
270284
module.exports = CSSDocument;
271-
});
285+
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#testId {
2+
font-size: 20px;
3+
}
4+
5+
.testClass {
6+
background-color:rgba(102,102,204,.5);
7+
color:rgba(255,255,255,1);
8+
}
9+

test/spec/LiveDevelopment-test-files/simple2.html renamed to test/spec/LiveDevelopment-test-files/iframe.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<meta charset="UTF-8">
55
<title>Simple Test</title>
66
<link rel="stylesheet" href="simpleShared.css">
7-
<link rel="stylesheet" href="simple2.css">
7+
<link rel="stylesheet" href="iframe.css">
88
</head>
99

1010
<body>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Simple Test</title>
6+
<link rel="stylesheet" href="simpleShared.css">
7+
<link rel="stylesheet" href="simple1.css">
8+
</head>
9+
10+
<body>
11+
<p id="testId" class="testClass">iframes are cool.</p>
12+
<iframe src="iframe.html"></iframe>
13+
</body>
14+
</html>

test/spec/LiveDevelopment-test-files/simple2.css

Lines changed: 0 additions & 8 deletions
This file was deleted.

test/spec/LiveDevelopment-test.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ define(function (require, exports, module) {
286286
HighlightAgentModule.load();
287287

288288
// module spies
289-
spyOn(CSSAgentModule, "styleForURL").andReturn("");
289+
spyOn(CSSAgentModule, "styleForURL").andReturn([]);
290290
spyOn(CSSAgentModule, "reloadCSSForDocument").andCallFake(function () { return new $.Deferred().resolve(); });
291291
spyOn(HighlightAgentModule, "redraw").andCallFake(function () {});
292292
spyOn(HighlightAgentModule, "rule").andCallFake(function () {});
@@ -642,6 +642,10 @@ define(function (require, exports, module) {
642642
doOneTest("simple1Query.html", "simple1.css");
643643
});
644644

645+
it("should push changes after loading an iframe", function () {
646+
doOneTest("simple1iframe.html", "simple1.css");
647+
});
648+
645649
it("should push in memory css changes made before the session starts", function () {
646650
var localText,
647651
browserText;
@@ -767,6 +771,10 @@ define(function (require, exports, module) {
767771
expect(updatedNode.value).toBe("Live Preview in Brackets is awesome!");
768772
});
769773
});
774+
775+
it("should push changes to the iframes' css file", function () {
776+
doOneTest("simple1iframe.html", "iframe.css");
777+
});
770778
});
771779

772780
describe("HTML Editing", function () {

0 commit comments

Comments
 (0)