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

Commit bc09738

Browse files
author
Narciso Jaramillo
committed
Merge pull request #2136 from adobe/glenn/css-highlight
Add Preview Highlight functionality
2 parents f139ec4 + 87804ff commit bc09738

9 files changed

Lines changed: 200 additions & 52 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,7 @@ src/brackets.min.css
77
src/extensions/dev/*
88
!src/extensions/dev/README
99

10+
src/extensions/disabled
11+
1012
#OSX .DS_Store files
1113
.DS_Store

src/LiveDevelopment/Agents/HighlightAgent.js

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,10 @@
3434
define(function HighlightAgent(require, exports, module) {
3535
"use strict";
3636

37-
var Inspector = require("LiveDevelopment/Inspector/Inspector");
38-
var RemoteAgent = require("LiveDevelopment/Agents/RemoteAgent");
39-
var DOMAgent = require("LiveDevelopment/Agents/DOMAgent");
37+
var DOMAgent = require("LiveDevelopment/Agents/DOMAgent"),
38+
Inspector = require("LiveDevelopment/Inspector/Inspector"),
39+
LiveDevelopment = require("LiveDevelopment/LiveDevelopment"),
40+
RemoteAgent = require("LiveDevelopment/Agents/RemoteAgent");
4041

4142
var _highlight; // active highlight
4243

@@ -66,6 +67,10 @@ define(function HighlightAgent(require, exports, module) {
6667
* @param {DOMNode} node
6768
*/
6869
function node(n) {
70+
if (!LiveDevelopment.config.experimental) {
71+
return;
72+
}
73+
6974
if (!Inspector.config.highlight) {
7075
return;
7176
}
@@ -94,29 +99,41 @@ define(function HighlightAgent(require, exports, module) {
9499
* @param {string} rule selector
95100
*/
96101
function rule(name) {
97-
if (_highlight.rule === name) {
102+
if (_highlight.ref === name) {
98103
return;
99104
}
100105
hide();
101106
_highlight = {type: "css", ref: name};
102107
RemoteAgent.call("highlightRule", name);
103108
}
109+
110+
/**
111+
* Redraw active highlights
112+
*/
113+
function redraw() {
114+
RemoteAgent.call("redrawHighlights");
115+
}
104116

105117
/** Initialize the agent */
106118
function load() {
107119
_highlight = {};
108-
$(RemoteAgent).on("highlight.HighlightAgent", _onRemoteHighlight);
120+
if (LiveDevelopment.config.experimental) {
121+
$(RemoteAgent).on("highlight.HighlightAgent", _onRemoteHighlight);
122+
}
109123
}
110124

111125
/** Clean up */
112126
function unload() {
113-
$(RemoteAgent).off(".HighlightAgent");
127+
if (LiveDevelopment.config.experimental) {
128+
$(RemoteAgent).off(".HighlightAgent");
129+
}
114130
}
115131

116132
// Export public functions
117133
exports.hide = hide;
118134
exports.node = node;
119135
exports.rule = rule;
136+
exports.redraw = redraw;
120137
exports.load = load;
121138
exports.unload = unload;
122139
});

src/LiveDevelopment/Agents/RemoteFunctions.js

Lines changed: 109 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
function RemoteFunctions(experimental) {
3434
"use strict";
3535

36+
var HIGHLIGHT_CLASSNAME = "__brackets-ld-highlight";
37+
3638
// determine the color for a type
3739
function _typeColor(type, highlight) {
3840
switch (type) {
@@ -49,6 +51,10 @@ function RemoteFunctions(experimental) {
4951

5052
// compute the screen offset of an element
5153
function _screenOffset(element, key) {
54+
if (element === document.body) {
55+
var bounds = element.getBoundingClientRect();
56+
return (key === "offsetLeft" ? bounds.left : bounds.top);
57+
}
5258
var value = 0;
5359
while (element) {
5460
value += element[key];
@@ -204,27 +210,102 @@ function RemoteFunctions(experimental) {
204210
return false;
205211
},
206212

207-
add: function (element) {
213+
_makeHighlightDiv: function (element, doAnimation) {
214+
var elementBounds = element.getBoundingClientRect(),
215+
highlight = window.document.createElement("div"),
216+
styles = window.getComputedStyle(element);
217+
218+
highlight.className = HIGHLIGHT_CLASSNAME;
219+
220+
var stylesToSet = {
221+
"left": _screenOffset(element, "offsetLeft") + "px",
222+
"top": _screenOffset(element, "offsetTop") + "px",
223+
"width": elementBounds.width + "px",
224+
"height": elementBounds.height + "px",
225+
"z-index": 2000000,
226+
"position": "absolute",
227+
"pointer-events": "none",
228+
"border-top-left-radius": styles.borderTopLeftRadius,
229+
"border-top-right-radius": styles.borderTopRightRadius,
230+
"border-bottom-left-radius": styles.borderBottomLeftRadius,
231+
"border-bottom-right-radius": styles.borderBottomRightRadius
232+
};
233+
234+
var animateStartValues = {
235+
"opacity": 0,
236+
"background": "rgba(94,167,255, 0.5)",
237+
"box-shadow": "0 0 2px 1px rgba(94,167,255, 1), inset 0 0 4px 1px rgba(255,255,255,1)"
238+
};
239+
240+
var animateEndValues = {
241+
"opacity": 1,
242+
"background": "rgba(94,167,255, 0.1)",
243+
"box-shadow": "0 0 1px 1px rgba(94,167,255, 0.6), inset 0 0 4px 1px rgba(255,255,255,0.8)"
244+
};
245+
246+
var transitionValues = {
247+
"-webkit-transition-property": "opacity, box-shadow, background",
248+
"-webkit-transition-duration": "0.3s, 0.4s, 0.4s",
249+
"transition-property": "opacity, box-shadow, background",
250+
"transition-duration": "0.3s, 0.4s, 0.4s"
251+
};
252+
253+
function _setStyleValues(styleValues, obj) {
254+
var prop;
255+
256+
for (prop in styleValues) {
257+
obj.setProperty(prop, styleValues[prop]);
258+
}
259+
}
260+
261+
_setStyleValues(stylesToSet, highlight.style);
262+
_setStyleValues(
263+
doAnimation ? animateStartValues : animateEndValues,
264+
highlight.style
265+
);
266+
267+
268+
if (doAnimation) {
269+
_setStyleValues(transitionValues, highlight.style);
270+
271+
window.setTimeout(function () {
272+
_setStyleValues(animateEndValues, highlight.style);
273+
}, 0);
274+
}
275+
276+
window.document.body.appendChild(highlight);
277+
},
278+
279+
add: function (element, doAnimation) {
208280
if (this._elementExists(element) || element === document) {
209281
return;
210282
}
211283
if (this.trigger) {
212284
_trigger(element, "highlight", 1);
213285
}
214286
this.elements.push(element);
215-
this.orgColors.push(element.style.getPropertyValue("background-color"));
216-
element.style.setProperty("background-color", this.color);
287+
288+
this._makeHighlightDiv(element, doAnimation);
217289
},
218290

219291
clear: function () {
220-
var i;
221-
for (i in this.elements) {
222-
var e = this.elements[i];
223-
e.style.setProperty("background-color", this.orgColors[i]);
224-
_trigger(e, "highlight", 0, true);
292+
var i, highlights = window.document.querySelectorAll("." + HIGHLIGHT_CLASSNAME),
293+
body = window.document.body;
294+
295+
for (i = 0; i < highlights.length; i++) {
296+
body.removeChild(highlights[i]);
225297
}
298+
226299
this.elements = [];
227-
this.orgColors = [];
300+
},
301+
302+
redraw: function () {
303+
var i, highlighted = this.elements.slice(0);
304+
305+
this.clear();
306+
for (i in highlighted) {
307+
this.add(highlighted[i], false);
308+
}
228309
}
229310
};
230311

@@ -252,7 +333,7 @@ function RemoteFunctions(experimental) {
252333
if (!event.metaKey) {
253334
return;
254335
}
255-
_localHighlight.add(event.target);
336+
_localHighlight.add(event.target, true);
256337
}
257338

258339
function onMouseOut(event) {
@@ -305,7 +386,6 @@ function RemoteFunctions(experimental) {
305386
}
306387
}
307388

308-
309389
/** Public Commands **********************************************************/
310390

311391
// show goto
@@ -336,7 +416,7 @@ function RemoteFunctions(experimental) {
336416
if (clear) {
337417
_remoteHighlight.clear();
338418
}
339-
_remoteHighlight.add(node);
419+
_remoteHighlight.add(node, true);
340420
}
341421

342422
// highlight a rule
@@ -347,16 +427,32 @@ function RemoteFunctions(experimental) {
347427
highlight(nodes[i]);
348428
}
349429
}
430+
431+
// redraw active highlights
432+
function redrawHighlights() {
433+
if (_remoteHighlight) {
434+
_remoteHighlight.redraw();
435+
}
436+
}
350437

351438
// init
352439
if (experimental) {
353440
window.document.addEventListener("keydown", onKeyDown);
354441
}
442+
443+
window.addEventListener("resize", redrawHighlights);
444+
445+
// Scrolling a div can interfere with highlighting.
446+
var i, divs = window.document.getElementsByTagName("div");
447+
for (i = 0; i < divs.length; i++) {
448+
divs[i].addEventListener("scroll", redrawHighlights);
449+
}
355450

356451
return {
357452
"showGoto": showGoto,
358453
"hideHighlight": hideHighlight,
359454
"highlight": highlight,
360-
"highlightRule": highlightRule
455+
"highlightRule": highlightRule,
456+
"redrawHighlights": redrawHighlights
361457
};
362458
}

src/LiveDevelopment/Documents/CSSDocument.js

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,16 +80,11 @@ define(function CSSDocumentModule(require, exports, module) {
8080
// get the style sheet
8181
this.styleSheet = CSSAgent.styleForURL(this.doc.url);
8282

83-
// WebInspector Command: CSS.getStyleSheet
84-
Inspector.CSS.getStyleSheet(this.styleSheet.styleSheetId, function callback(res) {
85-
// res = {styleSheet}
86-
this.rules = res.styleSheet.rules;
87-
}.bind(this));
88-
8983
// If the CSS document is dirty, push the changes into the browser now
9084
if (doc.isDirty) {
9185
CSSAgent.reloadCSSForDocument(this.doc);
9286
}
87+
this.reloadRules();
9388
};
9489

9590
/** Get the browser version of the StyleSheet object */
@@ -135,6 +130,18 @@ define(function CSSDocumentModule(require, exports, module) {
135130
}
136131
};
137132

133+
// Reload rules
134+
CSSDocument.prototype.reloadRules = function () {
135+
this.loadRulePromise = this.getStyleSheetFromBrowser().done(function (styleSheet) {
136+
this.rules = styleSheet.rules;
137+
this.loadRulePromise = null;
138+
if (this.pendingCursorActivity) {
139+
this.pendingCursorActivity = false;
140+
this.onCursorActivity();
141+
}
142+
}.bind(this));
143+
};
144+
138145
// find a rule in the given rules
139146
CSSDocument.prototype.ruleAtLocation = function ruleAtLocation(location) {
140147
var i, rule;
@@ -153,6 +160,13 @@ define(function CSSDocumentModule(require, exports, module) {
153160
/** Triggered on cursor activity of the editor */
154161
CSSDocument.prototype.onCursorActivity = function onCursorActivity(event, editor) {
155162
if (Inspector.config.highlight) {
163+
// If there is an active loadRulePromise, we can't accurately get the rule
164+
// at the location. Set a flag here so we can get called again once the
165+
// rules have arrived.
166+
if (this.loadRulePromise) {
167+
this.pendingCursorActivity = true;
168+
return;
169+
}
156170
var codeMirror = this.editor._codeMirror;
157171
var location = codeMirror.indexFromPos(codeMirror.getCursor());
158172
var rule = this.ruleAtLocation(location);
@@ -168,6 +182,10 @@ define(function CSSDocumentModule(require, exports, module) {
168182
CSSDocument.prototype.onChange = function onChange(event, editor, change) {
169183
// brute force: update the CSS
170184
CSSAgent.reloadCSSForDocument(this.doc);
185+
this.reloadRules();
186+
if (Inspector.config.highlight) {
187+
HighlightAgent.redraw();
188+
}
171189
};
172190
/** Triggered if the Document's file is deleted */
173191
CSSDocument.prototype.onDeleted = function onDeleted(event, editor, change) {

src/LiveDevelopment/LiveDevelopment.js

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ define(function LiveDevelopment(require, exports, module) {
104104
"remote" : true,
105105
"network" : true,
106106
"dom" : true,
107-
"css" : true
107+
"css" : true,
108+
"highlight" : true
108109
};
109110

110111
// store the names (matching property names in the 'agent' object) of agents that we've loaded
@@ -559,6 +560,21 @@ define(function LiveDevelopment(require, exports, module) {
559560
Inspector.disconnect();
560561
_setStatus(STATUS_INACTIVE);
561562
}
563+
564+
/** Enable highlighting */
565+
function showHighlight() {
566+
// Force cursor activity to kick highlighting
567+
if (_liveDocument instanceof CSSDocument) {
568+
_liveDocument.onCursorActivity();
569+
}
570+
}
571+
572+
/** Hide any active highlighting */
573+
function hideHighlight() {
574+
if (Inspector.connected() && agents.highlight) {
575+
agents.highlight.hide();
576+
}
577+
}
562578

563579
/** Triggered by a document change from the DocumentManager */
564580
function _onDocumentChange() {
@@ -569,6 +585,7 @@ define(function LiveDevelopment(require, exports, module) {
569585
}
570586

571587
if (Inspector.connected()) {
588+
hideHighlight();
572589
if (agents.network && agents.network.wasURLRequested(doc.url)) {
573590
_closeDocument();
574591
var editor = EditorManager.getCurrentFullEditor();
@@ -628,13 +645,6 @@ define(function LiveDevelopment(require, exports, module) {
628645
return foundDoc;
629646
}
630647

631-
/** Hide any active highlighting */
632-
function hideHighlight() {
633-
if (Inspector.connected() && agents.highlight) {
634-
agents.highlight.hide();
635-
}
636-
}
637-
638648
/** Initialize the LiveDevelopment Session */
639649
function init(theConfig) {
640650
exports.config = theConfig;
@@ -657,6 +667,7 @@ define(function LiveDevelopment(require, exports, module) {
657667
exports.enableAgent = enableAgent;
658668
exports.disableAgent = disableAgent;
659669
exports.getLiveDocForPath = getLiveDocForPath;
670+
exports.showHighlight = showHighlight;
660671
exports.hideHighlight = hideHighlight;
661672
exports.init = init;
662673
});

0 commit comments

Comments
 (0)