Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
META-INF.dirigible.dev-tools.emulation.MediaQueryInspector.js Maven / Gradle / Ivy
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as Bindings from '../bindings/bindings.js';
import * as Common from '../common/common.js';
import * as Platform from '../platform/platform.js';
import * as SDK from '../sdk/sdk.js';
import * as UI from '../ui/ui.js';
import * as Workspace from '../workspace/workspace.js'; // eslint-disable-line no-unused-vars
/**
* @implements {SDK.SDKModel.SDKModelObserver}
* @unrestricted
*/
export class MediaQueryInspector extends UI.Widget.Widget {
/**
* @param {function():number} getWidthCallback
* @param {function(number)} setWidthCallback
*/
constructor(getWidthCallback, setWidthCallback) {
super(true);
this.registerRequiredCSS('emulation/mediaQueryInspector.css');
this.contentElement.classList.add('media-inspector-view');
this.contentElement.addEventListener('click', this._onMediaQueryClicked.bind(this), false);
this.contentElement.addEventListener('contextmenu', this._onContextMenu.bind(this), false);
this._mediaThrottler = new Common.Throttler.Throttler(0);
this._getWidthCallback = getWidthCallback;
this._setWidthCallback = setWidthCallback;
this._scale = 1;
SDK.SDKModel.TargetManager.instance().observeModels(SDK.CSSModel.CSSModel, this);
UI.ZoomManager.ZoomManager.instance().addEventListener(
UI.ZoomManager.Events.ZoomChanged, this._renderMediaQueries.bind(this), this);
}
/**
* @override
* @param {!SDK.CSSModel.CSSModel} cssModel
*/
modelAdded(cssModel) {
// FIXME: adapt this to multiple targets.
if (this._cssModel) {
return;
}
this._cssModel = cssModel;
this._cssModel.addEventListener(SDK.CSSModel.Events.StyleSheetAdded, this._scheduleMediaQueriesUpdate, this);
this._cssModel.addEventListener(SDK.CSSModel.Events.StyleSheetRemoved, this._scheduleMediaQueriesUpdate, this);
this._cssModel.addEventListener(SDK.CSSModel.Events.StyleSheetChanged, this._scheduleMediaQueriesUpdate, this);
this._cssModel.addEventListener(
SDK.CSSModel.Events.MediaQueryResultChanged, this._scheduleMediaQueriesUpdate, this);
}
/**
* @override
* @param {!SDK.CSSModel.CSSModel} cssModel
*/
modelRemoved(cssModel) {
if (cssModel !== this._cssModel) {
return;
}
this._cssModel.removeEventListener(SDK.CSSModel.Events.StyleSheetAdded, this._scheduleMediaQueriesUpdate, this);
this._cssModel.removeEventListener(SDK.CSSModel.Events.StyleSheetRemoved, this._scheduleMediaQueriesUpdate, this);
this._cssModel.removeEventListener(SDK.CSSModel.Events.StyleSheetChanged, this._scheduleMediaQueriesUpdate, this);
this._cssModel.removeEventListener(
SDK.CSSModel.Events.MediaQueryResultChanged, this._scheduleMediaQueriesUpdate, this);
delete this._cssModel;
}
/**
* @param {number} scale
*/
setAxisTransform(scale) {
if (Math.abs(this._scale - scale) < 1e-8) {
return;
}
this._scale = scale;
this._renderMediaQueries();
}
/**
* @param {!Event} event
*/
_onMediaQueryClicked(event) {
const mediaQueryMarker = event.target.enclosingNodeOrSelfWithClass('media-inspector-bar');
if (!mediaQueryMarker) {
return;
}
const model = mediaQueryMarker._model;
if (model.section() === Section.Max) {
this._setWidthCallback(model.maxWidthExpression().computedLength());
return;
}
if (model.section() === Section.Min) {
this._setWidthCallback(model.minWidthExpression().computedLength());
return;
}
const currentWidth = this._getWidthCallback();
if (currentWidth !== model.minWidthExpression().computedLength()) {
this._setWidthCallback(model.minWidthExpression().computedLength());
} else {
this._setWidthCallback(model.maxWidthExpression().computedLength());
}
}
/**
* @param {!Event} event
*/
_onContextMenu(event) {
if (!this._cssModel || !this._cssModel.isEnabled()) {
return;
}
const mediaQueryMarker = event.target.enclosingNodeOrSelfWithClass('media-inspector-bar');
if (!mediaQueryMarker) {
return;
}
const locations = mediaQueryMarker._locations;
const uiLocations = new Map();
for (let i = 0; i < locations.length; ++i) {
const uiLocation =
Bindings.CSSWorkspaceBinding.CSSWorkspaceBinding.instance().rawLocationToUILocation(locations[i]);
if (!uiLocation) {
continue;
}
const descriptor = Platform.StringUtilities.sprintf(
'%s:%d:%d', uiLocation.uiSourceCode.url(), uiLocation.lineNumber + 1, uiLocation.columnNumber + 1);
uiLocations.set(descriptor, uiLocation);
}
const contextMenuItems = [...uiLocations.keys()].sort();
const contextMenu = new UI.ContextMenu.ContextMenu(event);
const subMenuItem =
contextMenu.defaultSection().appendSubMenuItem(Common.UIString.UIString('Reveal in source code'));
for (let i = 0; i < contextMenuItems.length; ++i) {
const title = contextMenuItems[i];
subMenuItem.defaultSection().appendItem(
title,
this._revealSourceLocation.bind(
this, /** @type {!Workspace.UISourceCode.UILocation} */ (uiLocations.get(title))));
}
contextMenu.show();
}
/**
* @param {!Workspace.UISourceCode.UILocation} location
*/
_revealSourceLocation(location) {
Common.Revealer.reveal(location);
}
_scheduleMediaQueriesUpdate() {
if (!this.isShowing()) {
return;
}
this._mediaThrottler.schedule(this._refetchMediaQueries.bind(this));
}
_refetchMediaQueries() {
if (!this.isShowing() || !this._cssModel) {
return Promise.resolve();
}
return this._cssModel.mediaQueriesPromise().then(this._rebuildMediaQueries.bind(this));
}
/**
* @param {!Array.} models
* @return {!Array.}
*/
_squashAdjacentEqual(models) {
const filtered = [];
for (let i = 0; i < models.length; ++i) {
const last = filtered.peekLast();
if (!last || !last.equals(models[i])) {
filtered.push(models[i]);
}
}
return filtered;
}
/**
* @param {!Array.} cssMedias
*/
_rebuildMediaQueries(cssMedias) {
let queryModels = [];
for (let i = 0; i < cssMedias.length; ++i) {
const cssMedia = cssMedias[i];
if (!cssMedia.mediaList) {
continue;
}
for (let j = 0; j < cssMedia.mediaList.length; ++j) {
const mediaQuery = cssMedia.mediaList[j];
const queryModel = MediaQueryUIModel.createFromMediaQuery(cssMedia, mediaQuery);
if (queryModel && queryModel.rawLocation()) {
queryModels.push(queryModel);
}
}
}
queryModels.sort(compareModels);
queryModels = this._squashAdjacentEqual(queryModels);
let allEqual = this._cachedQueryModels && this._cachedQueryModels.length === queryModels.length;
for (let i = 0; allEqual && i < queryModels.length; ++i) {
allEqual = allEqual && this._cachedQueryModels[i].equals(queryModels[i]);
}
if (allEqual) {
return;
}
this._cachedQueryModels = queryModels;
this._renderMediaQueries();
/**
* @param {!MediaQueryUIModel} model1
* @param {!MediaQueryUIModel} model2
* @return {number}
*/
function compareModels(model1, model2) {
return model1.compareTo(model2);
}
}
_renderMediaQueries() {
if (!this._cachedQueryModels || !this.isShowing()) {
return;
}
const markers = [];
let lastMarker = null;
for (let i = 0; i < this._cachedQueryModels.length; ++i) {
const model = this._cachedQueryModels[i];
if (lastMarker && lastMarker.model.dimensionsEqual(model)) {
lastMarker.locations.push(model.rawLocation());
lastMarker.active = lastMarker.active || model.active();
} else {
lastMarker = {active: model.active(), model: model, locations: [model.rawLocation()]};
markers.push(lastMarker);
}
}
this.contentElement.removeChildren();
let container = null;
for (let i = 0; i < markers.length; ++i) {
if (!i || markers[i].model.section() !== markers[i - 1].model.section()) {
container = this.contentElement.createChild('div', 'media-inspector-marker-container');
}
const marker = markers[i];
const bar = this._createElementFromMediaQueryModel(marker.model);
bar._model = marker.model;
bar._locations = marker.locations;
bar.classList.toggle('media-inspector-marker-inactive', !marker.active);
container.appendChild(bar);
}
}
/**
* @return {number}
*/
_zoomFactor() {
return UI.ZoomManager.ZoomManager.instance().zoomFactor() / this._scale;
}
/**
* @override
*/
wasShown() {
this._scheduleMediaQueriesUpdate();
}
/**
* @param {!MediaQueryUIModel} model
* @return {!Element}
*/
_createElementFromMediaQueryModel(model) {
const zoomFactor = this._zoomFactor();
const minWidthValue = model.minWidthExpression() ? model.minWidthExpression().computedLength() / zoomFactor : 0;
const maxWidthValue = model.maxWidthExpression() ? model.maxWidthExpression().computedLength() / zoomFactor : 0;
const result = createElementWithClass('div', 'media-inspector-bar');
if (model.section() === Section.Max) {
result.createChild('div', 'media-inspector-marker-spacer');
const markerElement = result.createChild('div', 'media-inspector-marker media-inspector-marker-max-width');
markerElement.style.width = maxWidthValue + 'px';
markerElement.title = model.mediaText();
appendLabel(markerElement, model.maxWidthExpression(), false, false);
appendLabel(markerElement, model.maxWidthExpression(), true, true);
result.createChild('div', 'media-inspector-marker-spacer');
}
if (model.section() === Section.MinMax) {
result.createChild('div', 'media-inspector-marker-spacer');
const leftElement = result.createChild('div', 'media-inspector-marker media-inspector-marker-min-max-width');
leftElement.style.width = (maxWidthValue - minWidthValue) * 0.5 + 'px';
leftElement.title = model.mediaText();
appendLabel(leftElement, model.minWidthExpression(), true, false);
appendLabel(leftElement, model.maxWidthExpression(), false, true);
result.createChild('div', 'media-inspector-marker-spacer').style.flex = '0 0 ' + minWidthValue + 'px';
const rightElement = result.createChild('div', 'media-inspector-marker media-inspector-marker-min-max-width');
rightElement.style.width = (maxWidthValue - minWidthValue) * 0.5 + 'px';
rightElement.title = model.mediaText();
appendLabel(rightElement, model.minWidthExpression(), true, false);
appendLabel(rightElement, model.maxWidthExpression(), false, true);
result.createChild('div', 'media-inspector-marker-spacer');
}
if (model.section() === Section.Min) {
const leftElement = result.createChild(
'div', 'media-inspector-marker media-inspector-marker-min-width media-inspector-marker-min-width-left');
leftElement.title = model.mediaText();
appendLabel(leftElement, model.minWidthExpression(), false, false);
result.createChild('div', 'media-inspector-marker-spacer').style.flex = '0 0 ' + minWidthValue + 'px';
const rightElement = result.createChild(
'div', 'media-inspector-marker media-inspector-marker-min-width media-inspector-marker-min-width-right');
rightElement.title = model.mediaText();
appendLabel(rightElement, model.minWidthExpression(), true, true);
}
function appendLabel(marker, expression, atLeft, leftAlign) {
marker
.createChild(
'div',
'media-inspector-marker-label-container ' + (atLeft ? 'media-inspector-marker-label-container-left' :
'media-inspector-marker-label-container-right'))
.createChild(
'span', 'media-inspector-marker-label ' +
(leftAlign ? 'media-inspector-label-left' : 'media-inspector-label-right'))
.textContent = expression.value() + expression.unit();
}
return result;
}
}
/**
* @enum {number}
*/
export const Section = {
Max: 0,
MinMax: 1,
Min: 2
};
/**
* @unrestricted
*/
export class MediaQueryUIModel {
/**
* @param {!SDK.CSSMedia.CSSMedia} cssMedia
* @param {?SDK.CSSMedia.CSSMediaQueryExpression} minWidthExpression
* @param {?SDK.CSSMedia.CSSMediaQueryExpression} maxWidthExpression
* @param {boolean} active
*/
constructor(cssMedia, minWidthExpression, maxWidthExpression, active) {
this._cssMedia = cssMedia;
this._minWidthExpression = minWidthExpression;
this._maxWidthExpression = maxWidthExpression;
this._active = active;
if (maxWidthExpression && !minWidthExpression) {
this._section = Section.Max;
} else if (minWidthExpression && maxWidthExpression) {
this._section = Section.MinMax;
} else {
this._section = Section.Min;
}
}
/**
* @param {!SDK.CSSMedia.CSSMedia} cssMedia
* @param {!SDK.CSSMedia.CSSMediaQuery} mediaQuery
* @return {?MediaQueryUIModel}
*/
static createFromMediaQuery(cssMedia, mediaQuery) {
let maxWidthExpression = null;
let maxWidthPixels = Number.MAX_VALUE;
let minWidthExpression = null;
let minWidthPixels = Number.MIN_VALUE;
const expressions = mediaQuery.expressions();
for (let i = 0; i < expressions.length; ++i) {
const expression = expressions[i];
const feature = expression.feature();
if (feature.indexOf('width') === -1) {
continue;
}
const pixels = expression.computedLength();
if (feature.startsWith('max-') && pixels < maxWidthPixels) {
maxWidthExpression = expression;
maxWidthPixels = pixels;
} else if (feature.startsWith('min-') && pixels > minWidthPixels) {
minWidthExpression = expression;
minWidthPixels = pixels;
}
}
if (minWidthPixels > maxWidthPixels || (!maxWidthExpression && !minWidthExpression)) {
return null;
}
return new MediaQueryUIModel(cssMedia, minWidthExpression, maxWidthExpression, mediaQuery.active());
}
/**
* @param {!MediaQueryUIModel} other
* @return {boolean}
*/
equals(other) {
return this.compareTo(other) === 0;
}
/**
* @param {!MediaQueryUIModel} other
* @return {boolean}
*/
dimensionsEqual(other) {
return this.section() === other.section() &&
(!this.minWidthExpression() ||
(this.minWidthExpression().computedLength() === other.minWidthExpression().computedLength())) &&
(!this.maxWidthExpression() ||
(this.maxWidthExpression().computedLength() === other.maxWidthExpression().computedLength()));
}
/**
* @param {!MediaQueryUIModel} other
* @return {number}
*/
compareTo(other) {
if (this.section() !== other.section()) {
return this.section() - other.section();
}
if (this.dimensionsEqual(other)) {
const myLocation = this.rawLocation();
const otherLocation = other.rawLocation();
if (!myLocation && !otherLocation) {
return this.mediaText().compareTo(other.mediaText());
}
if (myLocation && !otherLocation) {
return 1;
}
if (!myLocation && otherLocation) {
return -1;
}
if (this.active() !== other.active()) {
return this.active() ? -1 : 1;
}
return myLocation.url.compareTo(otherLocation.url) || myLocation.lineNumber - otherLocation.lineNumber ||
myLocation.columnNumber - otherLocation.columnNumber;
}
if (this.section() === Section.Max) {
return other.maxWidthExpression().computedLength() - this.maxWidthExpression().computedLength();
}
if (this.section() === Section.Min) {
return this.minWidthExpression().computedLength() - other.minWidthExpression().computedLength();
}
return this.minWidthExpression().computedLength() - other.minWidthExpression().computedLength() ||
other.maxWidthExpression().computedLength() - this.maxWidthExpression().computedLength();
}
/**
* @return {!Section}
*/
section() {
return this._section;
}
/**
* @return {string}
*/
mediaText() {
return this._cssMedia.text;
}
/**
* @return {?SDK.CSSModel.CSSLocation}
*/
rawLocation() {
if (!this._rawLocation) {
this._rawLocation = this._cssMedia.rawLocation();
}
return this._rawLocation;
}
/**
* @return {?SDK.CSSMedia.CSSMediaQueryExpression}
*/
minWidthExpression() {
return this._minWidthExpression;
}
/**
* @return {?SDK.CSSMedia.CSSMediaQueryExpression}
*/
maxWidthExpression() {
return this._maxWidthExpression;
}
/**
* @return {boolean}
*/
active() {
return this._active;
}
}