Skip to content

Commit

Permalink
новый компонент WindowPortal позволяет рендерить содержимое в новое окно
Browse files Browse the repository at this point in the history
например, для печатных форм
  • Loading branch information
unpete committed Mar 5, 2020
1 parent 3296a8f commit 096d099
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 8 deletions.
16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand All @@ -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",
Expand Down Expand Up @@ -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"
},
Expand Down
98 changes: 98 additions & 0 deletions packages/metadata-react/src/App/WindowPortal.js
Original file line number Diff line number Diff line change
@@ -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 <div> in the new window
return ReactDOM.createPortal(Component ? <Component obj={obj} attr={attr}/> : 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,
};
10 changes: 10 additions & 0 deletions packages/metadata-react/src/App/dialogs.js
Original file line number Diff line number Diff line change
Expand Up @@ -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')}
});
}
}

};

0 comments on commit 096d099

Please sign in to comment.