OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | |
5 /** | 4 /** |
6 * @constructor | |
7 * @extends {WebInspector.Widget} | |
8 * @implements {WebInspector.TargetManager.Observer} | 5 * @implements {WebInspector.TargetManager.Observer} |
9 * @param {function():number} getWidthCallback | 6 * @unrestricted |
10 * @param {function(number)} setWidthCallback | |
11 */ | 7 */ |
12 WebInspector.MediaQueryInspector = function(getWidthCallback, setWidthCallback) | 8 WebInspector.MediaQueryInspector = class extends WebInspector.Widget { |
13 { | 9 /** |
14 WebInspector.Widget.call(this, true); | 10 * @param {function():number} getWidthCallback |
15 this.registerRequiredCSS("emulation/mediaQueryInspector.css"); | 11 * @param {function(number)} setWidthCallback |
16 this.contentElement.classList.add("media-inspector-view"); | 12 */ |
17 this.contentElement.addEventListener("click", this._onMediaQueryClicked.bind
(this), false); | 13 constructor(getWidthCallback, setWidthCallback) { |
18 this.contentElement.addEventListener("contextmenu", this._onContextMenu.bind
(this), false); | 14 super(true); |
| 15 this.registerRequiredCSS('emulation/mediaQueryInspector.css'); |
| 16 this.contentElement.classList.add('media-inspector-view'); |
| 17 this.contentElement.addEventListener('click', this._onMediaQueryClicked.bind
(this), false); |
| 18 this.contentElement.addEventListener('contextmenu', this._onContextMenu.bind
(this), false); |
19 this._mediaThrottler = new WebInspector.Throttler(0); | 19 this._mediaThrottler = new WebInspector.Throttler(0); |
20 | 20 |
21 this._getWidthCallback = getWidthCallback; | 21 this._getWidthCallback = getWidthCallback; |
22 this._setWidthCallback = setWidthCallback; | 22 this._setWidthCallback = setWidthCallback; |
23 this._scale = 1; | 23 this._scale = 1; |
24 | 24 |
25 WebInspector.targetManager.observeTargets(this); | 25 WebInspector.targetManager.observeTargets(this); |
26 WebInspector.zoomManager.addEventListener(WebInspector.ZoomManager.Events.Zo
omChanged, this._renderMediaQueries.bind(this), this); | 26 WebInspector.zoomManager.addEventListener( |
| 27 WebInspector.ZoomManager.Events.ZoomChanged, this._renderMediaQueries.bi
nd(this), this); |
| 28 } |
| 29 |
| 30 /** |
| 31 * @override |
| 32 * @param {!WebInspector.Target} target |
| 33 */ |
| 34 targetAdded(target) { |
| 35 // FIXME: adapt this to multiple targets. |
| 36 if (this._cssModel) |
| 37 return; |
| 38 this._cssModel = WebInspector.CSSModel.fromTarget(target); |
| 39 if (!this._cssModel) |
| 40 return; |
| 41 this._cssModel.addEventListener( |
| 42 WebInspector.CSSModel.Events.StyleSheetAdded, this._scheduleMediaQueries
Update, this); |
| 43 this._cssModel.addEventListener( |
| 44 WebInspector.CSSModel.Events.StyleSheetRemoved, this._scheduleMediaQueri
esUpdate, this); |
| 45 this._cssModel.addEventListener( |
| 46 WebInspector.CSSModel.Events.StyleSheetChanged, this._scheduleMediaQueri
esUpdate, this); |
| 47 this._cssModel.addEventListener( |
| 48 WebInspector.CSSModel.Events.MediaQueryResultChanged, this._scheduleMedi
aQueriesUpdate, this); |
| 49 } |
| 50 |
| 51 /** |
| 52 * @override |
| 53 * @param {!WebInspector.Target} target |
| 54 */ |
| 55 targetRemoved(target) { |
| 56 if (WebInspector.CSSModel.fromTarget(target) !== this._cssModel) |
| 57 return; |
| 58 this._cssModel.removeEventListener( |
| 59 WebInspector.CSSModel.Events.StyleSheetAdded, this._scheduleMediaQueries
Update, this); |
| 60 this._cssModel.removeEventListener( |
| 61 WebInspector.CSSModel.Events.StyleSheetRemoved, this._scheduleMediaQueri
esUpdate, this); |
| 62 this._cssModel.removeEventListener( |
| 63 WebInspector.CSSModel.Events.StyleSheetChanged, this._scheduleMediaQueri
esUpdate, this); |
| 64 this._cssModel.removeEventListener( |
| 65 WebInspector.CSSModel.Events.MediaQueryResultChanged, this._scheduleMedi
aQueriesUpdate, this); |
| 66 delete this._cssModel; |
| 67 } |
| 68 |
| 69 /** |
| 70 * @param {number} scale |
| 71 */ |
| 72 setAxisTransform(scale) { |
| 73 if (Math.abs(this._scale - scale) < 1e-8) |
| 74 return; |
| 75 this._scale = scale; |
| 76 this._renderMediaQueries(); |
| 77 } |
| 78 |
| 79 /** |
| 80 * @param {!Event} event |
| 81 */ |
| 82 _onMediaQueryClicked(event) { |
| 83 var mediaQueryMarker = event.target.enclosingNodeOrSelfWithClass('media-insp
ector-bar'); |
| 84 if (!mediaQueryMarker) |
| 85 return; |
| 86 |
| 87 var model = mediaQueryMarker._model; |
| 88 if (model.section() === WebInspector.MediaQueryInspector.Section.Max) { |
| 89 this._setWidthCallback(model.maxWidthExpression().computedLength()); |
| 90 return; |
| 91 } |
| 92 if (model.section() === WebInspector.MediaQueryInspector.Section.Min) { |
| 93 this._setWidthCallback(model.minWidthExpression().computedLength()); |
| 94 return; |
| 95 } |
| 96 var currentWidth = this._getWidthCallback(); |
| 97 if (currentWidth !== model.minWidthExpression().computedLength()) |
| 98 this._setWidthCallback(model.minWidthExpression().computedLength()); |
| 99 else |
| 100 this._setWidthCallback(model.maxWidthExpression().computedLength()); |
| 101 } |
| 102 |
| 103 /** |
| 104 * @param {!Event} event |
| 105 */ |
| 106 _onContextMenu(event) { |
| 107 if (!this._cssModel || !this._cssModel.isEnabled()) |
| 108 return; |
| 109 |
| 110 var mediaQueryMarker = event.target.enclosingNodeOrSelfWithClass('media-insp
ector-bar'); |
| 111 if (!mediaQueryMarker) |
| 112 return; |
| 113 |
| 114 var locations = mediaQueryMarker._locations; |
| 115 var uiLocations = new Map(); |
| 116 for (var i = 0; i < locations.length; ++i) { |
| 117 var uiLocation = WebInspector.cssWorkspaceBinding.rawLocationToUILocation(
locations[i]); |
| 118 if (!uiLocation) |
| 119 continue; |
| 120 var descriptor = String.sprintf( |
| 121 '%s:%d:%d', uiLocation.uiSourceCode.url(), uiLocation.lineNumber + 1,
uiLocation.columnNumber + 1); |
| 122 uiLocations.set(descriptor, uiLocation); |
| 123 } |
| 124 |
| 125 var contextMenuItems = uiLocations.keysArray().sort(); |
| 126 var contextMenu = new WebInspector.ContextMenu(event); |
| 127 var subMenuItem = contextMenu.appendSubMenuItem(WebInspector.UIString.capita
lize('Reveal in ^source ^code')); |
| 128 for (var i = 0; i < contextMenuItems.length; ++i) { |
| 129 var title = contextMenuItems[i]; |
| 130 subMenuItem.appendItem( |
| 131 title, |
| 132 this._revealSourceLocation.bind(this, /** @type {!WebInspector.UILocat
ion} */ (uiLocations.get(title)))); |
| 133 } |
| 134 contextMenu.show(); |
| 135 } |
| 136 |
| 137 /** |
| 138 * @param {!WebInspector.UILocation} location |
| 139 */ |
| 140 _revealSourceLocation(location) { |
| 141 WebInspector.Revealer.reveal(location); |
| 142 } |
| 143 |
| 144 _scheduleMediaQueriesUpdate() { |
| 145 if (!this.isShowing()) |
| 146 return; |
| 147 this._mediaThrottler.schedule(this._refetchMediaQueries.bind(this)); |
| 148 } |
| 149 |
| 150 _refetchMediaQueries() { |
| 151 if (!this.isShowing() || !this._cssModel) |
| 152 return Promise.resolve(); |
| 153 |
| 154 return this._cssModel.mediaQueriesPromise().then(this._rebuildMediaQueries.b
ind(this)); |
| 155 } |
| 156 |
| 157 /** |
| 158 * @param {!Array.<!WebInspector.MediaQueryInspector.MediaQueryUIModel>} model
s |
| 159 * @return {!Array.<!WebInspector.MediaQueryInspector.MediaQueryUIModel>} |
| 160 */ |
| 161 _squashAdjacentEqual(models) { |
| 162 var filtered = []; |
| 163 for (var i = 0; i < models.length; ++i) { |
| 164 var last = filtered.peekLast(); |
| 165 if (!last || !last.equals(models[i])) |
| 166 filtered.push(models[i]); |
| 167 } |
| 168 return filtered; |
| 169 } |
| 170 |
| 171 /** |
| 172 * @param {!Array.<!WebInspector.CSSMedia>} cssMedias |
| 173 */ |
| 174 _rebuildMediaQueries(cssMedias) { |
| 175 var queryModels = []; |
| 176 for (var i = 0; i < cssMedias.length; ++i) { |
| 177 var cssMedia = cssMedias[i]; |
| 178 if (!cssMedia.mediaList) |
| 179 continue; |
| 180 for (var j = 0; j < cssMedia.mediaList.length; ++j) { |
| 181 var mediaQuery = cssMedia.mediaList[j]; |
| 182 var queryModel = WebInspector.MediaQueryInspector.MediaQueryUIModel.crea
teFromMediaQuery(cssMedia, mediaQuery); |
| 183 if (queryModel && queryModel.rawLocation()) |
| 184 queryModels.push(queryModel); |
| 185 } |
| 186 } |
| 187 queryModels.sort(compareModels); |
| 188 queryModels = this._squashAdjacentEqual(queryModels); |
| 189 |
| 190 var allEqual = this._cachedQueryModels && this._cachedQueryModels.length ===
queryModels.length; |
| 191 for (var i = 0; allEqual && i < queryModels.length; ++i) |
| 192 allEqual = allEqual && this._cachedQueryModels[i].equals(queryModels[i]); |
| 193 if (allEqual) |
| 194 return; |
| 195 this._cachedQueryModels = queryModels; |
| 196 this._renderMediaQueries(); |
| 197 |
| 198 /** |
| 199 * @param {!WebInspector.MediaQueryInspector.MediaQueryUIModel} model1 |
| 200 * @param {!WebInspector.MediaQueryInspector.MediaQueryUIModel} model2 |
| 201 * @return {number} |
| 202 */ |
| 203 function compareModels(model1, model2) { |
| 204 return model1.compareTo(model2); |
| 205 } |
| 206 } |
| 207 |
| 208 _renderMediaQueries() { |
| 209 if (!this._cachedQueryModels || !this.isShowing()) |
| 210 return; |
| 211 |
| 212 var markers = []; |
| 213 var lastMarker = null; |
| 214 for (var i = 0; i < this._cachedQueryModels.length; ++i) { |
| 215 var model = this._cachedQueryModels[i]; |
| 216 if (lastMarker && lastMarker.model.dimensionsEqual(model)) { |
| 217 lastMarker.locations.push(model.rawLocation()); |
| 218 lastMarker.active = lastMarker.active || model.active(); |
| 219 } else { |
| 220 lastMarker = {active: model.active(), model: model, locations: [model.ra
wLocation()]}; |
| 221 markers.push(lastMarker); |
| 222 } |
| 223 } |
| 224 |
| 225 this.contentElement.removeChildren(); |
| 226 |
| 227 var container = null; |
| 228 for (var i = 0; i < markers.length; ++i) { |
| 229 if (!i || markers[i].model.section() !== markers[i - 1].model.section()) |
| 230 container = this.contentElement.createChild('div', 'media-inspector-mark
er-container'); |
| 231 var marker = markers[i]; |
| 232 var bar = this._createElementFromMediaQueryModel(marker.model); |
| 233 bar._model = marker.model; |
| 234 bar._locations = marker.locations; |
| 235 bar.classList.toggle('media-inspector-marker-inactive', !marker.active); |
| 236 container.appendChild(bar); |
| 237 } |
| 238 } |
| 239 |
| 240 /** |
| 241 * @return {number} |
| 242 */ |
| 243 _zoomFactor() { |
| 244 return WebInspector.zoomManager.zoomFactor() / this._scale; |
| 245 } |
| 246 |
| 247 /** |
| 248 * @override |
| 249 */ |
| 250 wasShown() { |
| 251 this._scheduleMediaQueriesUpdate(); |
| 252 } |
| 253 |
| 254 /** |
| 255 * @param {!WebInspector.MediaQueryInspector.MediaQueryUIModel} model |
| 256 * @return {!Element} |
| 257 */ |
| 258 _createElementFromMediaQueryModel(model) { |
| 259 var zoomFactor = this._zoomFactor(); |
| 260 var minWidthValue = model.minWidthExpression() ? model.minWidthExpression().
computedLength() / zoomFactor : 0; |
| 261 var maxWidthValue = model.maxWidthExpression() ? model.maxWidthExpression().
computedLength() / zoomFactor : 0; |
| 262 var result = createElementWithClass('div', 'media-inspector-bar'); |
| 263 |
| 264 if (model.section() === WebInspector.MediaQueryInspector.Section.Max) { |
| 265 result.createChild('div', 'media-inspector-marker-spacer'); |
| 266 var markerElement = result.createChild('div', 'media-inspector-marker medi
a-inspector-marker-max-width'); |
| 267 markerElement.style.width = maxWidthValue + 'px'; |
| 268 markerElement.title = model.mediaText(); |
| 269 appendLabel(markerElement, model.maxWidthExpression(), false, false); |
| 270 appendLabel(markerElement, model.maxWidthExpression(), true, true); |
| 271 result.createChild('div', 'media-inspector-marker-spacer'); |
| 272 } |
| 273 |
| 274 if (model.section() === WebInspector.MediaQueryInspector.Section.MinMax) { |
| 275 result.createChild('div', 'media-inspector-marker-spacer'); |
| 276 var leftElement = result.createChild('div', 'media-inspector-marker media-
inspector-marker-min-max-width'); |
| 277 leftElement.style.width = (maxWidthValue - minWidthValue) * 0.5 + 'px'; |
| 278 leftElement.title = model.mediaText(); |
| 279 appendLabel(leftElement, model.minWidthExpression(), true, false); |
| 280 appendLabel(leftElement, model.maxWidthExpression(), false, true); |
| 281 result.createChild('div', 'media-inspector-marker-spacer').style.flex = '0
0 ' + minWidthValue + 'px'; |
| 282 var rightElement = result.createChild('div', 'media-inspector-marker media
-inspector-marker-min-max-width'); |
| 283 rightElement.style.width = (maxWidthValue - minWidthValue) * 0.5 + 'px'; |
| 284 rightElement.title = model.mediaText(); |
| 285 appendLabel(rightElement, model.minWidthExpression(), true, false); |
| 286 appendLabel(rightElement, model.maxWidthExpression(), false, true); |
| 287 result.createChild('div', 'media-inspector-marker-spacer'); |
| 288 } |
| 289 |
| 290 if (model.section() === WebInspector.MediaQueryInspector.Section.Min) { |
| 291 var leftElement = result.createChild( |
| 292 'div', 'media-inspector-marker media-inspector-marker-min-width media-
inspector-marker-min-width-left'); |
| 293 leftElement.title = model.mediaText(); |
| 294 appendLabel(leftElement, model.minWidthExpression(), false, false); |
| 295 result.createChild('div', 'media-inspector-marker-spacer').style.flex = '0
0 ' + minWidthValue + 'px'; |
| 296 var rightElement = result.createChild( |
| 297 'div', 'media-inspector-marker media-inspector-marker-min-width media-
inspector-marker-min-width-right'); |
| 298 rightElement.title = model.mediaText(); |
| 299 appendLabel(rightElement, model.minWidthExpression(), true, true); |
| 300 } |
| 301 |
| 302 function appendLabel(marker, expression, atLeft, leftAlign) { |
| 303 marker |
| 304 .createChild( |
| 305 'div', |
| 306 'media-inspector-marker-label-container ' + (atLeft ? 'media-inspe
ctor-marker-label-container-left' : |
| 307 'media-inspe
ctor-marker-label-container-right')) |
| 308 .createChild( |
| 309 'span', 'media-inspector-marker-label ' + |
| 310 (leftAlign ? 'media-inspector-label-left' : 'media-inspector-l
abel-right')) |
| 311 .textContent = expression.value() + expression.unit(); |
| 312 } |
| 313 |
| 314 return result; |
| 315 } |
27 }; | 316 }; |
28 | 317 |
29 /** | 318 /** |
30 * @enum {number} | 319 * @enum {number} |
31 */ | 320 */ |
32 WebInspector.MediaQueryInspector.Section = { | 321 WebInspector.MediaQueryInspector.Section = { |
33 Max: 0, | 322 Max: 0, |
34 MinMax: 1, | 323 MinMax: 1, |
35 Min: 2 | 324 Min: 2 |
36 }; | 325 }; |
37 | 326 |
38 WebInspector.MediaQueryInspector.prototype = { | |
39 /** | |
40 * @override | |
41 * @param {!WebInspector.Target} target | |
42 */ | |
43 targetAdded: function(target) | |
44 { | |
45 // FIXME: adapt this to multiple targets. | |
46 if (this._cssModel) | |
47 return; | |
48 this._cssModel = WebInspector.CSSModel.fromTarget(target); | |
49 if (!this._cssModel) | |
50 return; | |
51 this._cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetA
dded, this._scheduleMediaQueriesUpdate, this); | |
52 this._cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetR
emoved, this._scheduleMediaQueriesUpdate, this); | |
53 this._cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetC
hanged, this._scheduleMediaQueriesUpdate, this); | |
54 this._cssModel.addEventListener(WebInspector.CSSModel.Events.MediaQueryR
esultChanged, this._scheduleMediaQueriesUpdate, this); | |
55 }, | |
56 | |
57 /** | |
58 * @override | |
59 * @param {!WebInspector.Target} target | |
60 */ | |
61 targetRemoved: function(target) | |
62 { | |
63 if (WebInspector.CSSModel.fromTarget(target) !== this._cssModel) | |
64 return; | |
65 this._cssModel.removeEventListener(WebInspector.CSSModel.Events.StyleShe
etAdded, this._scheduleMediaQueriesUpdate, this); | |
66 this._cssModel.removeEventListener(WebInspector.CSSModel.Events.StyleShe
etRemoved, this._scheduleMediaQueriesUpdate, this); | |
67 this._cssModel.removeEventListener(WebInspector.CSSModel.Events.StyleShe
etChanged, this._scheduleMediaQueriesUpdate, this); | |
68 this._cssModel.removeEventListener(WebInspector.CSSModel.Events.MediaQue
ryResultChanged, this._scheduleMediaQueriesUpdate, this); | |
69 delete this._cssModel; | |
70 }, | |
71 | |
72 /** | |
73 * @param {number} scale | |
74 */ | |
75 setAxisTransform: function(scale) | |
76 { | |
77 if (Math.abs(this._scale - scale) < 1e-8) | |
78 return; | |
79 this._scale = scale; | |
80 this._renderMediaQueries(); | |
81 }, | |
82 | |
83 /** | |
84 * @param {!Event} event | |
85 */ | |
86 _onMediaQueryClicked: function(event) | |
87 { | |
88 var mediaQueryMarker = event.target.enclosingNodeOrSelfWithClass("media-
inspector-bar"); | |
89 if (!mediaQueryMarker) | |
90 return; | |
91 | |
92 var model = mediaQueryMarker._model; | |
93 if (model.section() === WebInspector.MediaQueryInspector.Section.Max) { | |
94 this._setWidthCallback(model.maxWidthExpression().computedLength()); | |
95 return; | |
96 } | |
97 if (model.section() === WebInspector.MediaQueryInspector.Section.Min) { | |
98 this._setWidthCallback(model.minWidthExpression().computedLength()); | |
99 return; | |
100 } | |
101 var currentWidth = this._getWidthCallback(); | |
102 if (currentWidth !== model.minWidthExpression().computedLength()) | |
103 this._setWidthCallback(model.minWidthExpression().computedLength()); | |
104 else | |
105 this._setWidthCallback(model.maxWidthExpression().computedLength()); | |
106 }, | |
107 | |
108 /** | |
109 * @param {!Event} event | |
110 */ | |
111 _onContextMenu: function(event) | |
112 { | |
113 if (!this._cssModel || !this._cssModel.isEnabled()) | |
114 return; | |
115 | |
116 var mediaQueryMarker = event.target.enclosingNodeOrSelfWithClass("media-
inspector-bar"); | |
117 if (!mediaQueryMarker) | |
118 return; | |
119 | |
120 var locations = mediaQueryMarker._locations; | |
121 var uiLocations = new Map(); | |
122 for (var i = 0; i < locations.length; ++i) { | |
123 var uiLocation = WebInspector.cssWorkspaceBinding.rawLocationToUILoc
ation(locations[i]); | |
124 if (!uiLocation) | |
125 continue; | |
126 var descriptor = String.sprintf("%s:%d:%d", uiLocation.uiSourceCode.
url(), uiLocation.lineNumber + 1, uiLocation.columnNumber + 1); | |
127 uiLocations.set(descriptor, uiLocation); | |
128 } | |
129 | |
130 var contextMenuItems = uiLocations.keysArray().sort(); | |
131 var contextMenu = new WebInspector.ContextMenu(event); | |
132 var subMenuItem = contextMenu.appendSubMenuItem(WebInspector.UIString.ca
pitalize("Reveal in ^source ^code")); | |
133 for (var i = 0; i < contextMenuItems.length; ++i) { | |
134 var title = contextMenuItems[i]; | |
135 subMenuItem.appendItem(title, this._revealSourceLocation.bind(this,
/** @type {!WebInspector.UILocation} */(uiLocations.get(title)))); | |
136 } | |
137 contextMenu.show(); | |
138 }, | |
139 | |
140 /** | |
141 * @param {!WebInspector.UILocation} location | |
142 */ | |
143 _revealSourceLocation: function(location) | |
144 { | |
145 WebInspector.Revealer.reveal(location); | |
146 }, | |
147 | |
148 _scheduleMediaQueriesUpdate: function() | |
149 { | |
150 if (!this.isShowing()) | |
151 return; | |
152 this._mediaThrottler.schedule(this._refetchMediaQueries.bind(this)); | |
153 }, | |
154 | |
155 _refetchMediaQueries: function() | |
156 { | |
157 if (!this.isShowing() || !this._cssModel) | |
158 return Promise.resolve(); | |
159 | |
160 return this._cssModel.mediaQueriesPromise() | |
161 .then(this._rebuildMediaQueries.bind(this)); | |
162 }, | |
163 | |
164 /** | |
165 * @param {!Array.<!WebInspector.MediaQueryInspector.MediaQueryUIModel>} mod
els | |
166 * @return {!Array.<!WebInspector.MediaQueryInspector.MediaQueryUIModel>} | |
167 */ | |
168 _squashAdjacentEqual: function(models) | |
169 { | |
170 var filtered = []; | |
171 for (var i = 0; i < models.length; ++i) { | |
172 var last = filtered.peekLast(); | |
173 if (!last || !last.equals(models[i])) | |
174 filtered.push(models[i]); | |
175 } | |
176 return filtered; | |
177 }, | |
178 | |
179 /** | |
180 * @param {!Array.<!WebInspector.CSSMedia>} cssMedias | |
181 */ | |
182 _rebuildMediaQueries: function(cssMedias) | |
183 { | |
184 var queryModels = []; | |
185 for (var i = 0; i < cssMedias.length; ++i) { | |
186 var cssMedia = cssMedias[i]; | |
187 if (!cssMedia.mediaList) | |
188 continue; | |
189 for (var j = 0; j < cssMedia.mediaList.length; ++j) { | |
190 var mediaQuery = cssMedia.mediaList[j]; | |
191 var queryModel = WebInspector.MediaQueryInspector.MediaQueryUIMo
del.createFromMediaQuery(cssMedia, mediaQuery); | |
192 if (queryModel && queryModel.rawLocation()) | |
193 queryModels.push(queryModel); | |
194 } | |
195 } | |
196 queryModels.sort(compareModels); | |
197 queryModels = this._squashAdjacentEqual(queryModels); | |
198 | |
199 var allEqual = this._cachedQueryModels && this._cachedQueryModels.length
=== queryModels.length; | |
200 for (var i = 0; allEqual && i < queryModels.length; ++i) | |
201 allEqual = allEqual && this._cachedQueryModels[i].equals(queryModels
[i]); | |
202 if (allEqual) | |
203 return; | |
204 this._cachedQueryModels = queryModels; | |
205 this._renderMediaQueries(); | |
206 | |
207 /** | |
208 * @param {!WebInspector.MediaQueryInspector.MediaQueryUIModel} model1 | |
209 * @param {!WebInspector.MediaQueryInspector.MediaQueryUIModel} model2 | |
210 * @return {number} | |
211 */ | |
212 function compareModels(model1, model2) | |
213 { | |
214 return model1.compareTo(model2); | |
215 } | |
216 }, | |
217 | |
218 _renderMediaQueries: function() | |
219 { | |
220 if (!this._cachedQueryModels || !this.isShowing()) | |
221 return; | |
222 | |
223 var markers = []; | |
224 var lastMarker = null; | |
225 for (var i = 0; i < this._cachedQueryModels.length; ++i) { | |
226 var model = this._cachedQueryModels[i]; | |
227 if (lastMarker && lastMarker.model.dimensionsEqual(model)) { | |
228 lastMarker.locations.push(model.rawLocation()); | |
229 lastMarker.active = lastMarker.active || model.active(); | |
230 } else { | |
231 lastMarker = { | |
232 active: model.active(), | |
233 model: model, | |
234 locations: [ model.rawLocation() ] | |
235 }; | |
236 markers.push(lastMarker); | |
237 } | |
238 } | |
239 | |
240 this.contentElement.removeChildren(); | |
241 | |
242 var container = null; | |
243 for (var i = 0; i < markers.length; ++i) { | |
244 if (!i || markers[i].model.section() !== markers[i - 1].model.sectio
n()) | |
245 container = this.contentElement.createChild("div", "media-inspec
tor-marker-container"); | |
246 var marker = markers[i]; | |
247 var bar = this._createElementFromMediaQueryModel(marker.model); | |
248 bar._model = marker.model; | |
249 bar._locations = marker.locations; | |
250 bar.classList.toggle("media-inspector-marker-inactive", !marker.acti
ve); | |
251 container.appendChild(bar); | |
252 } | |
253 }, | |
254 | |
255 /** | |
256 * @return {number} | |
257 */ | |
258 _zoomFactor: function() | |
259 { | |
260 return WebInspector.zoomManager.zoomFactor() / this._scale; | |
261 }, | |
262 | |
263 wasShown: function() | |
264 { | |
265 this._scheduleMediaQueriesUpdate(); | |
266 }, | |
267 | |
268 /** | |
269 * @param {!WebInspector.MediaQueryInspector.MediaQueryUIModel} model | |
270 * @return {!Element} | |
271 */ | |
272 _createElementFromMediaQueryModel: function(model) | |
273 { | |
274 var zoomFactor = this._zoomFactor(); | |
275 var minWidthValue = model.minWidthExpression() ? model.minWidthExpressio
n().computedLength() / zoomFactor : 0; | |
276 var maxWidthValue = model.maxWidthExpression() ? model.maxWidthExpressio
n().computedLength() / zoomFactor : 0; | |
277 var result = createElementWithClass("div", "media-inspector-bar"); | |
278 | |
279 if (model.section() === WebInspector.MediaQueryInspector.Section.Max) { | |
280 result.createChild("div", "media-inspector-marker-spacer"); | |
281 var markerElement = result.createChild("div", "media-inspector-marke
r media-inspector-marker-max-width"); | |
282 markerElement.style.width = maxWidthValue + "px"; | |
283 markerElement.title = model.mediaText(); | |
284 appendLabel(markerElement, model.maxWidthExpression(), false, false)
; | |
285 appendLabel(markerElement, model.maxWidthExpression(), true, true); | |
286 result.createChild("div", "media-inspector-marker-spacer"); | |
287 } | |
288 | |
289 if (model.section() === WebInspector.MediaQueryInspector.Section.MinMax)
{ | |
290 result.createChild("div", "media-inspector-marker-spacer"); | |
291 var leftElement = result.createChild("div", "media-inspector-marker
media-inspector-marker-min-max-width"); | |
292 leftElement.style.width = (maxWidthValue - minWidthValue) * 0.5 + "p
x"; | |
293 leftElement.title = model.mediaText(); | |
294 appendLabel(leftElement, model.minWidthExpression(), true, false); | |
295 appendLabel(leftElement, model.maxWidthExpression(), false, true); | |
296 result.createChild("div", "media-inspector-marker-spacer").style.fle
x = "0 0 " + minWidthValue + "px"; | |
297 var rightElement = result.createChild("div", "media-inspector-marker
media-inspector-marker-min-max-width"); | |
298 rightElement.style.width = (maxWidthValue - minWidthValue) * 0.5 +
"px"; | |
299 rightElement.title = model.mediaText(); | |
300 appendLabel(rightElement, model.minWidthExpression(), true, false); | |
301 appendLabel(rightElement, model.maxWidthExpression(), false, true); | |
302 result.createChild("div", "media-inspector-marker-spacer"); | |
303 } | |
304 | |
305 if (model.section() === WebInspector.MediaQueryInspector.Section.Min) { | |
306 var leftElement = result.createChild("div", "media-inspector-marker
media-inspector-marker-min-width media-inspector-marker-min-width-left"); | |
307 leftElement.title = model.mediaText(); | |
308 appendLabel(leftElement, model.minWidthExpression(), false, false); | |
309 result.createChild("div", "media-inspector-marker-spacer").style.fle
x = "0 0 " + minWidthValue + "px"; | |
310 var rightElement = result.createChild("div", "media-inspector-marker
media-inspector-marker-min-width media-inspector-marker-min-width-right"); | |
311 rightElement.title = model.mediaText(); | |
312 appendLabel(rightElement, model.minWidthExpression(), true, true); | |
313 } | |
314 | |
315 function appendLabel(marker, expression, atLeft, leftAlign) | |
316 { | |
317 marker.createChild("div", "media-inspector-marker-label-container "
+ (atLeft ? "media-inspector-marker-label-container-left" : "media-inspector-mar
ker-label-container-right")) | |
318 .createChild("span", "media-inspector-marker-label " + (leftAlig
n ? "media-inspector-label-left" : "media-inspector-label-right")) | |
319 .textContent = expression.value() + expression.unit(); | |
320 } | |
321 | |
322 return result; | |
323 }, | |
324 | |
325 __proto__: WebInspector.Widget.prototype | |
326 }; | |
327 | |
328 /** | 327 /** |
329 * @constructor | 328 * @unrestricted |
330 * @param {!WebInspector.CSSMedia} cssMedia | |
331 * @param {?WebInspector.CSSMediaQueryExpression} minWidthExpression | |
332 * @param {?WebInspector.CSSMediaQueryExpression} maxWidthExpression | |
333 * @param {boolean} active | |
334 */ | 329 */ |
335 WebInspector.MediaQueryInspector.MediaQueryUIModel = function(cssMedia, minWidth
Expression, maxWidthExpression, active) | 330 WebInspector.MediaQueryInspector.MediaQueryUIModel = class { |
336 { | 331 /** |
| 332 * @param {!WebInspector.CSSMedia} cssMedia |
| 333 * @param {?WebInspector.CSSMediaQueryExpression} minWidthExpression |
| 334 * @param {?WebInspector.CSSMediaQueryExpression} maxWidthExpression |
| 335 * @param {boolean} active |
| 336 */ |
| 337 constructor(cssMedia, minWidthExpression, maxWidthExpression, active) { |
337 this._cssMedia = cssMedia; | 338 this._cssMedia = cssMedia; |
338 this._minWidthExpression = minWidthExpression; | 339 this._minWidthExpression = minWidthExpression; |
339 this._maxWidthExpression = maxWidthExpression; | 340 this._maxWidthExpression = maxWidthExpression; |
340 this._active = active; | 341 this._active = active; |
341 if (maxWidthExpression && !minWidthExpression) | 342 if (maxWidthExpression && !minWidthExpression) |
342 this._section = WebInspector.MediaQueryInspector.Section.Max; | 343 this._section = WebInspector.MediaQueryInspector.Section.Max; |
343 else if (minWidthExpression && maxWidthExpression) | 344 else if (minWidthExpression && maxWidthExpression) |
344 this._section = WebInspector.MediaQueryInspector.Section.MinMax; | 345 this._section = WebInspector.MediaQueryInspector.Section.MinMax; |
345 else | 346 else |
346 this._section = WebInspector.MediaQueryInspector.Section.Min; | 347 this._section = WebInspector.MediaQueryInspector.Section.Min; |
347 }; | 348 } |
348 | 349 |
349 /** | 350 /** |
350 * @param {!WebInspector.CSSMedia} cssMedia | 351 * @param {!WebInspector.CSSMedia} cssMedia |
351 * @param {!WebInspector.CSSMediaQuery} mediaQuery | 352 * @param {!WebInspector.CSSMediaQuery} mediaQuery |
352 * @return {?WebInspector.MediaQueryInspector.MediaQueryUIModel} | 353 * @return {?WebInspector.MediaQueryInspector.MediaQueryUIModel} |
353 */ | 354 */ |
354 WebInspector.MediaQueryInspector.MediaQueryUIModel.createFromMediaQuery = functi
on(cssMedia, mediaQuery) | 355 static createFromMediaQuery(cssMedia, mediaQuery) { |
355 { | |
356 var maxWidthExpression = null; | 356 var maxWidthExpression = null; |
357 var maxWidthPixels = Number.MAX_VALUE; | 357 var maxWidthPixels = Number.MAX_VALUE; |
358 var minWidthExpression = null; | 358 var minWidthExpression = null; |
359 var minWidthPixels = Number.MIN_VALUE; | 359 var minWidthPixels = Number.MIN_VALUE; |
360 var expressions = mediaQuery.expressions(); | 360 var expressions = mediaQuery.expressions(); |
361 for (var i = 0; i < expressions.length; ++i) { | 361 for (var i = 0; i < expressions.length; ++i) { |
362 var expression = expressions[i]; | 362 var expression = expressions[i]; |
363 var feature = expression.feature(); | 363 var feature = expression.feature(); |
364 if (feature.indexOf("width") === -1) | 364 if (feature.indexOf('width') === -1) |
365 continue; | 365 continue; |
366 var pixels = expression.computedLength(); | 366 var pixels = expression.computedLength(); |
367 if (feature.startsWith("max-") && pixels < maxWidthPixels) { | 367 if (feature.startsWith('max-') && pixels < maxWidthPixels) { |
368 maxWidthExpression = expression; | 368 maxWidthExpression = expression; |
369 maxWidthPixels = pixels; | 369 maxWidthPixels = pixels; |
370 } else if (feature.startsWith("min-") && pixels > minWidthPixels) { | 370 } else if (feature.startsWith('min-') && pixels > minWidthPixels) { |
371 minWidthExpression = expression; | 371 minWidthExpression = expression; |
372 minWidthPixels = pixels; | 372 minWidthPixels = pixels; |
373 } | 373 } |
374 } | 374 } |
375 if (minWidthPixels > maxWidthPixels || (!maxWidthExpression && !minWidthExpr
ession)) | 375 if (minWidthPixels > maxWidthPixels || (!maxWidthExpression && !minWidthExpr
ession)) |
376 return null; | 376 return null; |
377 | 377 |
378 return new WebInspector.MediaQueryInspector.MediaQueryUIModel(cssMedia, minW
idthExpression, maxWidthExpression, mediaQuery.active()); | 378 return new WebInspector.MediaQueryInspector.MediaQueryUIModel( |
| 379 cssMedia, minWidthExpression, maxWidthExpression, mediaQuery.active()); |
| 380 } |
| 381 |
| 382 /** |
| 383 * @param {!WebInspector.MediaQueryInspector.MediaQueryUIModel} other |
| 384 * @return {boolean} |
| 385 */ |
| 386 equals(other) { |
| 387 return this.compareTo(other) === 0; |
| 388 } |
| 389 |
| 390 /** |
| 391 * @param {!WebInspector.MediaQueryInspector.MediaQueryUIModel} other |
| 392 * @return {boolean} |
| 393 */ |
| 394 dimensionsEqual(other) { |
| 395 return this.section() === other.section() && |
| 396 (!this.minWidthExpression() || |
| 397 (this.minWidthExpression().computedLength() === other.minWidthExpressio
n().computedLength())) && |
| 398 (!this.maxWidthExpression() || |
| 399 (this.maxWidthExpression().computedLength() === other.maxWidthExpressio
n().computedLength())); |
| 400 } |
| 401 |
| 402 /** |
| 403 * @param {!WebInspector.MediaQueryInspector.MediaQueryUIModel} other |
| 404 * @return {number} |
| 405 */ |
| 406 compareTo(other) { |
| 407 if (this.section() !== other.section()) |
| 408 return this.section() - other.section(); |
| 409 if (this.dimensionsEqual(other)) { |
| 410 var myLocation = this.rawLocation(); |
| 411 var otherLocation = other.rawLocation(); |
| 412 if (!myLocation && !otherLocation) |
| 413 return this.mediaText().compareTo(other.mediaText()); |
| 414 if (myLocation && !otherLocation) |
| 415 return 1; |
| 416 if (!myLocation && otherLocation) |
| 417 return -1; |
| 418 if (this.active() !== other.active()) |
| 419 return this.active() ? -1 : 1; |
| 420 return myLocation.url.compareTo(otherLocation.url) || myLocation.lineNumbe
r - otherLocation.lineNumber || |
| 421 myLocation.columnNumber - otherLocation.columnNumber; |
| 422 } |
| 423 if (this.section() === WebInspector.MediaQueryInspector.Section.Max) |
| 424 return other.maxWidthExpression().computedLength() - this.maxWidthExpressi
on().computedLength(); |
| 425 if (this.section() === WebInspector.MediaQueryInspector.Section.Min) |
| 426 return this.minWidthExpression().computedLength() - other.minWidthExpressi
on().computedLength(); |
| 427 return this.minWidthExpression().computedLength() - other.minWidthExpression
().computedLength() || |
| 428 other.maxWidthExpression().computedLength() - this.maxWidthExpression().
computedLength(); |
| 429 } |
| 430 |
| 431 /** |
| 432 * @return {!WebInspector.MediaQueryInspector.Section} |
| 433 */ |
| 434 section() { |
| 435 return this._section; |
| 436 } |
| 437 |
| 438 /** |
| 439 * @return {string} |
| 440 */ |
| 441 mediaText() { |
| 442 return this._cssMedia.text; |
| 443 } |
| 444 |
| 445 /** |
| 446 * @return {?WebInspector.CSSLocation} |
| 447 */ |
| 448 rawLocation() { |
| 449 if (!this._rawLocation) |
| 450 this._rawLocation = this._cssMedia.rawLocation(); |
| 451 return this._rawLocation; |
| 452 } |
| 453 |
| 454 /** |
| 455 * @return {?WebInspector.CSSMediaQueryExpression} |
| 456 */ |
| 457 minWidthExpression() { |
| 458 return this._minWidthExpression; |
| 459 } |
| 460 |
| 461 /** |
| 462 * @return {?WebInspector.CSSMediaQueryExpression} |
| 463 */ |
| 464 maxWidthExpression() { |
| 465 return this._maxWidthExpression; |
| 466 } |
| 467 |
| 468 /** |
| 469 * @return {boolean} |
| 470 */ |
| 471 active() { |
| 472 return this._active; |
| 473 } |
379 }; | 474 }; |
380 | 475 |
381 WebInspector.MediaQueryInspector.MediaQueryUIModel.prototype = { | 476 |
382 /** | |
383 * @param {!WebInspector.MediaQueryInspector.MediaQueryUIModel} other | |
384 * @return {boolean} | |
385 */ | |
386 equals: function(other) | |
387 { | |
388 return this.compareTo(other) === 0; | |
389 }, | |
390 | |
391 /** | |
392 * @param {!WebInspector.MediaQueryInspector.MediaQueryUIModel} other | |
393 * @return {boolean} | |
394 */ | |
395 dimensionsEqual: function(other) | |
396 { | |
397 return this.section() === other.section() | |
398 && (!this.minWidthExpression() || (this.minWidthExpression().compute
dLength() === other.minWidthExpression().computedLength())) | |
399 && (!this.maxWidthExpression() || (this.maxWidthExpression().compute
dLength() === other.maxWidthExpression().computedLength())); | |
400 }, | |
401 | |
402 /** | |
403 * @param {!WebInspector.MediaQueryInspector.MediaQueryUIModel} other | |
404 * @return {number} | |
405 */ | |
406 compareTo: function(other) | |
407 { | |
408 if (this.section() !== other.section()) | |
409 return this.section() - other.section(); | |
410 if (this.dimensionsEqual(other)) { | |
411 var myLocation = this.rawLocation(); | |
412 var otherLocation = other.rawLocation(); | |
413 if (!myLocation && !otherLocation) | |
414 return this.mediaText().compareTo(other.mediaText()); | |
415 if (myLocation && !otherLocation) | |
416 return 1; | |
417 if (!myLocation && otherLocation) | |
418 return -1; | |
419 if (this.active() !== other.active()) | |
420 return this.active() ? -1 : 1; | |
421 return myLocation.url.compareTo(otherLocation.url) || myLocation.lin
eNumber - otherLocation.lineNumber || myLocation.columnNumber - otherLocation.co
lumnNumber; | |
422 } | |
423 if (this.section() === WebInspector.MediaQueryInspector.Section.Max) | |
424 return other.maxWidthExpression().computedLength() - this.maxWidthEx
pression().computedLength(); | |
425 if (this.section() === WebInspector.MediaQueryInspector.Section.Min) | |
426 return this.minWidthExpression().computedLength() - other.minWidthEx
pression().computedLength(); | |
427 return this.minWidthExpression().computedLength() - other.minWidthExpres
sion().computedLength() || other.maxWidthExpression().computedLength() - this.ma
xWidthExpression().computedLength(); | |
428 }, | |
429 | |
430 /** | |
431 * @return {!WebInspector.MediaQueryInspector.Section} | |
432 */ | |
433 section: function() | |
434 { | |
435 return this._section; | |
436 }, | |
437 | |
438 /** | |
439 * @return {string} | |
440 */ | |
441 mediaText: function() | |
442 { | |
443 return this._cssMedia.text; | |
444 }, | |
445 | |
446 /** | |
447 * @return {?WebInspector.CSSLocation} | |
448 */ | |
449 rawLocation: function() | |
450 { | |
451 if (!this._rawLocation) | |
452 this._rawLocation = this._cssMedia.rawLocation(); | |
453 return this._rawLocation; | |
454 }, | |
455 | |
456 /** | |
457 * @return {?WebInspector.CSSMediaQueryExpression} | |
458 */ | |
459 minWidthExpression: function() | |
460 { | |
461 return this._minWidthExpression; | |
462 }, | |
463 | |
464 /** | |
465 * @return {?WebInspector.CSSMediaQueryExpression} | |
466 */ | |
467 maxWidthExpression: function() | |
468 { | |
469 return this._maxWidthExpression; | |
470 }, | |
471 | |
472 /** | |
473 * @return {boolean} | |
474 */ | |
475 active: function() | |
476 { | |
477 return this._active; | |
478 } | |
479 }; | |
OLD | NEW |