Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(105)

Side by Side Diff: Source/devtools/front_end/MediaQueryInspector.js

Issue 366633002: DevTools: Move jsdifflib to "sources", extract "toolbox" module (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 /**
6 * @constructor
7 * @extends {WebInspector.View}
8 */
9 WebInspector.MediaQueryInspector = function()
10 {
11 WebInspector.View.call(this);
12 this.element.classList.add("media-inspector-view", "media-inspector-view-emp ty");
13 this.element.addEventListener("click", this._onMediaQueryClicked.bind(this), false);
14 this.element.addEventListener("contextmenu", this._onContextMenu.bind(this), false);
15 this.element.addEventListener("webkitAnimationEnd", this._onAnimationEnd.bin d(this), false);
16 this._mediaThrottler = new WebInspector.Throttler(100);
17
18 this._translateZero = 0;
19 this._offset = 0;
20 this._scale = 1;
21
22 this._rulerDecorationLayer = document.createElementWithClass("div", "fill");
23 this._rulerDecorationLayer.classList.add("media-inspector-ruler-decoration") ;
24 this._rulerDecorationLayer.addEventListener("click", this._onRulerDecoration Clicked.bind(this), false);
25
26 WebInspector.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.Sty leSheetAdded, this._scheduleMediaQueriesUpdate, this);
27 WebInspector.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.Sty leSheetRemoved, this._scheduleMediaQueriesUpdate, this);
28 WebInspector.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.Sty leSheetChanged, this._scheduleMediaQueriesUpdate, this);
29 WebInspector.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.Med iaQueryResultChanged, this._scheduleMediaQueriesUpdate, this);
30 WebInspector.zoomManager.addEventListener(WebInspector.ZoomManager.Events.Zo omChanged, this._renderMediaQueries.bind(this), this);
31 this._scheduleMediaQueriesUpdate();
32 }
33
34 /**
35 * @enum {number}
36 */
37 WebInspector.MediaQueryInspector.Section = {
38 Max: 0,
39 MinMax: 1,
40 Min: 2
41 }
42
43 WebInspector.MediaQueryInspector.Events = {
44 HeightUpdated: "HeightUpdated"
45 }
46
47 WebInspector.MediaQueryInspector.prototype = {
48 /**
49 * @return {!Element}
50 */
51 rulerDecorationLayer: function()
52 {
53 return this._rulerDecorationLayer;
54 },
55
56 /**
57 * @return {!Array.<number>}
58 */
59 _mediaQueryThresholds: function()
60 {
61 if (!this._cachedQueryModels)
62 return [];
63 var thresholds = [];
64 for (var i = 0; i < this._cachedQueryModels.length; ++i) {
65 var model = this._cachedQueryModels[i];
66 if (model.minWidthExpression())
67 thresholds.push(model.minWidthExpression().computedLength());
68 if (model.maxWidthExpression())
69 thresholds.push(model.maxWidthExpression().computedLength());
70 }
71 thresholds.sortNumbers();
72 return thresholds;
73 },
74
75 /**
76 * @param {?Event} event
77 */
78 _onRulerDecorationClicked: function(event)
79 {
80 var thresholdElement = event.target.enclosingNodeOrSelfWithClass("media- inspector-threshold-serif");
81 if (!thresholdElement)
82 return;
83 WebInspector.settings.showMediaQueryInspector.set(true);
84 var revealValue = thresholdElement._value;
85 for (var mediaQueryContainer = this.element.firstChild; mediaQueryContai ner; mediaQueryContainer = mediaQueryContainer.nextSibling) {
86 var model = mediaQueryContainer._model;
87 if ((model.minWidthExpression() && Math.abs(model.minWidthExpression ().computedLength() - revealValue) === 0)
88 || (model.maxWidthExpression() && Math.abs(model.maxWidthExpress ion().computedLength() - revealValue) === 0)) {
89 mediaQueryContainer.scrollIntoViewIfNeeded(false);
90 var hasRunningAnimation = mediaQueryContainer.classList.contains ("media-inspector-marker-highlight-1") || mediaQueryContainer.classList.contains ("media-inspector-marker-highlight-2");
91 mediaQueryContainer.classList.toggle("media-inspector-marker-hig hlight-1");
92 if (hasRunningAnimation)
93 mediaQueryContainer.classList.toggle("media-inspector-marker -highlight-2");
94 return;
95 }
96 }
97 },
98
99 /**
100 * @param {?Event} event
101 */
102 _onAnimationEnd: function(event)
103 {
104 event.target.classList.remove("media-inspector-marker-highlight-1");
105 event.target.classList.remove("media-inspector-marker-highlight-2");
106 },
107
108 /**
109 * @param {number} translate
110 * @param {number} offset
111 * @param {number} scale
112 */
113 setAxisTransform: function(translate, offset, scale)
114 {
115 if (this._translateZero === translate && this._offset === offset && Math .abs(this._scale - scale) < 1e-8)
116 return;
117 this._translateZero = translate;
118 this._offset = offset;
119 this._scale = scale;
120 this._renderMediaQueries();
121 },
122
123 /**
124 * @param {boolean} enabled
125 */
126 setEnabled: function(enabled)
127 {
128 this._enabled = enabled;
129 },
130
131 /**
132 * @param {?Event} event
133 */
134 _onMediaQueryClicked: function(event)
135 {
136 var mediaQueryMarkerContainer = event.target.enclosingNodeOrSelfWithClas s("media-inspector-marker-container");
137 if (!mediaQueryMarkerContainer)
138 return;
139
140 /**
141 * @param {number} width
142 */
143 function setWidth(width)
144 {
145 WebInspector.overridesSupport.settings.deviceWidth.set(width);
146 WebInspector.overridesSupport.settings.emulateResolution.set(true);
147 }
148
149 var model = mediaQueryMarkerContainer._model;
150 if (model.section() === WebInspector.MediaQueryInspector.Section.Max) {
151 setWidth(model.maxWidthExpression().computedLength());
152 return;
153 }
154 if (model.section() === WebInspector.MediaQueryInspector.Section.Min) {
155 setWidth(model.minWidthExpression().computedLength());
156 return;
157 }
158 var currentWidth = WebInspector.overridesSupport.settings.deviceWidth.ge t();
159 if (currentWidth !== model.minWidthExpression().computedLength())
160 setWidth(model.minWidthExpression().computedLength());
161 else
162 setWidth(model.maxWidthExpression().computedLength());
163 },
164
165 /**
166 * @param {?Event} event
167 */
168 _onContextMenu: function(event)
169 {
170 var mediaQueryMarkerContainer = event.target.enclosingNodeOrSelfWithClas s("media-inspector-marker-container");
171 if (!mediaQueryMarkerContainer)
172 return;
173
174 var locations = mediaQueryMarkerContainer._locations;
175 var contextMenu = new WebInspector.ContextMenu(event);
176 var subMenuItem = contextMenu.appendSubMenuItem(WebInspector.UIString(We bInspector.useLowerCaseMenuTitles() ? "Reveal in source code" : "Reveal In Sourc e Code"));
177 for (var i = 0; i < locations.length; ++i) {
178 var location = locations[i];
179 var title = String.sprintf("%s:%d:%d", location.uiSourceCode.uri(), location.lineNumber + 1, location.columnNumber + 1);
180 subMenuItem.appendItem(title, this._revealSourceLocation.bind(this, location));
181 }
182 contextMenu.show();
183 },
184
185 /**
186 * @param {!WebInspector.UILocation} location
187 */
188 _revealSourceLocation: function(location)
189 {
190 WebInspector.Revealer.reveal(location);
191 },
192
193 _scheduleMediaQueriesUpdate: function()
194 {
195 if (!this._enabled)
196 return;
197 this._mediaThrottler.schedule(this._refetchMediaQueries.bind(this));
198 },
199
200 /**
201 * @param {!WebInspector.Throttler.FinishCallback} finishCallback
202 */
203 _refetchMediaQueries: function(finishCallback)
204 {
205 if (!this._enabled) {
206 finishCallback();
207 return;
208 }
209
210 /**
211 * @param {!Array.<!WebInspector.CSSMedia>} cssMedias
212 * @this {!WebInspector.MediaQueryInspector}
213 */
214 function callback(cssMedias)
215 {
216 this._rebuildMediaQueries(cssMedias);
217 finishCallback();
218 }
219 WebInspector.cssModel.getMediaQueries(callback.bind(this));
220 },
221
222 /**
223 * @param {!Array.<!WebInspector.MediaQueryInspector.MediaQueryUIModel>} mod els
224 * @return {!Array.<!WebInspector.MediaQueryInspector.MediaQueryUIModel>}
225 */
226 _squashAdjacentEqual: function(models)
227 {
228 var filtered = [];
229 for (var i = 0; i < models.length; ++i) {
230 var last = filtered.peekLast();
231 if (!last || !last.equals(models[i]))
232 filtered.push(models[i]);
233 }
234 return filtered;
235 },
236
237 /**
238 * @param {!Array.<!WebInspector.CSSMedia>} cssMedias
239 */
240 _rebuildMediaQueries: function(cssMedias)
241 {
242 var queryModels = [];
243 for (var i = 0; i < cssMedias.length; ++i) {
244 var cssMedia = cssMedias[i];
245 if (!cssMedia.mediaList)
246 continue;
247 for (var j = 0; j < cssMedia.mediaList.length; ++j) {
248 var mediaQueryExpressions = cssMedia.mediaList[j];
249 var queryModel = WebInspector.MediaQueryInspector.MediaQueryUIMo del.createFromMediaExpressions(cssMedia, mediaQueryExpressions);
250 if (queryModel)
251 queryModels.push(queryModel);
252 }
253 }
254 queryModels.sort(compareModels);
255 queryModels = this._squashAdjacentEqual(queryModels);
256
257 var allEqual = this._cachedQueryModels && this._cachedQueryModels.length == queryModels.length;
258 for (var i = 0; allEqual && i < queryModels.length; ++i)
259 allEqual = allEqual && this._cachedQueryModels[i].equals(queryModels [i]);
260 if (allEqual)
261 return;
262 this._cachedQueryModels = queryModels;
263 this._renderMediaQueries();
264
265 /**
266 * @param {!WebInspector.MediaQueryInspector.MediaQueryUIModel} model1
267 * @param {!WebInspector.MediaQueryInspector.MediaQueryUIModel} model2
268 * @return {number}
269 */
270 function compareModels(model1, model2)
271 {
272 return model1.compareTo(model2);
273 }
274 },
275
276 _renderMediaQueries: function()
277 {
278 if (!this._cachedQueryModels)
279 return;
280 this._renderRulerDecorations();
281 if (!this.isShowing())
282 return;
283
284 var markers = [];
285 var lastMarker = null;
286 for (var i = 0; i < this._cachedQueryModels.length; ++i) {
287 var model = this._cachedQueryModels[i];
288 if (!model.uiLocation())
289 continue;
290 if (lastMarker && lastMarker.model.dimensionsEqual(model)) {
291 lastMarker.locations.push(model.uiLocation());
292 } else {
293 lastMarker = {
294 model: model,
295 locations: [ model.uiLocation() ]
296 };
297 markers.push(lastMarker);
298 }
299 }
300 var heightChanges = this.element.children.length !== markers.length;
301
302 var scrollTop = this.element.scrollTop;
303 this.element.removeChildren();
304 for (var i = 0; i < markers.length; ++i) {
305 var marker = markers[i];
306 var bar = this._createElementFromMediaQueryModel(marker.model);
307 bar._model = marker.model;
308 bar._locations = marker.locations;
309 this.element.appendChild(bar);
310 }
311 this.element.scrollTop = scrollTop;
312 this.element.classList.toggle("media-inspector-view-empty", !this.elemen t.children.length);
313 if (heightChanges)
314 this.dispatchEventToListeners(WebInspector.MediaQueryInspector.Event s.HeightUpdated);
315 },
316
317 /**
318 * @return {number}
319 */
320 _zoomFactor: function()
321 {
322 return WebInspector.zoomManager.zoomFactor() / this._scale;
323 },
324
325 _renderRulerDecorations: function()
326 {
327 this._rulerDecorationLayer.removeChildren();
328 var zoomFactor = this._zoomFactor();
329
330 var thresholds = this._mediaQueryThresholds();
331 for (var i = 0; i < thresholds.length; ++i) {
332 var thresholdElement = this._rulerDecorationLayer.createChild("div", "media-inspector-threshold-serif");
333 thresholdElement._value = thresholds[i];
334 thresholdElement.style.left = (thresholds[i] - this._offset) / zoomF actor + "px";
335 }
336 },
337
338 wasShown: function()
339 {
340 this._renderMediaQueries();
341 },
342
343 /**
344 * @param {!WebInspector.MediaQueryInspector.MediaQueryUIModel} model
345 * @return {!Element}
346 */
347 _createElementFromMediaQueryModel: function(model)
348 {
349 var zoomFactor = this._zoomFactor();
350 var minWidthValue = model.minWidthExpression() ? model.minWidthExpressio n().computedLength() : 0;
351
352 var container = document.createElementWithClass("div", "media-inspector- marker-container hbox");
353 var markerElement = container.createChild("div", "media-inspector-marker ");
354 const styleClassPerSection = [
355 "media-inspector-marker-max-width",
356 "media-inspector-marker-min-max-width",
357 "media-inspector-marker-min-width"
358 ];
359 markerElement.classList.add(styleClassPerSection[model.section()]);
360 var leftPixelValue = minWidthValue ? (minWidthValue - this._offset) / zo omFactor + this._translateZero : 0;
361 markerElement.style.left = leftPixelValue + "px";
362 var widthPixelValue = null;
363 if (model.maxWidthExpression() && model.minWidthExpression())
364 widthPixelValue = (model.maxWidthExpression().computedLength() - min WidthValue) / zoomFactor;
365 else if (model.maxWidthExpression())
366 widthPixelValue = (model.maxWidthExpression().computedLength() - thi s._offset) / zoomFactor + this._translateZero;
367 else
368 markerElement.style.right = "0";
369 if (typeof widthPixelValue === "number")
370 markerElement.style.width = widthPixelValue + "px";
371
372 var maxLabelFiller = container.createChild("div", "media-inspector-max-l abel-filler");
373 if (model.maxWidthExpression()) {
374 maxLabelFiller.style.maxWidth = widthPixelValue + leftPixelValue + " px";
375 var label = container.createChild("span", "media-inspector-marker-la bel media-inspector-max-label");
376 label.textContent = model.maxWidthExpression().computedLength() + "p x";
377 }
378
379 if (model.minWidthExpression()) {
380 var minLabelFiller = maxLabelFiller.createChild("div", "media-inspec tor-min-label-filler");
381 minLabelFiller.style.maxWidth = leftPixelValue + "px";
382 var label = minLabelFiller.createChild("span", "media-inspector-mark er-label media-inspector-min-label");
383 label.textContent = model.minWidthExpression().computedLength() + "p x";
384 }
385
386 return container;
387 },
388
389 __proto__: WebInspector.View.prototype
390 };
391
392 /**
393 * @constructor
394 * @param {!WebInspector.CSSMedia} cssMedia
395 * @param {?WebInspector.CSSMediaQueryExpression} minWidthExpression
396 * @param {?WebInspector.CSSMediaQueryExpression} maxWidthExpression
397 */
398 WebInspector.MediaQueryInspector.MediaQueryUIModel = function(cssMedia, minWidth Expression, maxWidthExpression)
399 {
400 this._cssMedia = cssMedia;
401 this._minWidthExpression = minWidthExpression;
402 this._maxWidthExpression = maxWidthExpression;
403 if (maxWidthExpression && !minWidthExpression)
404 this._section = WebInspector.MediaQueryInspector.Section.Max;
405 else if (minWidthExpression && maxWidthExpression)
406 this._section = WebInspector.MediaQueryInspector.Section.MinMax;
407 else
408 this._section = WebInspector.MediaQueryInspector.Section.Min;
409 }
410
411 /**
412 * @param {!WebInspector.CSSMedia} cssMedia
413 * @param {!Array.<!WebInspector.CSSMediaQueryExpression>} mediaQueryExpressions
414 * @return {?WebInspector.MediaQueryInspector.MediaQueryUIModel}
415 */
416 WebInspector.MediaQueryInspector.MediaQueryUIModel.createFromMediaExpressions = function(cssMedia, mediaQueryExpressions)
417 {
418 var maxWidthExpression = null;
419 var maxWidthPixels = Number.MAX_VALUE;
420 var minWidthExpression = null;
421 var minWidthPixels = Number.MIN_VALUE;
422 for (var i = 0; i < mediaQueryExpressions.length; ++i) {
423 var expression = mediaQueryExpressions[i];
424 var feature = expression.feature();
425 if (feature.indexOf("width") === -1)
426 continue;
427 var pixels = expression.computedLength();
428 if (feature.startsWith("max-") && pixels < maxWidthPixels) {
429 maxWidthExpression = expression;
430 maxWidthPixels = pixels;
431 } else if (feature.startsWith("min-") && pixels > minWidthPixels) {
432 minWidthExpression = expression;
433 minWidthPixels = pixels;
434 }
435 }
436 if (minWidthPixels > maxWidthPixels || (!maxWidthExpression && !minWidthExpr ession))
437 return null;
438
439 return new WebInspector.MediaQueryInspector.MediaQueryUIModel(cssMedia, minW idthExpression, maxWidthExpression);
440 }
441
442 WebInspector.MediaQueryInspector.MediaQueryUIModel.prototype = {
443 /**
444 * @param {!WebInspector.MediaQueryInspector.MediaQueryUIModel} other
445 * @return {boolean}
446 */
447 equals: function(other)
448 {
449 return this.compareTo(other) === 0;
450 },
451
452 /**
453 * @param {!WebInspector.MediaQueryInspector.MediaQueryUIModel} other
454 * @return {boolean}
455 */
456 dimensionsEqual: function(other)
457 {
458 return this.section() === other.section()
459 && (!this.minWidthExpression() || (this.minWidthExpression().compute dLength() === other.minWidthExpression().computedLength()))
460 && (!this.maxWidthExpression() || (this.maxWidthExpression().compute dLength() === other.maxWidthExpression().computedLength()));
461 },
462
463 /**
464 * @param {!WebInspector.MediaQueryInspector.MediaQueryUIModel} other
465 * @return {number}
466 */
467 compareTo: function(other)
468 {
469 if (this.section() !== other.section())
470 return this.section() - other.section();
471 if (this.dimensionsEqual(other)) {
472 var myLocation = this.uiLocation();
473 var otherLocation = other.uiLocation();
474 if (!myLocation && !otherLocation)
475 return this.mediaText().compareTo(other.mediaText());
476 if (myLocation && !otherLocation)
477 return 1;
478 if (!myLocation && otherLocation)
479 return -1;
480 return myLocation.uiSourceCode.uri().compareTo(otherLocation.uiSourc eCode.uri()) || myLocation.lineNumber - otherLocation.lineNumber || myLocation.c olumnNumber - otherLocation.columnNumber;
481 }
482 if (this.section() === WebInspector.MediaQueryInspector.Section.Max)
483 return this.maxWidthExpression().computedLength() - other.maxWidthEx pression().computedLength();
484 if (this.section() === WebInspector.MediaQueryInspector.Section.Min)
485 return this.minWidthExpression().computedLength() - other.minWidthEx pression().computedLength();
486 return this.minWidthExpression().computedLength() - other.minWidthExpres sion().computedLength() || this.maxWidthExpression().computedLength() - other.ma xWidthExpression().computedLength();
487 },
488
489 /**
490 * @return {!WebInspector.MediaQueryInspector.Section}
491 */
492 section: function()
493 {
494 return this._section;
495 },
496
497 /**
498 * @return {string}
499 */
500 mediaText: function()
501 {
502 return this._cssMedia.text;
503 },
504
505 /**
506 * @return {?WebInspector.UILocation}
507 */
508 uiLocation: function()
509 {
510 return this._cssMedia.uiLocation();
511 },
512
513 /**
514 * @return {?WebInspector.CSSMediaQueryExpression}
515 */
516 minWidthExpression: function()
517 {
518 return this._minWidthExpression;
519 },
520
521 /**
522 * @return {?WebInspector.CSSMediaQueryExpression}
523 */
524 maxWidthExpression: function()
525 {
526 return this._maxWidthExpression;
527 }
528 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698