Chromium Code Reviews| Index: Source/devtools/front_end/toolbox/MediaQueryInspector.js |
| diff --git a/Source/devtools/front_end/toolbox/MediaQueryInspector.js b/Source/devtools/front_end/toolbox/MediaQueryInspector.js |
| index 31e2cfcf6b420e23439ae1174169a85c48d1b5dc..ad473c81694ae0549569d3d7bfa6c22a58154c40 100644 |
| --- a/Source/devtools/front_end/toolbox/MediaQueryInspector.js |
| +++ b/Source/devtools/front_end/toolbox/MediaQueryInspector.js |
| @@ -13,13 +13,15 @@ WebInspector.MediaQueryInspector = function() |
| this.element.classList.add("media-inspector-view", "media-inspector-view-empty"); |
| this.element.addEventListener("click", this._onMediaQueryClicked.bind(this), false); |
| this.element.addEventListener("contextmenu", this._onContextMenu.bind(this), false); |
| - this.element.addEventListener("webkitAnimationEnd", this._onAnimationEnd.bind(this), false); |
| this._mediaThrottler = new WebInspector.Throttler(100); |
| this._translateZero = 0; |
| this._offset = 0; |
| this._scale = 1; |
| this._lastReportedCount = 0; |
| + this._highlightedModel = null; |
| + this._highlightDecorationVisible = false; |
| + this._availableSections = [false, false, false]; |
| this._rulerDecorationLayer = document.createElementWithClass("div", "fill"); |
| this._rulerDecorationLayer.classList.add("media-inspector-ruler-decoration"); |
| @@ -41,9 +43,13 @@ WebInspector.MediaQueryInspector.Section = { |
| WebInspector.MediaQueryInspector.Events = { |
| HeightUpdated: "HeightUpdated", |
| - CountUpdated: "CountUpdated" |
| + CountUpdated: "CountUpdated", |
| + HighlightDecorationUpdated: "HighlightDecorationUpdated" |
| } |
| +/** @typedef {!{value: number, section: number}} */ |
| +WebInspector.MediaQueryInspector.Threshold; |
| + |
| WebInspector.MediaQueryInspector.prototype = { |
| /** |
| * @param {!WebInspector.Target} target |
| @@ -82,7 +88,7 @@ WebInspector.MediaQueryInspector.prototype = { |
| }, |
| /** |
| - * @return {!Array.<number>} |
| + * @return {!Array.<!WebInspector.MediaQueryInspector.Threshold>} |
| */ |
| _mediaQueryThresholds: function() |
| { |
| @@ -92,11 +98,21 @@ WebInspector.MediaQueryInspector.prototype = { |
| for (var i = 0; i < this._cachedQueryModels.length; ++i) { |
| var model = this._cachedQueryModels[i]; |
| if (model.minWidthExpression()) |
| - thresholds.push(model.minWidthExpression().computedLength()); |
| + thresholds.push({value: model.minWidthExpression().computedLength(), section: model.section()}); |
| if (model.maxWidthExpression()) |
| - thresholds.push(model.maxWidthExpression().computedLength()); |
| + thresholds.push({value: model.maxWidthExpression().computedLength(), section: model.section()}); |
| + } |
| + /** |
| + * @param {!WebInspector.MediaQueryInspector.Threshold} threshold1 |
| + * @param {!WebInspector.MediaQueryInspector.Threshold} threshold2 |
| + * @return {number} |
| + */ |
| + function comparator(threshold1, threshold2) |
| + { |
| + return threshold1.value - threshold2.value; |
| } |
| - thresholds.sortNumbers(); |
| + |
| + thresholds.sort(comparator); |
| return thresholds; |
| }, |
| @@ -105,32 +121,10 @@ WebInspector.MediaQueryInspector.prototype = { |
| */ |
| _onRulerDecorationClicked: function(event) |
| { |
| - var thresholdElement = event.target.enclosingNodeOrSelfWithClass("media-inspector-threshold-serif"); |
| + var thresholdElement = event.target.enclosingNodeOrSelfWithClass("media-inspector-threshold"); |
| if (!thresholdElement) |
| return; |
| WebInspector.settings.showMediaQueryInspector.set(true); |
| - var revealValue = thresholdElement._value; |
| - for (var mediaQueryContainer = this.element.firstChild; mediaQueryContainer; mediaQueryContainer = mediaQueryContainer.nextSibling) { |
| - var model = mediaQueryContainer._model; |
| - if ((model.minWidthExpression() && Math.abs(model.minWidthExpression().computedLength() - revealValue) === 0) |
| - || (model.maxWidthExpression() && Math.abs(model.maxWidthExpression().computedLength() - revealValue) === 0)) { |
| - mediaQueryContainer.scrollIntoViewIfNeeded(false); |
| - var hasRunningAnimation = mediaQueryContainer.classList.contains("media-inspector-marker-highlight-1") || mediaQueryContainer.classList.contains("media-inspector-marker-highlight-2"); |
| - mediaQueryContainer.classList.toggle("media-inspector-marker-highlight-1"); |
| - if (hasRunningAnimation) |
| - mediaQueryContainer.classList.toggle("media-inspector-marker-highlight-2"); |
| - return; |
| - } |
| - } |
| - }, |
| - |
| - /** |
| - * @param {!Event} event |
| - */ |
| - _onAnimationEnd: function(event) |
| - { |
| - event.target.classList.remove("media-inspector-marker-highlight-1"); |
| - event.target.classList.remove("media-inspector-marker-highlight-2"); |
| }, |
| /** |
| @@ -162,8 +156,8 @@ WebInspector.MediaQueryInspector.prototype = { |
| */ |
| _onMediaQueryClicked: function(event) |
| { |
| - var mediaQueryMarkerContainer = event.target.enclosingNodeOrSelfWithClass("media-inspector-marker-container"); |
| - if (!mediaQueryMarkerContainer) |
| + var mediaQueryMarker = event.target.enclosingNodeOrSelfWithClass("media-inspector-marker"); |
| + if (!mediaQueryMarker) |
| return; |
| /** |
| @@ -175,7 +169,7 @@ WebInspector.MediaQueryInspector.prototype = { |
| WebInspector.overridesSupport.settings.emulateResolution.set(true); |
| } |
| - var model = mediaQueryMarkerContainer._model; |
| + var model = mediaQueryMarker._model; |
| if (model.section() === WebInspector.MediaQueryInspector.Section.Max) { |
| setWidth(model.maxWidthExpression().computedLength()); |
| return; |
| @@ -196,11 +190,11 @@ WebInspector.MediaQueryInspector.prototype = { |
| */ |
| _onContextMenu: function(event) |
| { |
| - var mediaQueryMarkerContainer = event.target.enclosingNodeOrSelfWithClass("media-inspector-marker-container"); |
| - if (!mediaQueryMarkerContainer) |
| + var mediaQueryMarker = event.target.enclosingNodeOrSelfWithClass("media-inspector-marker"); |
| + if (!mediaQueryMarker) |
| return; |
| - var locations = mediaQueryMarkerContainer._locations; |
| + var locations = mediaQueryMarker._locations; |
| var contextMenu = new WebInspector.ContextMenu(event); |
| var subMenuItem = contextMenu.appendSubMenuItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Reveal in source code" : "Reveal In Source Code")); |
| for (var i = 0; i < locations.length; ++i) { |
| @@ -335,26 +329,83 @@ WebInspector.MediaQueryInspector.prototype = { |
| if (!this.isShowing()) |
| return; |
| - var heightChanges = this.element.children.length !== markers.length; |
| - |
| + var oldChildrenCount = this.element.children.length; |
| var scrollTop = this.element.scrollTop; |
| this.element.removeChildren(); |
| + |
| + for (var i = 0; i < this._availableSections.length; ++i) |
| + this._availableSections[i] = false; |
| + |
| + var container = null; |
| for (var i = 0; i < markers.length; ++i) { |
| + if (!i || markers[i].model.section() !== markers[i - 1].model.section()) { |
| + container = this.element.createChild("div", "media-inspector-marker-container"); |
| + this._availableSections[markers[i].model.section()] = true; |
| + var handler = this._onMarkerContainerMouseMove.bind(this); |
| + container.addEventListener("mousemove", handler, false); |
| + container.addEventListener("mouseout", handler, false); |
| + } |
| var marker = markers[i]; |
| - var bar = this._createElementFromMediaQueryModel(marker.model); |
| + var bar = this._createElementFromMediaQueryModel(/** @type {!Element} */ (container), marker.model); |
| bar._model = marker.model; |
| bar._locations = marker.locations; |
| bar.classList.toggle("media-inspector-marker-inactive", !marker.active); |
| - |
| - this.element.appendChild(bar); |
| } |
| this.element.scrollTop = scrollTop; |
| this.element.classList.toggle("media-inspector-view-empty", !this.element.children.length); |
| - if (heightChanges) |
| + if (this.element.children.length != oldChildrenCount) |
| this.dispatchEventToListeners(WebInspector.MediaQueryInspector.Events.HeightUpdated); |
| }, |
| /** |
| + * @param {!Event} event |
| + */ |
| + _onMarkerContainerMouseMove: function(event) |
| + { |
| + var mediaQueryMarkerContainer = event.target.enclosingNodeOrSelfWithClass("media-inspector-marker-container"); |
| + if (!mediaQueryMarkerContainer) |
| + return; |
| + var children = mediaQueryMarkerContainer.children; |
| + if (!children.length) |
| + return; |
| + for (var i = children.length - 1; i >= 0; --i) { |
| + if (children[i].containsEventPoint(event)) { |
|
lushnikov
2014/09/03 14:30:41
can't we use relatedTarget/target instead of this
|
| + this._highlightMarkerInContainer(children[i], mediaQueryMarkerContainer); |
| + return; |
| + } |
| + } |
| + this._highlightMarkerInContainer(null, mediaQueryMarkerContainer); |
| + }, |
| + |
| + /** |
| + * @param {?Element} marker |
| + * @param {!Element} container |
| + */ |
| + _highlightMarkerInContainer: function(marker, container) |
| + { |
| + var children = container.children; |
| + var found = !marker; |
| + for (var i = children.length - 1; i >= 0; --i) { |
|
lushnikov
2014/09/03 14:30:41
Can we simply update z-index of a marker (if any),
|
| + if (found) { |
| + children[i].classList.remove("media-inspector-marker-highlight"); |
| + children[i].classList.remove("media-inspector-marker-under-highlighted"); |
| + } else if (children[i] === marker) { |
| + children[i].classList.add("media-inspector-marker-highlight"); |
| + children[i].classList.remove("media-inspector-marker-under-highlighted"); |
| + found = true; |
| + } else { |
| + children[i].classList.remove("media-inspector-marker-highlight"); |
| + children[i].classList.add("media-inspector-marker-under-highlighted"); |
| + } |
| + } |
| + var highlightedModel = marker ? marker._model : null; |
| + if (highlightedModel !== this._highlightedModel) { |
| + this._highlightedModel = highlightedModel; |
| + this._renderRulerDecorations(); |
| + } |
| + }, |
| + |
| + /** |
| * @return {number} |
| */ |
| _zoomFactor: function() |
| @@ -362,17 +413,89 @@ WebInspector.MediaQueryInspector.prototype = { |
| return WebInspector.zoomManager.zoomFactor() / this._scale; |
| }, |
| + /** |
| + * @return {boolean} |
| + */ |
| + highlightDecorationVisible: function() |
| + { |
| + return this._highlightDecorationVisible; |
| + }, |
| + |
| _renderRulerDecorations: function() |
| { |
| + var highlightDecorationVisible = this.isShowing() && !!this._highlightedModel; |
| + if (highlightDecorationVisible !== this._highlightDecorationVisible) { |
| + this._highlightDecorationVisible = highlightDecorationVisible; |
| + this.dispatchEventToListeners(WebInspector.MediaQueryInspector.Events.HighlightDecorationUpdated); |
| + } |
| + |
| this._rulerDecorationLayer.removeChildren(); |
| var zoomFactor = this._zoomFactor(); |
| - var thresholds = this._mediaQueryThresholds(); |
| - for (var i = 0; i < thresholds.length; ++i) { |
| - var thresholdElement = this._rulerDecorationLayer.createChild("div", "media-inspector-threshold-serif"); |
| - thresholdElement.title = thresholds[i] + "px"; |
| - thresholdElement._value = thresholds[i]; |
| - thresholdElement.style.left = (thresholds[i] - this._offset) / zoomFactor + "px"; |
| + if (this.isShowing()) { |
| + if (!this._highlightedModel) |
|
lushnikov
2014/09/03 14:30:41
Can we extract this if-branch in a separate method
dgozman
2014/09/04 15:34:32
This method is removed now.
|
| + return; |
| + |
| + const highlightStyleClassPerSection = [ |
| + "media-inspector-highlight-threshold-max", |
| + "media-inspector-highlight-threshold-min-max", |
| + "media-inspector-highlight-threshold-min" |
| + ]; |
| + const classPerRowCount = [ |
| + "media-inspector-highlight-threshold-one-row", |
| + "media-inspector-highlight-threshold-two-rows", |
| + "media-inspector-highlight-threshold-three-rows" |
| + ]; |
| + var section = this._highlightedModel.section(); |
| + var rowCount = 0; |
| + for (var i = section; i < highlightStyleClassPerSection.length; ++i) { |
| + if (this._availableSections[i]) |
|
lushnikov
2014/09/03 14:30:41
availableSections is used only here; lets compute
dgozman
2014/09/04 15:34:32
Done.
|
| + rowCount++; |
| + } |
| + |
| + if (this._highlightedModel.minWidthExpression()) { |
| + var valueInPixels = this._highlightedModel.minWidthExpression().computedLength(); |
| + var minThresholdElement = this._rulerDecorationLayer.createChild("div", "media-inspector-highlight-threshold"); |
| + minThresholdElement.classList.add(highlightStyleClassPerSection[section]); |
| + minThresholdElement.classList.add(classPerRowCount[rowCount - 1]); |
| + if (this._highlightedModel.maxWidthExpression()) { |
|
lushnikov
2014/09/03 14:30:41
curly braces are not needed
|
| + minThresholdElement.classList.add("media-inspector-highlight-threshold-left"); |
| + } else { |
| + minThresholdElement.classList.add("media-inspector-highlight-threshold-right"); |
| + } |
| + minThresholdElement.title = valueInPixels + "px"; |
| + minThresholdElement.style.left = (valueInPixels - this._offset) / zoomFactor + "px"; |
| + minThresholdElement.createChild("span", "media-inspector-highlight-threshold-label").textContent = valueInPixels + "px"; |
| + } |
| + |
| + if (this._highlightedModel.maxWidthExpression()) { |
|
lushnikov
2014/09/03 14:30:41
this if-statment look almost identical to the prev
|
| + var valueInPixels = this._highlightedModel.maxWidthExpression().computedLength(); |
| + var maxThresholdElement = this._rulerDecorationLayer.createChild("div", "media-inspector-highlight-threshold"); |
| + maxThresholdElement.classList.add(highlightStyleClassPerSection[section]); |
| + maxThresholdElement.classList.add(classPerRowCount[rowCount - 1]); |
| + if (this._highlightedModel.minWidthExpression()) { |
| + maxThresholdElement.classList.add("media-inspector-highlight-threshold-right"); |
| + } else { |
| + maxThresholdElement.classList.add("media-inspector-highlight-threshold-left"); |
| + } |
| + maxThresholdElement.title = valueInPixels + "px"; |
| + maxThresholdElement.style.left = (valueInPixels - this._offset) / zoomFactor + "px"; |
| + maxThresholdElement.createChild("span", "media-inspector-highlight-threshold-label").textContent = valueInPixels + "px"; |
| + } |
| + } else { |
| + const thresholdStyleClassPerSection = [ |
| + "media-inspector-threshold-max", |
| + "media-inspector-threshold-min-max", |
| + "media-inspector-threshold-min" |
| + ]; |
| + var thresholds = this._mediaQueryThresholds(); |
| + for (var i = 0; i < thresholds.length; ++i) { |
| + var thresholdElement = this._rulerDecorationLayer.createChild("div", "media-inspector-threshold"); |
| + thresholdElement.classList.add(thresholdStyleClassPerSection[thresholds[i].section]); |
| + thresholdElement.title = thresholds[i].value + "px"; |
| + thresholdElement._value = thresholds[i].value; |
| + thresholdElement.style.left = (thresholds[i].value - this._offset) / zoomFactor + "px"; |
| + } |
| } |
| }, |
| @@ -381,51 +504,42 @@ WebInspector.MediaQueryInspector.prototype = { |
| this._renderMediaQueries(); |
| }, |
| + willHide: function() |
| + { |
| + window.setImmediate(this._renderRulerDecorations.bind(this)); |
|
lushnikov
2014/09/03 14:30:41
why do you use setImmediate here?
dgozman
2014/09/04 15:34:32
It was necessary to have isShowing return the righ
|
| + }, |
| + |
| /** |
| + * @param {!Element} container |
| * @param {!WebInspector.MediaQueryInspector.MediaQueryUIModel} model |
| * @return {!Element} |
| */ |
| - _createElementFromMediaQueryModel: function(model) |
| + _createElementFromMediaQueryModel: function(container, model) |
| { |
| var zoomFactor = this._zoomFactor(); |
| var minWidthValue = model.minWidthExpression() ? model.minWidthExpression().computedLength() : 0; |
| const styleClassPerSection = [ |
| - "media-inspector-marker-container-max-width", |
| - "media-inspector-marker-container-min-max-width", |
| - "media-inspector-marker-container-min-width" |
| + "media-inspector-marker-max-width", |
| + "media-inspector-marker-min-max-width", |
| + "media-inspector-marker-min-width" |
| ]; |
| - var container = document.createElementWithClass("div", "media-inspector-marker-container hbox"); |
| - container.classList.add(styleClassPerSection[model.section()]); |
| - |
| var markerElement = container.createChild("div", "media-inspector-marker"); |
| var leftPixelValue = minWidthValue ? (minWidthValue - this._offset) / zoomFactor + this._translateZero : 0; |
| markerElement.style.left = leftPixelValue + "px"; |
| + markerElement.classList.add(styleClassPerSection[model.section()]); |
| var widthPixelValue = null; |
| - if (model.maxWidthExpression() && model.minWidthExpression()) |
| + if (model.maxWidthExpression() && model.minWidthExpression()) { |
|
lushnikov
2014/09/03 14:30:41
curlies are not needed
dgozman
2014/09/04 15:34:32
Done.
|
| widthPixelValue = (model.maxWidthExpression().computedLength() - minWidthValue) / zoomFactor; |
| - else if (model.maxWidthExpression()) |
| + } else if (model.maxWidthExpression()) { |
|
lushnikov
2014/09/03 14:30:41
ditto
|
| widthPixelValue = (model.maxWidthExpression().computedLength() - this._offset) / zoomFactor + this._translateZero; |
| - else |
| + } else { |
|
lushnikov
2014/09/03 14:30:41
ditto
|
| markerElement.style.right = "0"; |
| + } |
| if (typeof widthPixelValue === "number") |
| markerElement.style.width = widthPixelValue + "px"; |
| - var maxLabelFiller = container.createChild("div", "media-inspector-max-label-filler"); |
| - if (model.maxWidthExpression()) { |
| - maxLabelFiller.style.maxWidth = Math.max(widthPixelValue + leftPixelValue, 0) + "px"; |
| - var label = container.createChild("span", "media-inspector-marker-label media-inspector-max-label"); |
| - label.textContent = model.maxWidthExpression().computedLength() + "px"; |
| - } |
| - |
| - if (model.minWidthExpression()) { |
| - var minLabelFiller = maxLabelFiller.createChild("div", "media-inspector-min-label-filler"); |
| - minLabelFiller.style.maxWidth = Math.max(leftPixelValue, 0) + "px"; |
| - var label = minLabelFiller.createChild("span", "media-inspector-marker-label media-inspector-min-label"); |
| - label.textContent = model.minWidthExpression().computedLength() + "px"; |
| - } |
| - |
| - return container; |
| + return markerElement; |
| }, |
| __proto__: WebInspector.View.prototype |
| @@ -527,10 +641,10 @@ WebInspector.MediaQueryInspector.MediaQueryUIModel.prototype = { |
| return myLocation.uiSourceCode.uri().compareTo(otherLocation.uiSourceCode.uri()) || myLocation.lineNumber - otherLocation.lineNumber || myLocation.columnNumber - otherLocation.columnNumber; |
| } |
| if (this.section() === WebInspector.MediaQueryInspector.Section.Max) |
| - return this.maxWidthExpression().computedLength() - other.maxWidthExpression().computedLength(); |
| + return other.maxWidthExpression().computedLength() - this.maxWidthExpression().computedLength(); |
| if (this.section() === WebInspector.MediaQueryInspector.Section.Min) |
| return this.minWidthExpression().computedLength() - other.minWidthExpression().computedLength(); |
| - return this.minWidthExpression().computedLength() - other.minWidthExpression().computedLength() || this.maxWidthExpression().computedLength() - other.maxWidthExpression().computedLength(); |
| + return this.minWidthExpression().computedLength() - other.minWidthExpression().computedLength() || other.maxWidthExpression().computedLength() - this.maxWidthExpression().computedLength(); |
| }, |
| /** |