From 07521a682aab2ed31cb56574dfb3f1b7f7ba78df Mon Sep 17 00:00:00 2001 From: Razvan Caliman Date: Tue, 13 Mar 2018 21:15:52 +0100 Subject: [PATCH] Bug 1443846 - Part 2: Add skeleton for font editor panel. r=gl - Implement basic React component & Redux store and actions for font editor. - Move font overview rendering from FontsApp into its own component: FontOverview. FontsApp remains just a wrapper for FontEditor and FontOverview. - Listen to rule selection events to toggle the display of the font editor and font overview panels. MozReview-Commit-ID: 496LHPqpnKL --- .../inspector/fonts/actions/font-editor.js | 21 +++++ .../client/inspector/fonts/actions/index.js | 3 + .../client/inspector/fonts/actions/moz.build | 1 + .../inspector/fonts/components/FontEditor.js | 32 +++++++ .../fonts/components/FontOverview.js | 88 +++++++++++++++++++ .../inspector/fonts/components/FontsApp.js | 81 +++++------------ .../inspector/fonts/components/moz.build | 2 + devtools/client/inspector/fonts/fonts.js | 53 ++++++++++- .../inspector/fonts/reducers/font-editor.js | 32 +++++++ .../client/inspector/fonts/reducers/moz.build | 1 + devtools/client/inspector/fonts/types.js | 11 +++ devtools/client/inspector/reducers.js | 1 + devtools/client/themes/fonts.css | 4 + 13 files changed, 268 insertions(+), 62 deletions(-) create mode 100644 devtools/client/inspector/fonts/actions/font-editor.js create mode 100644 devtools/client/inspector/fonts/components/FontEditor.js create mode 100644 devtools/client/inspector/fonts/components/FontOverview.js create mode 100644 devtools/client/inspector/fonts/reducers/font-editor.js diff --git a/devtools/client/inspector/fonts/actions/font-editor.js b/devtools/client/inspector/fonts/actions/font-editor.js new file mode 100644 index 000000000000..332506d5a634 --- /dev/null +++ b/devtools/client/inspector/fonts/actions/font-editor.js @@ -0,0 +1,21 @@ +/* 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_EDITOR_VISIBILITY, +} = require("./index"); + +module.exports = { + + toggleFontEditor(isVisible, selector = "") { + return { + type: UPDATE_EDITOR_VISIBILITY, + isVisible, + selector, + }; + }, + +}; diff --git a/devtools/client/inspector/fonts/actions/index.js b/devtools/client/inspector/fonts/actions/index.js index 579a478fd7d5..103830e90726 100644 --- a/devtools/client/inspector/fonts/actions/index.js +++ b/devtools/client/inspector/fonts/actions/index.js @@ -8,6 +8,9 @@ const { createEnum } = require("devtools/client/shared/enum"); createEnum([ + // Toggle the visibiltiy of the font editor + "UPDATE_EDITOR_VISIBILITY", + // Update the list of fonts. "UPDATE_FONTS", diff --git a/devtools/client/inspector/fonts/actions/moz.build b/devtools/client/inspector/fonts/actions/moz.build index 3d181421d849..334bf80fb6a6 100644 --- a/devtools/client/inspector/fonts/actions/moz.build +++ b/devtools/client/inspector/fonts/actions/moz.build @@ -5,6 +5,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. DevToolsModules( + 'font-editor.js', 'font-options.js', 'fonts.js', 'index.js', diff --git a/devtools/client/inspector/fonts/components/FontEditor.js b/devtools/client/inspector/fonts/components/FontEditor.js new file mode 100644 index 000000000000..85b66fe91d99 --- /dev/null +++ b/devtools/client/inspector/fonts/components/FontEditor.js @@ -0,0 +1,32 @@ +/* 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 { PureComponent } = require("devtools/client/shared/vendor/react"); +const dom = require("devtools/client/shared/vendor/react-dom-factories"); +const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); + +const Types = require("../types"); + +class FontEditor extends PureComponent { + static get propTypes() { + return { + fontEditor: PropTypes.shape(Types.fontEditor).isRequired, + }; + } + + render() { + const { selector } = this.props.fontEditor; + + return dom.div( + { + className: "theme-sidebar inspector-tabpanel", + id: "sidebar-panel-fonteditor" + }, `Placeholder for Font Editor panel for selector: ${selector}` + ); + } +} + +module.exports = FontEditor; diff --git a/devtools/client/inspector/fonts/components/FontOverview.js b/devtools/client/inspector/fonts/components/FontOverview.js new file mode 100644 index 000000000000..3adb1f9292cf --- /dev/null +++ b/devtools/client/inspector/fonts/components/FontOverview.js @@ -0,0 +1,88 @@ +/* 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, PureComponent } = require("devtools/client/shared/vendor/react"); +const dom = require("devtools/client/shared/vendor/react-dom-factories"); +const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); + +const Accordion = createFactory(require("devtools/client/inspector/layout/components/Accordion")); +const FontList = createFactory(require("./FontList")); + +const { getStr } = require("../utils/l10n"); +const Types = require("../types"); + +class FontOverview extends PureComponent { + static get propTypes() { + return { + fontData: PropTypes.shape(Types.fontData).isRequired, + fontOptions: PropTypes.shape(Types.fontOptions).isRequired, + onPreviewFonts: PropTypes.func.isRequired, + }; + } + + renderElementFonts() { + let { + fontData, + fontOptions, + onPreviewFonts, + } = this.props; + let { fonts } = fontData; + + return fonts.length ? + FontList({ + fonts, + fontOptions, + onPreviewFonts + }) + : + dom.div( + { + className: "devtools-sidepanel-no-result" + }, + getStr("fontinspector.noFontsOnSelectedElement") + ); + } + + renderOtherFonts() { + let { + fontData, + onPreviewFonts, + fontOptions, + } = this.props; + let { otherFonts } = fontData; + + if (!otherFonts.length) { + return null; + } + + return Accordion({ + items: [ + { + header: getStr("fontinspector.otherFontsInPageHeader"), + component: FontList, + componentProps: { + fontOptions, + fonts: otherFonts, + onPreviewFonts + }, + opened: false + } + ] + }); + } + + render() { + return dom.div( + { + id: "font-container", + }, + this.renderElementFonts(), + this.renderOtherFonts() + ); + } +} + +module.exports = FontOverview; diff --git a/devtools/client/inspector/fonts/components/FontsApp.js b/devtools/client/inspector/fonts/components/FontsApp.js index 10eabab13412..e768a0e79cac 100644 --- a/devtools/client/inspector/fonts/components/FontsApp.js +++ b/devtools/client/inspector/fonts/components/FontsApp.js @@ -9,85 +9,44 @@ const dom = require("devtools/client/shared/vendor/react-dom-factories"); const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); const { connect } = require("devtools/client/shared/vendor/react-redux"); -const Accordion = createFactory(require("devtools/client/inspector/layout/components/Accordion")); -const FontList = createFactory(require("./FontList")); +const FontEditor = createFactory(require("./FontEditor")); +const FontOverview = createFactory(require("./FontOverview")); -const { getStr } = require("../utils/l10n"); const Types = require("../types"); class FontsApp extends PureComponent { static get propTypes() { return { fontData: PropTypes.shape(Types.fontData).isRequired, + fontEditor: PropTypes.shape(Types.fontEditor).isRequired, fontOptions: PropTypes.shape(Types.fontOptions).isRequired, onPreviewFonts: PropTypes.func.isRequired, }; } - renderElementFonts() { - let { - fontData, - fontOptions, - onPreviewFonts, - } = this.props; - let { fonts } = fontData; - - return fonts.length ? - FontList({ - fonts, - fontOptions, - onPreviewFonts - }) - : - dom.div( - { - className: "devtools-sidepanel-no-result" - }, - getStr("fontinspector.noFontsOnSelectedElement") - ); - } - - renderOtherFonts() { - let { - fontData, - onPreviewFonts, - fontOptions, - } = this.props; - let { otherFonts } = fontData; - - if (!otherFonts.length) { - return null; - } - - return Accordion({ - items: [ - { - header: getStr("fontinspector.otherFontsInPageHeader"), - component: FontList, - componentProps: { - fontOptions, - fonts: otherFonts, - onPreviewFonts - }, - opened: false - } - ] - }); - } - render() { + const { + fontData, + fontEditor, + fontOptions, + onPreviewFonts + } = this.props; + return dom.div( { className: "theme-sidebar inspector-tabpanel", id: "sidebar-panel-fontinspector" }, - dom.div( - { - id: "font-container" - }, - this.renderElementFonts(), - this.renderOtherFonts() - ) + fontEditor.isVisible ? + FontEditor({ + fontEditor, + }) + : + FontOverview({ + fontData, + fontOptions, + onPreviewFonts, + }) ); } } diff --git a/devtools/client/inspector/fonts/components/moz.build b/devtools/client/inspector/fonts/components/moz.build index bae2712d3d83..72275194e81f 100644 --- a/devtools/client/inspector/fonts/components/moz.build +++ b/devtools/client/inspector/fonts/components/moz.build @@ -6,7 +6,9 @@ DevToolsModules( 'Font.js', + 'FontEditor.js', 'FontList.js', + 'FontOverview.js', 'FontPreview.js', 'FontsApp.js', ) diff --git a/devtools/client/inspector/fonts/fonts.js b/devtools/client/inspector/fonts/fonts.js index 52db475985b9..f48cd4b6d3b6 100644 --- a/devtools/client/inspector/fonts/fonts.js +++ b/devtools/client/inspector/fonts/fonts.js @@ -19,18 +19,24 @@ const INSPECTOR_L10N = const { updateFonts } = require("./actions/fonts"); const { updatePreviewText } = require("./actions/font-options"); +const { toggleFontEditor } = require("./actions/font-editor"); + +const FONT_EDITOR_ID = "fonteditor"; class FontInspector { constructor(inspector, window) { this.document = window.document; this.inspector = inspector; this.pageStyle = this.inspector.pageStyle; + this.ruleView = this.inspector.getPanel("ruleview").view; + this.selectedRule = null; this.store = this.inspector.store; this.update = this.update.bind(this); - this.onNewNode = this.onNewNode.bind(this); this.onPreviewFonts = this.onPreviewFonts.bind(this); + this.onRuleSelected = this.onRuleSelected.bind(this); + this.onRuleUnselected = this.onRuleUnselected.bind(this); this.onThemeChanged = this.onThemeChanged.bind(this); this.init(); @@ -57,6 +63,8 @@ class FontInspector { this.inspector.selection.on("new-node-front", this.onNewNode); this.inspector.sidebar.on("fontinspector-selected", this.onNewNode); + this.ruleView.on("ruleview-rule-selected", this.onRuleSelected); + this.ruleView.on("ruleview-rule-unselected", this.onRuleUnselected); // Listen for theme changes as the color of the previews depend on the theme gDevTools.on("theme-switched", this.onThemeChanged); @@ -89,11 +97,15 @@ class FontInspector { destroy() { this.inspector.selection.off("new-node-front", this.onNewNode); this.inspector.sidebar.off("fontinspector-selected", this.onNewNode); + this.ruleView.off("ruleview-rule-selected", this.onRuleSelected); + this.ruleView.off("ruleview-rule-unselected", this.onRuleUnselected); gDevTools.off("theme-switched", this.onThemeChanged); this.document = null; this.inspector = null; this.pageStyle = null; + this.ruleView = null; + this.selectedRule = null; this.store = null; } @@ -150,6 +162,45 @@ class FontInspector { this.update(); } + /** + * Handler for "ruleview-rule-selected" event emitted from the rule view when a rule is + * marked as selected for an editor. + * If selected for the font editor, hold a reference to the rule so we know where to + * put property changes coming from the font editor and show the font editor panel. + * + * @param {Object} eventData + * Data payload for the event. Contains: + * - {String} editorId - id of the editor for which the rule was selected + * - {Rule} rule - reference to rule that was selected + */ + onRuleSelected(eventData) { + const { editorId, rule } = eventData; + if (editorId === FONT_EDITOR_ID) { + const selector = rule.matchedSelectors[0]; + this.selectedRule = rule; + this.store.dispatch(toggleFontEditor(true, selector)); + } + } + + /** + * Handler for "ruleview-rule-unselected" event emitted from the rule view when a rule + * was released from being selected for an editor. + * If previously selected for the font editor, release the reference to the rule and + * hide the font editor panel. + * + * @param {Object} eventData + * Data payload for the event. Contains: + * - {String} editorId - id of the editor for which the rule was released + * - {Rule} rule - reference to rule that was released + */ + onRuleUnselected(eventData) { + const { editorId, rule } = eventData; + if (editorId === FONT_EDITOR_ID && rule == this.selectedRule) { + this.selectedRule = null; + this.store.dispatch(toggleFontEditor(false)); + } + } + /** * Handler for the "theme-switched" event. */ diff --git a/devtools/client/inspector/fonts/reducers/font-editor.js b/devtools/client/inspector/fonts/reducers/font-editor.js new file mode 100644 index 000000000000..4d4ba48cffd8 --- /dev/null +++ b/devtools/client/inspector/fonts/reducers/font-editor.js @@ -0,0 +1,32 @@ +/* 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_EDITOR_VISIBILITY, +} = require("../actions/index"); + +const INITIAL_STATE = { + // Whether or not the font editor is visible. + isVisible: false, + // Selector text of the rule where font properties will be written. + selector: "", +}; + +let reducers = { + + [UPDATE_EDITOR_VISIBILITY](state, { isVisible, selector }) { + return { ...state, isVisible, selector }; + }, + +}; + +module.exports = function(state = INITIAL_STATE, action) { + let reducer = reducers[action.type]; + if (!reducer) { + return state; + } + return reducer(state, action); +}; diff --git a/devtools/client/inspector/fonts/reducers/moz.build b/devtools/client/inspector/fonts/reducers/moz.build index f580d5460079..0512407bf402 100644 --- a/devtools/client/inspector/fonts/reducers/moz.build +++ b/devtools/client/inspector/fonts/reducers/moz.build @@ -5,6 +5,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. DevToolsModules( + 'font-editor.js', 'font-options.js', 'fonts.js', ) diff --git a/devtools/client/inspector/fonts/types.js b/devtools/client/inspector/fonts/types.js index 6c74d948dc25..5e9a3fa3748b 100644 --- a/devtools/client/inspector/fonts/types.js +++ b/devtools/client/inspector/fonts/types.js @@ -79,6 +79,17 @@ exports.fontOptions = { previewText: PropTypes.string, }; +exports.fontEditor = { + // Font currently being edited + font: PropTypes.shape(font), + + // Whether or not the font editor is visible + isVisible: PropTypes.bool, + + // Selector text of the rule where font properties will be written + selector: PropTypes.string, +}; + /** * Font data. */ diff --git a/devtools/client/inspector/reducers.js b/devtools/client/inspector/reducers.js index a71a2a7a3106..bcbf5faf0297 100644 --- a/devtools/client/inspector/reducers.js +++ b/devtools/client/inspector/reducers.js @@ -15,5 +15,6 @@ exports.extensionsSidebar = require("devtools/client/inspector/extensions/reduce exports.flexbox = require("devtools/client/inspector/flexbox/reducers/flexbox"); exports.fontOptions = require("devtools/client/inspector/fonts/reducers/font-options"); exports.fontData = require("devtools/client/inspector/fonts/reducers/fonts"); +exports.fontEditor = require("devtools/client/inspector/fonts/reducers/font-editor"); exports.grids = require("devtools/client/inspector/grids/reducers/grids"); exports.highlighterSettings = require("devtools/client/inspector/grids/reducers/highlighter-settings"); diff --git a/devtools/client/themes/fonts.css b/devtools/client/themes/fonts.css index b06e239a454f..b4ad25d1b990 100644 --- a/devtools/client/themes/fonts.css +++ b/devtools/client/themes/fonts.css @@ -10,6 +10,10 @@ height: 100%; } +#sidebar-panel-fonteditor { + padding: 1em; +} + #font-container { overflow: auto; flex: auto;