diff options
Diffstat (limited to 'devtools/client/webconsole/new-console-output/components/grip-message-body.js')
-rw-r--r-- | devtools/client/webconsole/new-console-output/components/grip-message-body.js | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/devtools/client/webconsole/new-console-output/components/grip-message-body.js b/devtools/client/webconsole/new-console-output/components/grip-message-body.js new file mode 100644 index 000000000..9e353be0a --- /dev/null +++ b/devtools/client/webconsole/new-console-output/components/grip-message-body.js @@ -0,0 +1,101 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* 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"; + +// If this is being run from Mocha, then the browser loader hasn't set up +// define. We need to do that before loading Rep. +if (typeof define === "undefined") { + require("amd-loader"); +} + +// React +const { + createFactory, + PropTypes +} = require("devtools/client/shared/vendor/react"); +const { createFactories } = require("devtools/client/shared/components/reps/rep-utils"); +const { Rep } = createFactories(require("devtools/client/shared/components/reps/rep")); +const StringRep = createFactories(require("devtools/client/shared/components/reps/string").StringRep).rep; +const VariablesViewLink = createFactory(require("devtools/client/webconsole/new-console-output/components/variables-view-link")); +const { Grip } = require("devtools/client/shared/components/reps/grip"); + +GripMessageBody.displayName = "GripMessageBody"; + +GripMessageBody.propTypes = { + grip: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number, + PropTypes.object, + ]).isRequired, + serviceContainer: PropTypes.shape({ + createElement: PropTypes.func.isRequired, + }), + userProvidedStyle: PropTypes.string, +}; + +function GripMessageBody(props) { + const { grip, userProvidedStyle, serviceContainer } = props; + + let styleObject; + if (userProvidedStyle && userProvidedStyle !== "") { + styleObject = cleanupStyle(userProvidedStyle, serviceContainer.createElement); + } + + return ( + // @TODO once there is a longString rep, also turn off quotes for those. + typeof grip === "string" + ? StringRep({ + object: grip, + useQuotes: false, + mode: props.mode, + style: styleObject + }) + : Rep({ + object: grip, + objectLink: VariablesViewLink, + defaultRep: Grip, + mode: props.mode, + }) + ); +} + +function cleanupStyle(userProvidedStyle, createElement) { + // Regular expression that matches the allowed CSS property names. + const allowedStylesRegex = new RegExp( + "^(?:-moz-)?(?:background|border|box|clear|color|cursor|display|float|font|line|" + + "margin|padding|text|transition|outline|white-space|word|writing|" + + "(?:min-|max-)?width|(?:min-|max-)?height)" + ); + + // Regular expression that matches the forbidden CSS property values. + const forbiddenValuesRegexs = [ + // url(), -moz-element() + /\b(?:url|(?:-moz-)?element)[\s('"]+/gi, + + // various URL protocols + /['"(]*(?:chrome|resource|about|app|data|https?|ftp|file):+\/*/gi, + ]; + + // Use a dummy element to parse the style string. + let dummy = createElement("div"); + dummy.style = userProvidedStyle; + + // Return a style object as expected by React DOM components, e.g. + // {color: "red"} + // without forbidden properties and values. + return [...dummy.style] + .filter(name => { + return allowedStylesRegex.test(name) + && !forbiddenValuesRegexs.some(regex => regex.test(dummy.style[name])); + }) + .reduce((object, name) => { + return Object.assign({ + [name]: dummy.style[name] + }, object); + }, {}); +} + +module.exports = GripMessageBody; |