summaryrefslogtreecommitdiffstats
path: root/devtools/client/inspector/layout
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/inspector/layout')
-rw-r--r--devtools/client/inspector/layout/components/LayoutApp.js202
-rw-r--r--devtools/client/inspector/layout/components/moz.build9
-rw-r--r--devtools/client/inspector/layout/layout.js136
-rw-r--r--devtools/client/inspector/layout/moz.build17
-rw-r--r--devtools/client/inspector/layout/utils/l10n.js17
-rw-r--r--devtools/client/inspector/layout/utils/moz.build9
6 files changed, 390 insertions, 0 deletions
diff --git a/devtools/client/inspector/layout/components/LayoutApp.js b/devtools/client/inspector/layout/components/LayoutApp.js
new file mode 100644
index 0000000000..a4a3e3b4e2
--- /dev/null
+++ b/devtools/client/inspector/layout/components/LayoutApp.js
@@ -0,0 +1,202 @@
+/* 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 {
+ createFactory,
+ createRef,
+ PureComponent,
+} = require("resource://devtools/client/shared/vendor/react.js");
+const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js");
+const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.js");
+const {
+ connect,
+} = require("resource://devtools/client/shared/vendor/react-redux.js");
+const {
+ getSelectorFromGrip,
+ translateNodeFrontToGrip,
+} = require("resource://devtools/client/inspector/shared/utils.js");
+const { LocalizationHelper } = require("resource://devtools/shared/l10n.js");
+
+const Accordion = createFactory(
+ require("resource://devtools/client/shared/components/Accordion.js")
+);
+const BoxModel = createFactory(
+ require("resource://devtools/client/inspector/boxmodel/components/BoxModel.js")
+);
+const Flexbox = createFactory(
+ require("resource://devtools/client/inspector/flexbox/components/Flexbox.js")
+);
+const Grid = createFactory(
+ require("resource://devtools/client/inspector/grids/components/Grid.js")
+);
+
+const BoxModelTypes = require("resource://devtools/client/inspector/boxmodel/types.js");
+const FlexboxTypes = require("resource://devtools/client/inspector/flexbox/types.js");
+const GridTypes = require("resource://devtools/client/inspector/grids/types.js");
+
+const BOXMODEL_STRINGS_URI = "devtools/client/locales/boxmodel.properties";
+const BOXMODEL_L10N = new LocalizationHelper(BOXMODEL_STRINGS_URI);
+
+const LAYOUT_STRINGS_URI = "devtools/client/locales/layout.properties";
+const LAYOUT_L10N = new LocalizationHelper(LAYOUT_STRINGS_URI);
+
+const FLEXBOX_OPENED_PREF = "devtools.layout.flexbox.opened";
+const FLEX_CONTAINER_OPENED_PREF = "devtools.layout.flex-container.opened";
+const FLEX_ITEM_OPENED_PREF = "devtools.layout.flex-item.opened";
+const GRID_OPENED_PREF = "devtools.layout.grid.opened";
+const BOXMODEL_OPENED_PREF = "devtools.layout.boxmodel.opened";
+
+class LayoutApp extends PureComponent {
+ static get propTypes() {
+ return {
+ boxModel: PropTypes.shape(BoxModelTypes.boxModel).isRequired,
+ dispatch: PropTypes.func.isRequired,
+ flexbox: PropTypes.shape(FlexboxTypes.flexbox).isRequired,
+ getSwatchColorPickerTooltip: PropTypes.func.isRequired,
+ grids: PropTypes.arrayOf(PropTypes.shape(GridTypes.grid)).isRequired,
+ highlighterSettings: PropTypes.shape(GridTypes.highlighterSettings)
+ .isRequired,
+ onSetFlexboxOverlayColor: PropTypes.func.isRequired,
+ onSetGridOverlayColor: PropTypes.func.isRequired,
+ onShowBoxModelEditor: PropTypes.func.isRequired,
+ onShowGridOutlineHighlight: PropTypes.func,
+ onToggleGeometryEditor: PropTypes.func.isRequired,
+ onToggleGridHighlighter: PropTypes.func.isRequired,
+ onToggleShowGridAreas: PropTypes.func.isRequired,
+ onToggleShowGridLineNumbers: PropTypes.func.isRequired,
+ onToggleShowInfiniteLines: PropTypes.func.isRequired,
+ setSelectedNode: PropTypes.func.isRequired,
+ showBoxModelProperties: PropTypes.bool.isRequired,
+ };
+ }
+
+ constructor(props) {
+ super(props);
+ this.containerRef = createRef();
+
+ this.scrollToTop = this.scrollToTop.bind(this);
+ }
+
+ getBoxModelSection() {
+ return {
+ component: BoxModel,
+ componentProps: this.props,
+ contentClassName: "layout-content",
+ header: BOXMODEL_L10N.getStr("boxmodel.title"),
+ id: "layout-section-boxmodel",
+ opened: Services.prefs.getBoolPref(BOXMODEL_OPENED_PREF),
+ onToggle: opened => {
+ Services.prefs.setBoolPref(BOXMODEL_OPENED_PREF, opened);
+ },
+ };
+ }
+
+ getFlexAccordionData(flexContainer) {
+ if (!flexContainer.actorID) {
+ // No flex container or flex item selected.
+ return {
+ pref: FLEXBOX_OPENED_PREF,
+ id: "layout-section-flex",
+ header: LAYOUT_L10N.getStr("flexbox.header"),
+ };
+ } else if (!flexContainer.flexItemShown) {
+ // No flex item selected.
+ return {
+ pref: FLEX_CONTAINER_OPENED_PREF,
+ id: "layout-section-flex-container",
+ header: LAYOUT_L10N.getStr("flexbox.flexContainer"),
+ };
+ }
+
+ return {
+ pref: FLEX_ITEM_OPENED_PREF,
+ id: "layout-section-flex-item",
+ header: LAYOUT_L10N.getFormatStr(
+ "flexbox.flexItemOf",
+ getSelectorFromGrip(translateNodeFrontToGrip(flexContainer.nodeFront))
+ ),
+ };
+ }
+
+ getFlexSection(flexContainer) {
+ const { pref, id, header } = this.getFlexAccordionData(flexContainer);
+
+ return {
+ className: "flex-accordion",
+ component: Flexbox,
+ componentProps: {
+ ...this.props,
+ flexContainer,
+ scrollToTop: this.scrollToTop,
+ },
+ contentClassName: "layout-content",
+ header,
+ id,
+ opened: Services.prefs.getBoolPref(pref),
+ onToggle: opened => {
+ Services.prefs.setBoolPref(pref, opened);
+ },
+ };
+ }
+
+ getGridSection() {
+ return {
+ component: Grid,
+ componentProps: this.props,
+ contentClassName: "layout-content",
+ header: LAYOUT_L10N.getStr("layout.header"),
+ id: "layout-grid-section",
+ opened: Services.prefs.getBoolPref(GRID_OPENED_PREF),
+ onToggle: opened => {
+ Services.prefs.setBoolPref(GRID_OPENED_PREF, opened);
+ },
+ };
+ }
+
+ /**
+ * Scrolls to the top of the layout container.
+ */
+ scrollToTop() {
+ this.containerRef.current.scrollTop = 0;
+ }
+
+ render() {
+ const { flexContainer, flexItemContainer } = this.props.flexbox;
+
+ const items = [
+ this.getFlexSection(flexContainer),
+ this.getGridSection(),
+ this.getBoxModelSection(),
+ ];
+
+ // If the current selected node is both a flex container and flex item. Render
+ // an extra accordion with another Flexbox component where the node is shown as an
+ // item of its parent flex container.
+ // If the node was selected from the markup-view, then show this accordion after the
+ // container accordion. Otherwise show it first.
+ // The reason is that if the user selects an item-container in the markup view, it
+ // is assumed that they want to primarily see that element as a container, so the
+ // container info should be at the top.
+ if (flexItemContainer?.actorID) {
+ items.splice(
+ this.props.flexbox.initiatedByMarkupViewSelection ? 1 : 0,
+ 0,
+ this.getFlexSection(flexItemContainer)
+ );
+ }
+
+ return dom.div(
+ {
+ className: "layout-container",
+ ref: this.containerRef,
+ role: "document",
+ },
+ Accordion({ items })
+ );
+ }
+}
+
+module.exports = connect(state => state)(LayoutApp);
diff --git a/devtools/client/inspector/layout/components/moz.build b/devtools/client/inspector/layout/components/moz.build
new file mode 100644
index 0000000000..bb3e2624ca
--- /dev/null
+++ b/devtools/client/inspector/layout/components/moz.build
@@ -0,0 +1,9 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+DevToolsModules(
+ "LayoutApp.js",
+)
diff --git a/devtools/client/inspector/layout/layout.js b/devtools/client/inspector/layout/layout.js
new file mode 100644
index 0000000000..b44dc29c2a
--- /dev/null
+++ b/devtools/client/inspector/layout/layout.js
@@ -0,0 +1,136 @@
+/* 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 {
+ createFactory,
+ createElement,
+} = require("resource://devtools/client/shared/vendor/react.js");
+const {
+ Provider,
+} = require("resource://devtools/client/shared/vendor/react-redux.js");
+const FlexboxInspector = require("resource://devtools/client/inspector/flexbox/flexbox.js");
+const GridInspector = require("resource://devtools/client/inspector/grids/grid-inspector.js");
+
+const LayoutApp = createFactory(
+ require("resource://devtools/client/inspector/layout/components/LayoutApp.js")
+);
+
+const { LocalizationHelper } = require("resource://devtools/shared/l10n.js");
+const INSPECTOR_L10N = new LocalizationHelper(
+ "devtools/client/locales/inspector.properties"
+);
+
+loader.lazyRequireGetter(
+ this,
+ "SwatchColorPickerTooltip",
+ "resource://devtools/client/shared/widgets/tooltip/SwatchColorPickerTooltip.js"
+);
+
+class LayoutView {
+ constructor(inspector, window) {
+ this.document = window.document;
+ this.inspector = inspector;
+ this.store = inspector.store;
+
+ this.init();
+ }
+
+ init() {
+ if (!this.inspector) {
+ return;
+ }
+
+ const { setSelectedNode } = this.inspector.getCommonComponentProps();
+
+ const {
+ onShowBoxModelEditor,
+ onShowRulePreviewTooltip,
+ onToggleGeometryEditor,
+ } = this.inspector.getPanel("boxmodel").getComponentProps();
+
+ this.flexboxInspector = new FlexboxInspector(
+ this.inspector,
+ this.inspector.panelWin
+ );
+ const { onSetFlexboxOverlayColor } =
+ this.flexboxInspector.getComponentProps();
+
+ this.gridInspector = new GridInspector(
+ this.inspector,
+ this.inspector.panelWin
+ );
+ const {
+ onSetGridOverlayColor,
+ onToggleGridHighlighter,
+ onToggleShowGridAreas,
+ onToggleShowGridLineNumbers,
+ onToggleShowInfiniteLines,
+ } = this.gridInspector.getComponentProps();
+
+ const layoutApp = LayoutApp({
+ getSwatchColorPickerTooltip: () => this.swatchColorPickerTooltip,
+ onSetFlexboxOverlayColor,
+ onSetGridOverlayColor,
+ onShowBoxModelEditor,
+ onShowRulePreviewTooltip,
+ onToggleGeometryEditor,
+ onToggleGridHighlighter,
+ onToggleShowGridAreas,
+ onToggleShowGridLineNumbers,
+ onToggleShowInfiniteLines,
+ setSelectedNode,
+ /**
+ * Shows the box model properties under the box model if true, otherwise, hidden by
+ * default.
+ */
+ showBoxModelProperties: true,
+ });
+
+ const provider = createElement(
+ Provider,
+ {
+ id: "layoutview",
+ key: "layoutview",
+ store: this.store,
+ title: INSPECTOR_L10N.getStr("inspector.sidebar.layoutViewTitle2"),
+ },
+ layoutApp
+ );
+
+ // Expose the provider to let inspector.js use it in setupSidebar.
+ this.provider = provider;
+ }
+
+ /**
+ * Destruction function called when the inspector is destroyed. Cleans up references.
+ */
+ destroy() {
+ if (this._swatchColorPickerTooltip) {
+ this._swatchColorPickerTooltip.destroy();
+ this._swatchColorPickerTooltip = null;
+ }
+
+ this.flexboxInspector.destroy();
+ this.gridInspector.destroy();
+
+ this.document = null;
+ this.inspector = null;
+ this.store = null;
+ }
+
+ get swatchColorPickerTooltip() {
+ if (!this._swatchColorPickerTooltip) {
+ this._swatchColorPickerTooltip = new SwatchColorPickerTooltip(
+ this.inspector.toolbox.doc,
+ this.inspector
+ );
+ }
+
+ return this._swatchColorPickerTooltip;
+ }
+}
+
+module.exports = LayoutView;
diff --git a/devtools/client/inspector/layout/moz.build b/devtools/client/inspector/layout/moz.build
new file mode 100644
index 0000000000..42d0bf4c7b
--- /dev/null
+++ b/devtools/client/inspector/layout/moz.build
@@ -0,0 +1,17 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+DIRS += [
+ "components",
+ "utils",
+]
+
+DevToolsModules(
+ "layout.js",
+)
+
+with Files("**"):
+ BUG_COMPONENT = ("DevTools", "Inspector: Layout")
diff --git a/devtools/client/inspector/layout/utils/l10n.js b/devtools/client/inspector/layout/utils/l10n.js
new file mode 100644
index 0000000000..12f5be3ad3
--- /dev/null
+++ b/devtools/client/inspector/layout/utils/l10n.js
@@ -0,0 +1,17 @@
+/* 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("resource://devtools/shared/l10n.js");
+const L10N = new LocalizationHelper(
+ "devtools/client/locales/layout.properties"
+);
+
+module.exports = {
+ getStr: (...args) => L10N.getStr(...args),
+ getFormatStr: (...args) => L10N.getFormatStr(...args),
+ getFormatStrWithNumbers: (...args) => L10N.getFormatStrWithNumbers(...args),
+ numberWithDecimals: (...args) => L10N.numberWithDecimals(...args),
+};
diff --git a/devtools/client/inspector/layout/utils/moz.build b/devtools/client/inspector/layout/utils/moz.build
new file mode 100644
index 0000000000..ddee85b5f7
--- /dev/null
+++ b/devtools/client/inspector/layout/utils/moz.build
@@ -0,0 +1,9 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+DevToolsModules(
+ "l10n.js",
+)