Bug 1333561 - Part 3: Implements the box model panel in the layout view. r=jdescottes

This commit is contained in:
Gabriel Luong 2017-01-28 12:50:26 -05:00
Родитель e8c8117123
Коммит f1d7bb9aba
16 изменённых файлов: 774 добавлений и 47 удалений

Просмотреть файл

@ -13,6 +13,7 @@
<link rel="stylesheet" href="chrome://devtools/skin/rules.css"/>
<link rel="stylesheet" href="chrome://devtools/skin/computed.css"/>
<link rel="stylesheet" href="chrome://devtools/skin/fonts.css"/>
<link rel="stylesheet" href="chrome://devtools/skin/boxmodel.css"/>
<link rel="stylesheet" href="chrome://devtools/skin/deprecated-boxmodel.css"/>
<link rel="stylesheet" href="chrome://devtools/skin/layout.css"/>
<link rel="stylesheet" href="chrome://devtools/skin/animationinspector.css"/>

Просмотреть файл

@ -0,0 +1,23 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {
UPDATE_LAYOUT,
} = require("./index");
module.exports = {
/**
* Update the layout state with the new layout properties.
*/
updateLayout(layout) {
return {
type: UPDATE_LAYOUT,
layout,
};
},
};

Просмотреть файл

@ -14,6 +14,9 @@ createEnum([
// Update the entire grids state with the new list of grids.
"UPDATE_GRIDS",
// Update the layout state with the latest layout properties.
"UPDATE_LAYOUT",
// Update the grid highlighter's show grid line numbers state.
"UPDATE_SHOW_GRID_LINE_NUMBERS",

Просмотреть файл

@ -5,6 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'box-model.js',
'grids.js',
'highlighter-settings.js',
'index.js',

Просмотреть файл

@ -8,19 +8,29 @@ const { addons, createClass, createFactory, DOM: dom, PropTypes } =
require("devtools/client/shared/vendor/react");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { LocalizationHelper } = require("devtools/shared/l10n");
const Accordion = createFactory(require("./Accordion"));
const BoxModel = createFactory(require("./BoxModel"));
const Grid = createFactory(require("./Grid"));
const Types = require("../types");
const { getStr } = require("../utils/l10n");
const BOXMODEL_STRINGS_URI = "devtools/client/locales/boxmodel.properties";
const BOXMODEL_L10N = new LocalizationHelper(BOXMODEL_STRINGS_URI);
const App = createClass({
displayName: "App",
propTypes: {
boxModel: PropTypes.shape(Types.boxModel).isRequired,
grids: PropTypes.arrayOf(PropTypes.shape(Types.grid)).isRequired,
highlighterSettings: PropTypes.shape(Types.highlighterSettings).isRequired,
onShowBoxModelEditor: PropTypes.func.isRequired,
onHideBoxModelHighlighter: PropTypes.func.isRequired,
onShowBoxModelHighlighter: PropTypes.func.isRequired,
onToggleGridHighlighter: PropTypes.func.isRequired,
onToggleShowGridLineNumbers: PropTypes.func.isRequired,
onToggleShowInfiniteLines: PropTypes.func.isRequired,
@ -35,12 +45,18 @@ const App = createClass({
},
Accordion({
items: [
{
header: BOXMODEL_L10N.getStr("boxmodel.title"),
component: BoxModel,
componentProps: this.props,
opened: true,
},
{
header: getStr("layout.header"),
component: Grid,
componentProps: this.props,
opened: true
}
opened: true,
},
]
})
);

Просмотреть файл

@ -0,0 +1,52 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { addons, createClass, createFactory, DOM: dom, PropTypes } =
require("devtools/client/shared/vendor/react");
const BoxModelInfo = createFactory(require("./BoxModelInfo"));
const BoxModelMain = createFactory(require("./BoxModelMain"));
const Types = require("../types");
module.exports = createClass({
displayName: "BoxModel",
propTypes: {
boxModel: PropTypes.shape(Types.boxModel).isRequired,
onHideBoxModelHighlighter: PropTypes.func.isRequired,
onShowBoxModelEditor: PropTypes.func.isRequired,
onShowBoxModelHighlighter: PropTypes.func.isRequired,
},
mixins: [ addons.PureRenderMixin ],
render() {
let {
boxModel,
onHideBoxModelHighlighter,
onShowBoxModelEditor,
onShowBoxModelHighlighter,
} = this.props;
return dom.div(
{
className: "boxmodel-container",
},
BoxModelMain({
boxModel,
onHideBoxModelHighlighter,
onShowBoxModelEditor,
onShowBoxModelHighlighter,
}),
BoxModelInfo({
boxModel,
})
);
},
});

Просмотреть файл

@ -0,0 +1,65 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { addons, createClass, DOM: dom, PropTypes } =
require("devtools/client/shared/vendor/react");
const { editableItem } = require("devtools/client/shared/inplace-editor");
const LONG_TEXT_ROTATE_LIMIT = 3;
module.exports = createClass({
displayName: "BoxModelEditable",
propTypes: {
box: PropTypes.string.isRequired,
direction: PropTypes.string.isRequired,
property: PropTypes.string.isRequired,
textContent: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
onShowBoxModelEditor: PropTypes.func.isRequired,
},
mixins: [ addons.PureRenderMixin ],
componentDidMount() {
let { property, onShowBoxModelEditor } = this.props;
editableItem({
element: this.refs.span,
}, (element, event) => {
onShowBoxModelEditor(element, event, property);
});
},
render() {
let {
box,
direction,
property,
textContent,
} = this.props;
let rotate = (direction == "left" || direction == "right") &&
textContent.toString().length > LONG_TEXT_ROTATE_LIMIT;
return dom.p(
{
className: `boxmodel-${box} boxmodel-${direction}
${rotate ? "boxmodel-rotate" : ""}`,
},
dom.span(
{
className: "boxmodel-editable",
"data-box": box,
title: property,
ref: "span",
},
textContent
)
);
},
});

Просмотреть файл

@ -0,0 +1,62 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { LocalizationHelper } = require("devtools/shared/l10n");
const { addons, createClass, DOM: dom, PropTypes } =
require("devtools/client/shared/vendor/react");
const Types = require("../types");
const BOXMODEL_STRINGS_URI = "devtools/client/locales/boxmodel.properties";
const BOXMODEL_L10N = new LocalizationHelper(BOXMODEL_STRINGS_URI);
const SHARED_STRINGS_URI = "devtools/client/locales/shared.properties";
const SHARED_L10N = new LocalizationHelper(SHARED_STRINGS_URI);
module.exports = createClass({
displayName: "BoxModelInfo",
propTypes: {
boxModel: PropTypes.shape(Types.boxModel).isRequired,
},
mixins: [ addons.PureRenderMixin ],
render() {
let { boxModel } = this.props;
let { layout } = boxModel;
let { width, height, position } = layout;
return dom.div(
{
className: "boxmodel-info",
},
dom.span(
{
className: "boxmodel-element-size",
},
SHARED_L10N.getFormatStr("dimensions", width, height)
),
dom.section(
{
className: "boxmodel-position-group",
},
dom.button({
className: "layout-geometry-editor devtools-button",
title: BOXMODEL_L10N.getStr("boxmodel.geometryButton.tooltip"),
}),
dom.span(
{
className: "boxmodel-element-position",
},
position
)
)
);
},
});

Просмотреть файл

@ -0,0 +1,261 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { addons, createClass, createFactory, DOM: dom, PropTypes } =
require("devtools/client/shared/vendor/react");
const { LocalizationHelper } = require("devtools/shared/l10n");
const BoxModelEditable = createFactory(require("./BoxModelEditable"));
const Types = require("../types");
const BOXMODEL_STRINGS_URI = "devtools/client/locales/boxmodel.properties";
const BOXMODEL_L10N = new LocalizationHelper(BOXMODEL_STRINGS_URI);
const SHARED_STRINGS_URI = "devtools/client/locales/shared.properties";
const SHARED_L10N = new LocalizationHelper(SHARED_STRINGS_URI);
module.exports = createClass({
displayName: "BoxModelMain",
propTypes: {
boxModel: PropTypes.shape(Types.boxModel).isRequired,
onHideBoxModelHighlighter: PropTypes.func.isRequired,
onShowBoxModelEditor: PropTypes.func.isRequired,
onShowBoxModelHighlighter: PropTypes.func.isRequired,
},
mixins: [ addons.PureRenderMixin ],
getBorderOrPaddingValue(property) {
let { layout } = this.props.boxModel;
return layout[property] ? parseFloat(layout[property]) : "-";
},
getHeightOrWidthValue(property) {
let { layout } = this.props.boxModel;
if (property == undefined) {
return "-";
}
property -= parseFloat(layout["border-left-width"]) +
parseFloat(layout["border-right-width"]) +
parseFloat(layout["padding-left"]) +
parseFloat(layout["padding-right"]);
property = parseFloat(property.toPrecision(6));
return property;
},
getMarginValue(property, direction) {
let { layout } = this.props.boxModel;
let autoMargins = layout.autoMargins || {};
let value = "-";
if (direction in autoMargins) {
value = "auto";
} else if (layout[property]) {
value = parseFloat(layout[property]);
}
return value;
},
onHighlightMouseOver(event) {
let region = event.target.getAttribute("data-box");
if (!region) {
this.props.onHideBoxModelHighlighter();
}
this.props.onShowBoxModelHighlighter({
region,
showOnly: region,
onlyRegionArea: true,
});
},
render() {
let { boxModel, onShowBoxModelEditor } = this.props;
let { layout } = boxModel;
let { width, height } = layout;
let borderTop = this.getBorderOrPaddingValue("border-top-width");
let borderRight = this.getBorderOrPaddingValue("border-right-width");
let borderBottom = this.getBorderOrPaddingValue("border-bottom-width");
let borderLeft = this.getBorderOrPaddingValue("border-left-width");
let paddingTop = this.getBorderOrPaddingValue("padding-top");
let paddingRight = this.getBorderOrPaddingValue("padding-right");
let paddingBottom = this.getBorderOrPaddingValue("padding-bottom");
let paddingLeft = this.getBorderOrPaddingValue("padding-left");
let marginTop = this.getMarginValue("margin-top", "top");
let marginRight = this.getMarginValue("margin-right", "right");
let marginBottom = this.getMarginValue("margin-bottom", "bottom");
let marginLeft = this.getMarginValue("margin-left", "left");
width = this.getHeightOrWidthValue(width);
height = this.getHeightOrWidthValue(height);
return dom.div(
{
className: "boxmodel-main",
onMouseOver: this.onHighlightMouseOver,
onMouseOut: this.props.onHideBoxModelHighlighter,
},
dom.span(
{
className: "boxmodel-legend",
"data-box": "margin",
title: BOXMODEL_L10N.getStr("boxmodel.margin"),
},
BOXMODEL_L10N.getStr("boxmodel.margin")
),
dom.div(
{
className: "boxmodel-margins",
"data-box": "margin",
title: BOXMODEL_L10N.getStr("boxmodel.margin"),
},
dom.span(
{
className: "boxmodel-legend",
"data-box": "border",
title: BOXMODEL_L10N.getStr("boxmodel.border"),
},
BOXMODEL_L10N.getStr("boxmodel.border")
),
dom.div(
{
className: "boxmodel-borders",
"data-box": "border",
title: BOXMODEL_L10N.getStr("boxmodel.border"),
},
dom.span(
{
className: "boxmodel-legend",
"data-box": "padding",
title: BOXMODEL_L10N.getStr("boxmodel.padding"),
},
BOXMODEL_L10N.getStr("boxmodel.padding")
),
dom.div(
{
className: "boxmodel-paddings",
"data-box": "padding",
title: BOXMODEL_L10N.getStr("boxmodel.padding"),
},
dom.div({
className: "boxmodel-content",
"data-box": "content",
title: BOXMODEL_L10N.getStr("boxmodel.content"),
})
)
),
),
BoxModelEditable({
box: "margin",
direction: "top",
property: "margin-top",
textContent: marginTop,
onShowBoxModelEditor,
}),
BoxModelEditable({
box: "margin",
direction: "right",
property: "margin-right",
textContent: marginRight,
onShowBoxModelEditor,
}),
BoxModelEditable({
box: "margin",
direction: "bottom",
property: "margin-bottom",
textContent: marginBottom,
onShowBoxModelEditor,
}),
BoxModelEditable({
box: "margin",
direction: "left",
property: "margin-left",
textContent: marginLeft,
onShowBoxModelEditor,
}),
BoxModelEditable({
box: "border",
direction: "top",
property: "border-top-width",
textContent: borderTop,
onShowBoxModelEditor,
}),
BoxModelEditable({
box: "border",
direction: "right",
property: "border-right-width",
textContent: borderRight,
onShowBoxModelEditor,
}),
BoxModelEditable({
box: "border",
direction: "bottom",
property: "border-bottom-width",
textContent: borderBottom,
onShowBoxModelEditor,
}),
BoxModelEditable({
box: "border",
direction: "left",
property: "border-left-width",
textContent: borderLeft,
onShowBoxModelEditor,
}),
BoxModelEditable({
box: "padding",
direction: "top",
property: "padding-top",
textContent: paddingTop,
onShowBoxModelEditor,
}),
BoxModelEditable({
box: "padding",
direction: "right",
property: "padding-right",
textContent: paddingRight,
onShowBoxModelEditor,
}),
BoxModelEditable({
box: "padding",
direction: "bottom",
property: "padding-bottom",
textContent: paddingBottom,
onShowBoxModelEditor,
}),
BoxModelEditable({
box: "padding",
direction: "left",
property: "padding-left",
textContent: paddingLeft,
onShowBoxModelEditor,
}),
dom.p(
{
className: "boxmodel-size",
},
dom.span(
{
"data-box": "content",
title: BOXMODEL_L10N.getStr("boxmodel.content"),
},
SHARED_L10N.getFormatStr("dimensions", width, height)
)
)
);
},
});

Просмотреть файл

@ -8,6 +8,10 @@ DevToolsModules(
'Accordion.css',
'Accordion.js',
'App.js',
'BoxModel.js',
'BoxModelEditable.js',
'BoxModelInfo.js',
'BoxModelMain.js',
'Grid.js',
'GridDisplaySettings.js',
'GridList.js',

Просмотреть файл

@ -6,9 +6,16 @@
const Services = require("Services");
const { Task } = require("devtools/shared/task");
const { getCssProperties } = require("devtools/shared/fronts/css-properties");
const { ReflowFront } = require("devtools/shared/fronts/reflow");
const { InplaceEditor } = require("devtools/client/shared/inplace-editor");
const { createFactory, createElement } = require("devtools/client/shared/vendor/react");
const { Provider } = require("devtools/client/shared/vendor/react-redux");
const {
updateLayout,
} = require("./actions/box-model");
const {
updateGridHighlighted,
updateGrids,
@ -21,10 +28,13 @@ const {
const App = createFactory(require("./components/App"));
const Store = require("./store");
const EditingSession = require("./utils/editing-session");
const { LocalizationHelper } = require("devtools/shared/l10n");
const INSPECTOR_L10N =
new LocalizationHelper("devtools/client/locales/inspector.properties");
const NUMERIC = /^-?[\d\.]+$/;
const SHOW_GRID_LINE_NUMBERS = "devtools.gridinspector.showGridLineNumbers";
const SHOW_INFINITE_LINES_PREF = "devtools.gridinspector.showInfiniteLines";
@ -35,15 +45,19 @@ function LayoutView(inspector, window) {
this.store = null;
this.walker = this.inspector.walker;
this.updateBoxModel = this.updateBoxModel.bind(this);
this.onGridLayoutChange = this.onGridLayoutChange.bind(this);
this.onHighlighterChange = this.onHighlighterChange.bind(this);
this.onNewSelection = this.onNewSelection.bind(this);
this.onSidebarSelect = this.onSidebarSelect.bind(this);
this.init();
this.highlighters.on("grid-highlighter-hidden", this.onHighlighterChange);
this.highlighters.on("grid-highlighter-shown", this.onHighlighterChange);
this.inspector.selection.on("new-node-front", this.onNewSelection);
this.inspector.sidebar.on("select", this.onSidebarSelect);
this.init();
}
LayoutView.prototype = {
@ -63,6 +77,95 @@ LayoutView.prototype = {
this.loadHighlighterSettings();
let app = App({
/**
* Hides the box-model highlighter on the currently selected element.
*/
onHideBoxModelHighlighter: () => {
let toolbox = this.inspector.toolbox;
toolbox.highlighterUtils.unhighlight();
},
/**
* Shows the inplace editor when a box model editable value is clicked on the
* box model panel.
*
* @param {DOMNode} element
* The element that was clicked.
* @param {Event} event
* The event object.
* @param {String} property
* The name of the property.
*/
onShowBoxModelEditor: (element, event, property) => {
let session = new EditingSession({
inspector: this.inspector,
doc: this.document,
elementRules: this.elementRules,
});
let initialValue = session.getProperty(property);
let editor = new InplaceEditor({
element: element,
initial: initialValue,
contentType: InplaceEditor.CONTENT_TYPES.CSS_VALUE,
property: {
name: property
},
start: self => {
self.elt.parentNode.classList.add("boxmodel-editing");
},
change: value => {
if (NUMERIC.test(value)) {
value += "px";
}
let properties = [
{ name: property, value: value }
];
if (property.substring(0, 7) == "border-") {
let bprop = property.substring(0, property.length - 5) + "style";
let style = session.getProperty(bprop);
if (!style || style == "none" || style == "hidden") {
properties.push({ name: bprop, value: "solid" });
}
}
session.setProperties(properties).catch(e => console.error(e));
},
done: (value, commit) => {
editor.elt.parentNode.classList.remove("boxmodel-editing");
if (!commit) {
session.revert().then(() => {
session.destroy();
}, e => console.error(e));
return;
}
let node = this.inspector.selection.nodeFront;
this.inspector.pageStyle.getLayout(node, {
autoMargins: true,
}).then(layout => {
this.store.dispatch(updateLayout(layout));
}, e => console.error(e));
},
contextMenu: this.inspector.onTextBoxContextMenu,
cssProperties: getCssProperties(this.inspector.toolbox)
}, event);
},
/**
* Shows the box-model highlighter on the currently selected element.
*
* @param {Object} options
* Options passed to the highlighter actor.
*/
onShowBoxModelHighlighter: (options = {}) => {
let toolbox = this.inspector.toolbox;
let nodeFront = this.inspector.selection.nodeFront;
toolbox.highlighterUtils.highlightNodeFront(nodeFront, options);
},
/**
* Handler for a change in the input checkboxes in the GridList component.
@ -120,7 +223,6 @@ LayoutView.prototype = {
}
}
},
});
let provider = createElement(Provider, {
@ -147,9 +249,16 @@ LayoutView.prototype = {
destroy() {
this.highlighters.off("grid-highlighter-hidden", this.onHighlighterChange);
this.highlighters.off("grid-highlighter-shown", this.onHighlighterChange);
this.inspector.selection.off("new-node-front", this.onNewSelection);
this.inspector.sidebar.off("select", this.onSidebarSelect);
this.layoutInspector.off("grid-layout-changed", this.onGridLayoutChange);
if (this.reflowFront) {
this.untrackReflows();
this.reflowFront.destroy();
this.reflowFront = null;
}
this.document = null;
this.inspector = null;
this.layoutInspector = null;
@ -166,6 +275,16 @@ LayoutView.prototype = {
this.inspector.sidebar.getCurrentTabID() === "layoutview";
},
/**
* Returns true if the layout panel is visible and the current node is valid to
* be displayed in the view.
*/
isPanelVisibleAndNodeValid() {
return this.isPanelVisible() &&
this.inspector.selection.isConnected() &&
this.inspector.selection.isElementNode();
},
/**
* Load the grid highligher display settings into the store from the stored preferences.
*/
@ -180,13 +299,79 @@ LayoutView.prototype = {
},
/**
* Refreshes the layout view by dispatching the new grid data. This is called when the
* Starts listening to reflows in the current tab.
*/
trackReflows() {
if (!this.reflowFront) {
let { target } = this.inspector;
if (target.form.reflowActor) {
this.reflowFront = ReflowFront(target.client,
target.form);
} else {
return;
}
}
this.reflowFront.on("reflows", this.updateBoxModel);
this.reflowFront.start();
},
/**
* Stops listening to reflows in the current tab.
*/
untrackReflows() {
if (!this.reflowFront) {
return;
}
this.reflowFront.off("reflows", this.updateBoxModel);
this.reflowFront.stop();
},
/**
* Updates the box model panel by dispatching the new layout data.
*/
updateBoxModel() {
let lastRequest = Task.spawn((function* () {
if (!(this.isPanelVisible() &&
this.inspector.selection.isConnected() &&
this.inspector.selection.isElementNode())) {
return null;
}
let node = this.inspector.selection.nodeFront;
let layout = yield this.inspector.pageStyle.getLayout(node, {
autoMargins: true,
});
let styleEntries = yield this.inspector.pageStyle.getApplied(node, {});
this.elementRules = styleEntries.map(e => e.rule);
// Update the redux store with the latest layout properties and update the box
// model view.
this.store.dispatch(updateLayout(layout));
// If a subsequent request has been made, wait for that one instead.
if (this._lastRequest != lastRequest) {
return this._lastRequest;
}
this._lastRequest = null;
this.inspector.emit("boxmodel-view-updated");
return null;
}).bind(this)).catch(console.error);
this._lastRequest = lastRequest;
},
/**
* Updates the grid panel by dispatching the new grid data. This is called when the
* layout view becomes visible or the view needs to be updated with new grid data.
*
* @param {Array|null} gridFronts
* Optional array of all GridFront in the current page.
*/
refresh: Task.async(function* (gridFronts) {
updateGridPanel: Task.async(function* (gridFronts) {
// Stop refreshing if the inspector or store is already destroyed.
if (!this.inspector || !this.store) {
return;
@ -221,7 +406,7 @@ LayoutView.prototype = {
*/
onGridLayoutChange(grids) {
if (this.isPanelVisible()) {
this.refresh(grids);
this.updateGridPanel(grids);
}
},
@ -240,6 +425,17 @@ LayoutView.prototype = {
this.store.dispatch(updateGridHighlighted(nodeFront, highlighted));
},
/**
* Selection 'new-node-front' event handler.
*/
onNewSelection: function () {
if (!this.isPanelVisibleAndNodeValid()) {
return;
}
this.updateBoxModel();
},
/**
* Handler for the inspector sidebar select event. Starts listening for
* "grid-layout-changed" if the layout panel is visible. Otherwise, stop
@ -249,11 +445,18 @@ LayoutView.prototype = {
onSidebarSelect() {
if (!this.isPanelVisible()) {
this.layoutInspector.off("grid-layout-changed", this.onGridLayoutChange);
this.untrackReflows();
return;
}
if (this.inspector.selection.isConnected() &&
this.inspector.selection.isElementNode()) {
this.trackReflows();
}
this.layoutInspector.on("grid-layout-changed", this.onGridLayoutChange);
this.refresh();
this.updateBoxModel();
this.updateGridPanel();
},
};

Просмотреть файл

@ -0,0 +1,31 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {
UPDATE_LAYOUT,
} = require("../actions/index");
const INITIAL_BOX_MODEL = {
layout: {},
};
let reducers = {
[UPDATE_LAYOUT](boxModel, { layout }) {
return Object.assign({}, boxModel, {
layout,
});
},
};
module.exports = function (boxModel = INITIAL_BOX_MODEL, action) {
let reducer = reducers[action.type];
if (!reducer) {
return boxModel;
}
return reducer(boxModel, action);
};

Просмотреть файл

@ -4,5 +4,6 @@
"use strict";
exports.boxModel = require("./box-model");
exports.grids = require("./grids");
exports.highlighterSettings = require("./highlighter-settings");

Просмотреть файл

@ -5,6 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'box-model.js',
'grids.js',
'highlighter-settings.js',
'index.js',

Просмотреть файл

@ -6,6 +6,16 @@
const { PropTypes } = require("devtools/client/shared/vendor/react");
/**
* The box model data for the current selected node.
*/
exports.boxModel = {
// The layout information of the current selected node
layout: PropTypes.object,
};
/**
* A single grid container in the document.
*/

Просмотреть файл

@ -2,13 +2,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/ */
#boxmodel-wrapper {
border-bottom-style: solid;
border-bottom-width: 1px;
border-color: var(--theme-splitter-color);
}
/**
* This is the stylesheet of the Box Model view implemented in the layout panel.
*/
#boxmodel-container {
.boxmodel-container {
/* The view will grow bigger as the window gets resized, until 400px */
max-width: 400px;
margin: 0px auto;
@ -17,24 +15,24 @@
/* Header */
#boxmodel-header,
#boxmodel-info {
.boxmodel-header,
.boxmodel-info {
display: flex;
align-items: center;
padding: 4px 17px;
}
#layout-geometry-editor {
.layout-geometry-editor {
visibility: hidden;
}
#layout-geometry-editor::before {
.layout-geometry-editor::before {
background: url(images/geometry-editor.svg) no-repeat center center / 16px 16px;
}
/* Main: contains the box-model regions */
#boxmodel-main {
.boxmodel-main {
position: relative;
box-sizing: border-box;
/* The regions are semi-transparent, so the white background is partly
@ -42,7 +40,7 @@
background-color: white;
color: var(--theme-selection-color);
/* Make sure there is some space between the window's edges and the regions */
margin: 0 14px 4px 14px;
margin: 14px 14px 4px 14px;
width: calc(100% - 2 * 14px);
}
@ -53,73 +51,73 @@
/* Regions are 3 nested elements with wide borders and outlines */
#boxmodel-content {
.boxmodel-content {
height: 18px;
}
#boxmodel-margins,
#boxmodel-borders,
#boxmodel-padding {
.boxmodel-margins,
.boxmodel-borders,
.boxmodel-paddings {
border-color: hsla(210,100%,85%,0.2);
border-width: 18px;
border-style: solid;
outline: dotted 1px hsl(210,100%,85%);
}
#boxmodel-margins {
.boxmodel-margins {
/* This opacity applies to all of the regions, since they are nested */
opacity: .8;
}
/* Regions colors */
#boxmodel-margins {
.boxmodel-margins {
border-color: #edff64;
}
#boxmodel-borders {
.boxmodel-borders {
border-color: #444444;
}
#boxmodel-padding {
.boxmodel-paddings {
border-color: #6a5acd;
}
#boxmodel-content {
.boxmodel-content {
background-color: #87ceeb;
}
.theme-firebug #boxmodel-main,
.theme-firebug #boxmodel-borders,
.theme-firebug #boxmodel-content {
.theme-firebug .boxmodel-main,
.theme-firebug .boxmodel-borders,
.theme-firebug .boxmodel-content {
border-style: solid;
}
.theme-firebug #boxmodel-main,
.theme-firebug #boxmodel-header {
.theme-firebug .boxmodel-main,
.theme-firebug .boxmodel-header {
font-family: var(--proportional-font-family);
}
.theme-firebug #boxmodel-main {
.theme-firebug .boxmodel-main {
color: var(--theme-body-color);
font-size: var(--theme-toolbar-font-size);
}
.theme-firebug #boxmodel-header {
.theme-firebug .boxmodel-header {
font-size: var(--theme-toolbar-font-size);
}
/* Editable region sizes are contained in absolutely positioned <p> */
#boxmodel-main > p {
.boxmodel-main > p {
position: absolute;
pointer-events: none;
margin: 0;
text-align: center;
}
#boxmodel-main > p > span,
#boxmodel-main > p > input {
.boxmodel-main > p > span,
.boxmodel-main > p > input {
vertical-align: middle;
pointer-events: auto;
}
@ -235,11 +233,6 @@
border-bottom-color: hsl(0, 0%, 50%);
}
.styleinspector-propertyeditor {
border: 1px solid #ccc;
padding: 0;
}
/* Make sure the content size doesn't appear as editable like the other sizes */
.boxmodel-size > span {
@ -248,11 +241,11 @@
/* Box Model Info: contains the position and size of the element */
#boxmodel-element-size {
.boxmodel-element-size {
flex: 1;
}
#boxmodel-position-group {
.boxmodel-position-group {
display: flex;
align-items: center;
}