From 096d099cd4a0bed6681e6859e514f9be9ce6574e Mon Sep 17 00:00:00 2001 From: unpete Date: Thu, 5 Mar 2020 16:50:56 +0500 Subject: [PATCH] =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D1=8B=D0=B9=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BC=D0=BF=D0=BE=D0=BD=D0=B5=D0=BD=D1=82=20WindowPortal=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=B7=D0=B2=D0=BE=D0=BB=D1=8F=D0=B5=D1=82=20=D1=80?= =?UTF-8?q?=D0=B5=D0=BD=D0=B4=D0=B5=D1=80=D0=B8=D1=82=D1=8C=20=D1=81=D0=BE?= =?UTF-8?q?=D0=B4=D0=B5=D1=80=D0=B6=D0=B8=D0=BC=D0=BE=D0=B5=20=D0=B2=20?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D0=BE=D0=B5=20=D0=BE=D0=BA=D0=BD=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit например, для печатных форм --- package.json | 16 +-- .../metadata-react/src/App/WindowPortal.js | 98 +++++++++++++++++++ packages/metadata-react/src/App/dialogs.js | 10 ++ 3 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 packages/metadata-react/src/App/WindowPortal.js diff --git a/package.json b/package.json index df9defa28..89695a2ee 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "doc": "doc" }, "dependencies": { - "@material-ui/core": "^4.9.4", + "@material-ui/core": "^4.9.5", "@material-ui/icons": "^4.9.1", "alasql": "^0.5.5", "cron": "^1.8.2", @@ -34,11 +34,11 @@ "rc-cascader": "^1.0.1", "rc-time-picker": "^3.7.3", "superlogin-client": "^0.8.0", - "uuid": "^7.0" + "uuid": "^7.0.2" }, "devDependencies": { "@babel/cli": "^7.8.4", - "@babel/core": "^7.8.4", + "@babel/core": "^7.8.7", "@babel/plugin-external-helpers": "^7.8.3", "@babel/plugin-proposal-class-properties": "^7.8.3", "@babel/plugin-proposal-decorators": "^7.8.3", @@ -59,14 +59,14 @@ "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-transform-object-assign": "^7.8.3", "@babel/plugin-transform-runtime": "^7.8.3", - "@babel/preset-env": "^7.8.4", + "@babel/preset-env": "^7.8.7", "@babel/preset-react": "^7.8.3", - "@babel/runtime": "^7.8.4", + "@babel/runtime": "^7.8.7", "babel-eslint": "^10.1.0", "babel-loader": "^8.0.6", "babel-plugin-transform-react-remove-prop-types": "^0.4.24", "concat-files": "^0.1.1", - "cross-env": "^7.0.0", + "cross-env": "^7.0.1", "debug": "^4.1.1", "decompress": "^4.2", "gulp": "^4.0.2", @@ -98,12 +98,12 @@ "redux-dynamic-middlewares": "^2.0", "redux-thunk": "^2.3.0", "rimraf": "^3.0.2", - "rollup": "^1.31.1", + "rollup": "^1.32.0", "rollup-plugin-cleanup": "^3.1.1", "rollup-plugin-node-builtins": "^2.1.2", "rollup-plugin-node-resolve": "^5.2.0", "rollup-plugin-replace": "^2.2.0", - "webpack": "^4.41.6", + "webpack": "^4.42.0", "yargs": "^15.1.0", "yuidocjs": "^0.10" }, diff --git a/packages/metadata-react/src/App/WindowPortal.js b/packages/metadata-react/src/App/WindowPortal.js new file mode 100644 index 000000000..d3265539e --- /dev/null +++ b/packages/metadata-react/src/App/WindowPortal.js @@ -0,0 +1,98 @@ +/** + * Рендерит children в новое окно + * + * @module WindowPortal + * + * Created by Evgeniy Malyarov on 05.03.2020. + */ + +import React from 'react'; +import ReactDOM from 'react-dom'; +import PropTypes from 'prop-types'; + +function copyStyles(sourceDoc, targetDoc) { + Array.from(sourceDoc.styleSheets).forEach(styleSheet => { + if (styleSheet.cssRules) { // true for inline styles + const newStyleEl = targetDoc.createElement('style'); + + Array.from(styleSheet.cssRules).forEach(cssRule => { + newStyleEl.appendChild(targetDoc.createTextNode(cssRule.cssText)); + }); + + targetDoc.head.appendChild(newStyleEl); + } else if (styleSheet.href) { // true for stylesheets loaded from a URL + const newLinkEl = targetDoc.createElement('link'); + + newLinkEl.rel = 'stylesheet'; + newLinkEl.href = styleSheet.href; + targetDoc.head.appendChild(newLinkEl); + } + }); +} + + +export default class WindowPortal extends React.PureComponent { + constructor(props) { + super(props); + this.externalWindow = null; + this.state = {containerEl: null}; + } + + componentDidMount() { + + // Create a new window, a div, and append it to the window + // The div **MUST** be created by the window it is to be + // appended to or it will fail in Edge with a "Permission Denied" + // or similar error. + // See: https://github.com/rmariuzzo/react-new-window/issues/12#issuecomment-386992550 + this.externalWindow = window.open('', '', 'menubar=no,toolbar=no,location=no,status=no,directories=no'); + const containerEl = this.externalWindow.document.createElement('div'); + this.externalWindow.document.body.appendChild(containerEl); + + this.externalWindow.document.title = this.props.title || 'Документ'; + copyStyles(document, this.externalWindow.document); + + // update the state in the parent component if the user closes the + // new window + this.externalWindow.addEventListener('beforeunload', () => { + this.props.handleClose(); + }); + + this.setState({containerEl}, () => { + if(this.props.print) { + setTimeout(() => this.externalWindow && this.externalWindow.print(), 1000); + } + }); + } + + componentWillUnmount() { + // This will fire when this.state.showWindowPortal in the parent component becomes false + // So we tidy up by just closing the window + this.externalWindow.close(); + } + + render() { + // The first render occurs before componentDidMount (where we open + // the new window), so our container may be null, in this case + // render nothing. + const {containerEl} = this.state; + if (!containerEl) { + return null; + } + + const {Component, children, obj, attr} = this.props; + + // Append props.children to the container
in the new window + return ReactDOM.createPortal(Component ? : children, containerEl); + } +} + +WindowPortal.propTypes = { + handleClose: PropTypes.func.isRequired, + title: PropTypes.string, + print: PropTypes.bool, + children: PropTypes.node, + Component: PropTypes.elementType, + obj: PropTypes.object, + attr: PropTypes.object, +}; diff --git a/packages/metadata-react/src/App/dialogs.js b/packages/metadata-react/src/App/dialogs.js index 2583bd9a7..053d13bb3 100644 --- a/packages/metadata-react/src/App/dialogs.js +++ b/packages/metadata-react/src/App/dialogs.js @@ -273,6 +273,16 @@ export default { value: {open: true, message, button: 'OK', handleClose: close_confirm} }); } + }, + + window({Component, obj, title, attr, print}) { + if(this._handleIfaceState) { + this._handleIfaceState({ + component: '', + name: 'wnd_portal', + value: {open: true, Component, obj, title, attr, print, handleClose: this.close_confirm.bind(this, 'wnd_portal')} + }); + } } };