From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- devtools/client/dom/content/actions/filter.js | 21 ++++ devtools/client/dom/content/actions/grips.js | 54 +++++++++ devtools/client/dom/content/actions/moz.build | 9 ++ devtools/client/dom/content/components/dom-tree.js | 91 +++++++++++++++ .../client/dom/content/components/main-frame.js | 63 +++++++++++ .../client/dom/content/components/main-toolbar.js | 66 +++++++++++ devtools/client/dom/content/components/moz.build | 10 ++ devtools/client/dom/content/constants.js | 9 ++ devtools/client/dom/content/dom-decorator.js | 50 +++++++++ devtools/client/dom/content/dom-view.css | 118 ++++++++++++++++++++ devtools/client/dom/content/dom-view.js | 65 +++++++++++ devtools/client/dom/content/grip-provider.js | 97 ++++++++++++++++ devtools/client/dom/content/moz.build | 19 ++++ devtools/client/dom/content/reducers/filter.js | 29 +++++ devtools/client/dom/content/reducers/grips.js | 123 +++++++++++++++++++++ devtools/client/dom/content/reducers/index.js | 14 +++ devtools/client/dom/content/reducers/moz.build | 10 ++ devtools/client/dom/content/utils.js | 27 +++++ 18 files changed, 875 insertions(+) create mode 100644 devtools/client/dom/content/actions/filter.js create mode 100644 devtools/client/dom/content/actions/grips.js create mode 100644 devtools/client/dom/content/actions/moz.build create mode 100644 devtools/client/dom/content/components/dom-tree.js create mode 100644 devtools/client/dom/content/components/main-frame.js create mode 100644 devtools/client/dom/content/components/main-toolbar.js create mode 100644 devtools/client/dom/content/components/moz.build create mode 100644 devtools/client/dom/content/constants.js create mode 100644 devtools/client/dom/content/dom-decorator.js create mode 100644 devtools/client/dom/content/dom-view.css create mode 100644 devtools/client/dom/content/dom-view.js create mode 100644 devtools/client/dom/content/grip-provider.js create mode 100644 devtools/client/dom/content/moz.build create mode 100644 devtools/client/dom/content/reducers/filter.js create mode 100644 devtools/client/dom/content/reducers/grips.js create mode 100644 devtools/client/dom/content/reducers/index.js create mode 100644 devtools/client/dom/content/reducers/moz.build create mode 100644 devtools/client/dom/content/utils.js (limited to 'devtools/client/dom/content') diff --git a/devtools/client/dom/content/actions/filter.js b/devtools/client/dom/content/actions/filter.js new file mode 100644 index 000000000..3fac9d278 --- /dev/null +++ b/devtools/client/dom/content/actions/filter.js @@ -0,0 +1,21 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* 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 constants = require("../constants"); + +/** + * Used to filter DOM panel content. + */ +function setVisibilityFilter(filter) { + return { + filter: filter, + type: constants.SET_VISIBILITY_FILTER, + }; +} + +// Exports from this module +exports.setVisibilityFilter = setVisibilityFilter; diff --git a/devtools/client/dom/content/actions/grips.js b/devtools/client/dom/content/actions/grips.js new file mode 100644 index 000000000..23d4fc895 --- /dev/null +++ b/devtools/client/dom/content/actions/grips.js @@ -0,0 +1,54 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* 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/. */ + /* globals DomProvider */ +"use strict"; + +const constants = require("../constants"); + +/** + * Used to fetch grip prototype and properties from the backend. + */ +function requestProperties(grip) { + return { + grip: grip, + type: constants.FETCH_PROPERTIES, + status: "start", + error: false + }; +} + +/** + * Executed when grip properties are received from the backend. + */ +function receiveProperties(grip, response, error) { + return { + grip: grip, + type: constants.FETCH_PROPERTIES, + status: "end", + response: response, + error: error + }; +} + +/** + * Used to get properties from the backend and fire an action + * when they are received. + */ +function fetchProperties(grip) { + return dispatch => { + // dispatch(requestProperties(grip)); + + // Use 'DomProvider' object exposed from the chrome scope. + return DomProvider.getPrototypeAndProperties(grip).then(response => { + dispatch(receiveProperties(grip, response)); + }); + }; +} + +// Exports from this module +exports.requestProperties = requestProperties; +exports.receiveProperties = receiveProperties; +exports.fetchProperties = fetchProperties; diff --git a/devtools/client/dom/content/actions/moz.build b/devtools/client/dom/content/actions/moz.build new file mode 100644 index 000000000..6454c00cc --- /dev/null +++ b/devtools/client/dom/content/actions/moz.build @@ -0,0 +1,9 @@ +# 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( + 'filter.js', + 'grips.js', +) diff --git a/devtools/client/dom/content/components/dom-tree.js b/devtools/client/dom/content/components/dom-tree.js new file mode 100644 index 000000000..ef529ac3f --- /dev/null +++ b/devtools/client/dom/content/components/dom-tree.js @@ -0,0 +1,91 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* 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"; + +// React & Redux +const React = require("devtools/client/shared/vendor/react"); +const { connect } = require("devtools/client/shared/vendor/react-redux"); + +// Reps +const { createFactories } = require("devtools/client/shared/components/reps/rep-utils"); +const TreeView = React.createFactory(require("devtools/client/shared/components/tree/tree-view")); +const { Rep } = createFactories(require("devtools/client/shared/components/reps/rep")); +const { Grip } = require("devtools/client/shared/components/reps/grip"); + +// DOM Panel +const { GripProvider } = require("../grip-provider"); +const { DomDecorator } = require("../dom-decorator"); + +// Shortcuts +const PropTypes = React.PropTypes; + +/** + * Renders DOM panel tree. + */ +var DomTree = React.createClass({ + displayName: "DomTree", + + propTypes: { + object: PropTypes.any, + filter: PropTypes.string, + dispatch: PropTypes.func.isRequired, + grips: PropTypes.object, + }, + + /** + * Filter DOM properties. Return true if the object + * should be visible in the tree. + */ + onFilter: function (object) { + if (!this.props.filter) { + return true; + } + + return (object.name && object.name.indexOf(this.props.filter) > -1); + }, + + /** + * Render DOM panel content + */ + render: function () { + let columns = [{ + "id": "value" + }]; + + // This is the integration point with Reps. The DomTree is using + // Reps to render all values. The code also specifies default rep + // used for data types that don't have its own specific template. + let renderValue = props => { + return Rep(Object.assign({}, props, { + defaultRep: Grip, + cropLimit: 50, + })); + }; + + return ( + TreeView({ + object: this.props.object, + provider: new GripProvider(this.props.grips, this.props.dispatch), + decorator: new DomDecorator(), + mode: "short", + columns: columns, + renderValue: renderValue, + onFilter: this.onFilter + }) + ); + } +}); + +const mapStateToProps = (state) => { + return { + grips: state.grips, + filter: state.filter + }; +}; + +// Exports from this module +module.exports = connect(mapStateToProps)(DomTree); + diff --git a/devtools/client/dom/content/components/main-frame.js b/devtools/client/dom/content/components/main-frame.js new file mode 100644 index 000000000..d786314e2 --- /dev/null +++ b/devtools/client/dom/content/components/main-frame.js @@ -0,0 +1,63 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* 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"; + +// React & Redux +const React = require("devtools/client/shared/vendor/react"); +const { connect } = require("devtools/client/shared/vendor/react-redux"); + +// DOM Panel +const DomTree = React.createFactory(require("./dom-tree")); +const MainToolbar = React.createFactory(require("./main-toolbar")); + +// Shortcuts +const { div } = React.DOM; +const PropTypes = React.PropTypes; + +/** + * Renders basic layout of the DOM panel. The DOM panel cotent consists + * from two main parts: toolbar and tree. + */ +var MainFrame = React.createClass({ + displayName: "MainFrame", + + propTypes: { + object: PropTypes.any, + filter: PropTypes.string, + dispatch: PropTypes.func.isRequired, + }, + + /** + * Render DOM panel content + */ + render: function () { + return ( + div({className: "mainFrame"}, + MainToolbar({ + dispatch: this.props.dispatch, + object: this.props.object + }), + div({className: "treeTableBox"}, + DomTree({ + object: this.props.object, + filter: this.props.filter, + }) + ) + ) + ); + } +}); + +// Transform state into props +// Note: use https://github.com/faassen/reselect for better performance. +const mapStateToProps = (state) => { + return { + filter: state.filter + }; +}; + +// Exports from this module +module.exports = connect(mapStateToProps)(MainFrame); diff --git a/devtools/client/dom/content/components/main-toolbar.js b/devtools/client/dom/content/components/main-toolbar.js new file mode 100644 index 000000000..c44a6b4ca --- /dev/null +++ b/devtools/client/dom/content/components/main-toolbar.js @@ -0,0 +1,66 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* 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"; + +// React +const React = require("devtools/client/shared/vendor/react"); +const { l10n } = require("../utils"); + +// Reps +const { createFactories } = require("devtools/client/shared/components/reps/rep-utils"); +const { Toolbar, ToolbarButton } = createFactories(require("devtools/client/jsonview/components/reps/toolbar")); + +// DOM Panel +const SearchBox = React.createFactory(require("devtools/client/shared/components/search-box")); + +// Actions +const { fetchProperties } = require("../actions/grips"); +const { setVisibilityFilter } = require("../actions/filter"); + +// Shortcuts +const PropTypes = React.PropTypes; + +/** + * This template is responsible for rendering a toolbar + * within the 'Headers' panel. + */ +var MainToolbar = React.createClass({ + displayName: "MainToolbar", + + propTypes: { + object: PropTypes.any.isRequired, + dispatch: PropTypes.func.isRequired, + }, + + onRefresh: function () { + this.props.dispatch(fetchProperties(this.props.object)); + }, + + onSearch: function (value) { + this.props.dispatch(setVisibilityFilter(value)); + }, + + render: function () { + return ( + Toolbar({}, + ToolbarButton({ + className: "btn refresh", + onClick: this.onRefresh}, + l10n.getStr("dom.refresh") + ), + SearchBox({ + delay: 250, + onChange: this.onSearch, + placeholder: l10n.getStr("dom.filterDOMPanel"), + type: "filter" + }) + ) + ); + } +}); + +// Exports from this module +module.exports = MainToolbar; diff --git a/devtools/client/dom/content/components/moz.build b/devtools/client/dom/content/components/moz.build new file mode 100644 index 000000000..0fa1f8089 --- /dev/null +++ b/devtools/client/dom/content/components/moz.build @@ -0,0 +1,10 @@ +# 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( + 'dom-tree.js', + 'main-frame.js', + 'main-toolbar.js' +) diff --git a/devtools/client/dom/content/constants.js b/devtools/client/dom/content/constants.js new file mode 100644 index 000000000..f06ca8512 --- /dev/null +++ b/devtools/client/dom/content/constants.js @@ -0,0 +1,9 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* 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"; + +exports.FETCH_PROPERTIES = "FETCH_PROPERTIES"; +exports.SET_VISIBILITY_FILTER = "SET_VISIBILITY_FILTER"; diff --git a/devtools/client/dom/content/dom-decorator.js b/devtools/client/dom/content/dom-decorator.js new file mode 100644 index 000000000..4042df8d3 --- /dev/null +++ b/devtools/client/dom/content/dom-decorator.js @@ -0,0 +1,50 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* 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 { Property } = require("./reducers/grips"); + +// Implementation + +function DomDecorator() { +} + +/** + * Decorator for DOM panel tree component. It's responsible for + * appending an icon to read only properties. + */ +DomDecorator.prototype = { + getRowClass: function (object) { + if (object instanceof Property) { + let value = object.value; + let names = []; + + if (value.enumerable) { + names.push("enumerable"); + } + if (value.writable) { + names.push("writable"); + } + if (value.configurable) { + names.push("configurable"); + } + + return names; + } + + return null; + }, + + /** + * Return custom React template for specified object. The template + * might depend on specified column. + */ + getValueRep: function (value, colId) { + } +}; + +// Exports from this module +exports.DomDecorator = DomDecorator; diff --git a/devtools/client/dom/content/dom-view.css b/devtools/client/dom/content/dom-view.css new file mode 100644 index 000000000..631f8c536 --- /dev/null +++ b/devtools/client/dom/content/dom-view.css @@ -0,0 +1,118 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* 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/. */ + +/******************************************************************************/ +/* General */ + +body { + padding: 0; + margin: 0; + overflow: hidden; +} + +.mainFrame { + display: flex; + flex-direction: column; + height: 100vh; +} + +.mainFrame > .treeTableBox { + flex: 1 1 auto; + overflow: auto; +} + +/******************************************************************************/ +/* TreeView Customization */ + +.treeTable { + width: 100%; +} + +/* Space for read only properties icon */ +.treeTable td.treeValueCell { + padding-inline-start: 16px; +} + +.treeTable .treeLabel, +.treeTable td.treeValueCell .objectBox { + direction: ltr; /* Don't change the direction of english labels */ +} + +/* Read only properties have a padlock icon */ +.treeTable tr:not(.writable) td.treeValueCell { + background: url("chrome://devtools/skin/images/firebug/read-only.svg") no-repeat; + background-position: 1px 5px; + background-size: 10px 10px; +} + +.treeTable tr:not(.writable) td.treeValueCell:dir(rtl) { + background-position-x: right 1px; +} + +/* Non-enumerable properties are grayed out */ +.treeTable tr:not(.enumerable) td.treeValueCell { + opacity: 0.7; +} + +.treeTable > tbody > tr > td { + border-bottom: 1px solid #EFEFEF; +} + +/* Label Types */ +.treeTable .userLabel, +.treeTable .userClassLabel, +.treeTable .userFunctionLabel { + font-weight: bold; +} + +.treeTable .userLabel { + color: #000000; +} + +.treeTable .userClassLabel { + color: #E90000; +} + +.treeTable .userFunctionLabel { + color: #025E2A; +} + +.treeTable .domLabel { + color: #000000; +} + +.treeTable .domClassLabel { + color: #E90000; +} + +.treeTable .domFunctionLabel { + color: #025E2A; +} + +.treeTable .ordinalLabel { + color: SlateBlue; + font-weight: bold; +} + +/******************************************************************************/ +/* Search box */ +.devtools-searchbox { + float: right; +} + +.devtools-searchbox:dir(rtl) { + float: left; +} + +/******************************************************************************/ +/* Theme Dark */ + +.theme-dark .treeTable > tbody > tr > td { + border-bottom: none; +} + +.theme-dark body { + background-color: var(--theme-body-background); +} diff --git a/devtools/client/dom/content/dom-view.js b/devtools/client/dom/content/dom-view.js new file mode 100644 index 000000000..b0ea11dee --- /dev/null +++ b/devtools/client/dom/content/dom-view.js @@ -0,0 +1,65 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* 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"; + +// React & Redux +const React = require("devtools/client/shared/vendor/react"); +const ReactDOM = require("devtools/client/shared/vendor/react-dom"); +const { Provider } = require("devtools/client/shared/vendor/react-redux"); +const { combineReducers } = require("devtools/client/shared/vendor/redux"); + +// DOM Panel +const MainFrame = React.createFactory(require("./components/main-frame")); + +// Store +const createStore = require("devtools/client/shared/redux/create-store")({ + log: false +}); + +const { reducers } = require("./reducers/index"); +const store = createStore(combineReducers(reducers)); + +/** + * This object represents view of the DOM panel and is responsible + * for rendering the content. It renders the top level ReactJS + * component: the MainFrame. + */ +function DomView(localStore) { + addEventListener("devtools/chrome/message", + this.onMessage.bind(this), true); + + // Make it local so, tests can access it. + this.store = localStore; +} + +DomView.prototype = { + initialize: function (rootGrip) { + let content = document.querySelector("#content"); + let mainFrame = MainFrame({ + object: rootGrip, + }); + + // Render top level component + let provider = React.createElement(Provider, { + store: this.store + }, mainFrame); + + this.mainFrame = ReactDOM.render(provider, content); + }, + + onMessage: function (event) { + let data = event.data; + let method = data.type; + + if (typeof this[method] == "function") { + this[method](data.args); + } + }, +}; + +// Construct DOM panel view object and expose it to tests. +// Tests can access it throught: |panel.panelWin.view| +window.view = new DomView(store); diff --git a/devtools/client/dom/content/grip-provider.js b/devtools/client/dom/content/grip-provider.js new file mode 100644 index 000000000..bcda1ff18 --- /dev/null +++ b/devtools/client/dom/content/grip-provider.js @@ -0,0 +1,97 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* 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 { fetchProperties } = require("./actions/grips"); +const { Property } = require("./reducers/grips"); + +// Implementation +function GripProvider(grips, dispatch) { + this.grips = grips; + this.dispatch = dispatch; +} + +/** + * This object provides data for the tree displayed in the tooltip + * content. + */ +GripProvider.prototype = { + /** + * Fetches properties from the backend. These properties might be + * displayed as child objects in e.g. a tree UI widget. + */ + getChildren: function (object) { + let grip = object; + if (object instanceof Property) { + grip = this.getValue(object); + } + + if (!grip || !grip.actor) { + return []; + } + + let props = this.grips.get(grip.actor); + if (!props) { + // Fetch missing data from the backend. Returning a promise + // from data provider causes the tree to show a spinner. + return this.dispatch(fetchProperties(grip)); + } + + return props; + }, + + hasChildren: function (object) { + if (object instanceof Property) { + let value = this.getValue(object); + if (!value) { + return false; + } + + let hasChildren = value.ownPropertyLength > 0; + + if (value.preview) { + hasChildren = hasChildren || value.preview.ownPropertiesLength > 0; + } + + if (value.preview) { + let preview = value.preview; + let k = preview.kind; + let objectsWithProps = ["DOMNode", "ObjectWithURL"]; + hasChildren = hasChildren || (objectsWithProps.indexOf(k) != -1); + hasChildren = hasChildren || (k == "ArrayLike" && preview.length > 0); + } + + return (value.type == "object" && hasChildren); + } + + return null; + }, + + getValue: function (object) { + if (object instanceof Property) { + let value = object.value; + return (typeof value.value != "undefined") ? value.value : + value.getterValue; + } + + return object; + }, + + getLabel: function (object) { + return (object instanceof Property) ? object.name : null; + }, + + getKey: function (object) { + return (object instanceof Property) ? object.key : null; + }, + + getType: function (object) { + return object.class ? object.class : ""; + }, +}; + +// Exports from this module +exports.GripProvider = GripProvider; diff --git a/devtools/client/dom/content/moz.build b/devtools/client/dom/content/moz.build new file mode 100644 index 000000000..b4a9c76bf --- /dev/null +++ b/devtools/client/dom/content/moz.build @@ -0,0 +1,19 @@ +# 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 += [ + 'actions', + 'components', + 'reducers', +] + +DevToolsModules( + 'constants.js', + 'dom-decorator.js', + 'dom-view.css', + 'dom-view.js', + 'grip-provider.js', + 'utils.js', +) diff --git a/devtools/client/dom/content/reducers/filter.js b/devtools/client/dom/content/reducers/filter.js new file mode 100644 index 000000000..3eb5bd3fc --- /dev/null +++ b/devtools/client/dom/content/reducers/filter.js @@ -0,0 +1,29 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* 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 constants = require("../constants"); + +/** + * Initial state definition + */ +function getInitialState() { + return ""; +} + +/** + * Filter displayed object properties. + */ +function filter(state = getInitialState(), action) { + if (action.type == constants.SET_VISIBILITY_FILTER) { + return action.filter; + } + + return state; +} + +// Exports from this module +exports.filter = filter; diff --git a/devtools/client/dom/content/reducers/grips.js b/devtools/client/dom/content/reducers/grips.js new file mode 100644 index 000000000..c7d589434 --- /dev/null +++ b/devtools/client/dom/content/reducers/grips.js @@ -0,0 +1,123 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* 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 constants = require("../constants"); + +/** + * Initial state definition + */ +function getInitialState() { + return new Map(); +} + +/** + * Maintain a cache of received grip responses from the backend. + */ +function grips(state = getInitialState(), action) { + // This reducer supports only one action, fetching actor properties + // from the backend so, bail out if we are dealing with any other + // action. + if (action.type != constants.FETCH_PROPERTIES) { + return state; + } + + switch (action.status) { + case "start": + return onRequestProperties(state, action); + case "end": + return onReceiveProperties(state, action); + } + + return state; +} + +/** + * Handle requestProperties action + */ +function onRequestProperties(state, action) { + return state; +} + +/** + * Handle receiveProperties action + */ +function onReceiveProperties(cache, action) { + let response = action.response; + let from = response.from; + let className = action.grip.class; + + // Properly deal with getters. + mergeProperties(response); + + // Compute list of requested children. + let previewProps = response.preview ? response.preview.ownProperties : null; + let ownProps = response.ownProperties || previewProps || []; + + let props = Object.keys(ownProps).map(key => { + // Array indexes as a special case. We convert any keys that are string + // representations of integers to integers. + if (className === "Array" && isInteger(key)) { + key = parseInt(key, 10); + } + return new Property(key, ownProps[key], key); + }); + + props.sort(sortName); + + // Return new state/map. + let newCache = new Map(cache); + newCache.set(from, props); + + return newCache; +} + +// Helpers + +function mergeProperties(response) { + let { ownProperties } = response; + + // 'safeGetterValues' is new and isn't necessary defined on old grips. + let safeGetterValues = response.safeGetterValues || {}; + + // Merge the safe getter values into one object such that we can use it + // in variablesView. + for (let name of Object.keys(safeGetterValues)) { + if (name in ownProperties) { + let { getterValue, getterPrototypeLevel } = safeGetterValues[name]; + ownProperties[name].getterValue = getterValue; + ownProperties[name].getterPrototypeLevel = getterPrototypeLevel; + } else { + ownProperties[name] = safeGetterValues[name]; + } + } +} + +function sortName(a, b) { + // Display non-enumerable properties at the end. + if (!a.value.enumerable && b.value.enumerable) { + return 1; + } + if (a.value.enumerable && !b.value.enumerable) { + return -1; + } + return a.name > b.name ? 1 : -1; +} + +function isInteger(n) { + // We use parseInt(n, 10) == n to disregard scientific notation e.g. "3e24" + return isFinite(n) && parseInt(n, 10) == n; +} + +function Property(name, value, key) { + this.name = name; + this.value = value; + this.key = key; +} + +// Exports from this module +exports.grips = grips; +exports.Property = Property; diff --git a/devtools/client/dom/content/reducers/index.js b/devtools/client/dom/content/reducers/index.js new file mode 100644 index 000000000..1900487e1 --- /dev/null +++ b/devtools/client/dom/content/reducers/index.js @@ -0,0 +1,14 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* 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 { grips } = require("./grips"); +const { filter } = require("./filter"); + +exports.reducers = { + grips, + filter, +}; diff --git a/devtools/client/dom/content/reducers/moz.build b/devtools/client/dom/content/reducers/moz.build new file mode 100644 index 000000000..0a00b3feb --- /dev/null +++ b/devtools/client/dom/content/reducers/moz.build @@ -0,0 +1,10 @@ +# 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( + 'filter.js', + 'grips.js', + 'index.js', +) diff --git a/devtools/client/dom/content/utils.js b/devtools/client/dom/content/utils.js new file mode 100644 index 000000000..645ba7921 --- /dev/null +++ b/devtools/client/dom/content/utils.js @@ -0,0 +1,27 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* 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"; + +/** + * The default localization just returns the last part of the key + * (all after the last dot). + */ +const DefaultL10N = { + getStr: function (key) { + let index = key.lastIndexOf("."); + return key.substr(index + 1); + } +}; + +/** + * The 'l10n' object is set by main.js in case the DOM panel content + * runs within a scope with chrome privileges. + * + * Note that DOM panel content can also run within a scope with no chrome + * privileges, e.g. in an iframe with type 'content' or in a browser tab, + * which allows using our own tools for development. + */ +exports.l10n = window.l10n || DefaultL10N; -- cgit v1.2.3