amis2/examples/components/SchemaRender.jsx

312 lines
9.2 KiB
React
Raw Normal View History

2019-06-11 17:00:02 +08:00
import React from 'react';
2022-06-01 15:06:00 +08:00
import {render, toast, Button, LazyComponent, Drawer} from 'amis';
2019-06-11 17:00:02 +08:00
import axios from 'axios';
import Portal from 'react-overlays/Portal';
2022-06-01 21:35:49 +08:00
import {normalizeLink} from 'amis-core';
2019-06-05 09:48:22 +08:00
import {withRouter} from 'react-router';
2020-07-28 18:23:02 +08:00
import copy from 'copy-to-clipboard';
import {qsparse, parseQuery} from 'amis-core';
2019-04-30 11:11:25 +08:00
function loadEditor() {
2019-11-07 10:41:14 +08:00
return new Promise(resolve =>
2022-06-01 21:35:49 +08:00
require(['amis-ui'], component => resolve(component.Editor))
2019-11-07 10:41:14 +08:00
);
2019-04-30 11:11:25 +08:00
}
const viewMode = localStorage.getItem('amis-viewMode') || 'pc';
2021-03-05 10:53:10 +08:00
export default function (schema, showCode, envOverrides) {
2019-11-07 10:41:14 +08:00
if (!schema['$schema']) {
schema = {
...schema
};
}
2019-04-30 11:11:25 +08:00
2019-11-07 10:41:14 +08:00
return withRouter(
class extends React.Component {
static displayName = 'SchemaRenderer';
iframeRef;
state = {open: false, schema: {}};
originalTitle = document.title;
2019-11-07 10:41:14 +08:00
toggleCode = () =>
this.setState({
open: !this.state.open
2019-04-30 11:11:25 +08:00
});
2020-07-28 18:23:02 +08:00
copyCode = () => {
copy(JSON.stringify(schema, null, 2));
2020-07-28 18:23:02 +08:00
toast.success('页面配置JSON已复制到粘贴板');
};
2019-11-07 10:41:14 +08:00
close = () =>
this.setState({
open: false
2019-04-30 11:11:25 +08:00
});
2019-11-07 10:41:14 +08:00
constructor(props) {
super(props);
const {history} = props;
2019-11-07 10:41:14 +08:00
this.env = {
updateLocation: (location, replace) => {
history[replace ? 'replace' : 'push'](normalizeLink(location));
2019-11-07 10:41:14 +08:00
},
jumpTo: (to, action) => {
if (to === 'goBack') {
return history.location.goBack();
}
to = normalizeLink(to);
if (action && action.actionType === 'url') {
action.blank === false
? (window.location.href = to)
: window.open(to);
return;
}
if (action && to && action.target) {
window.open(to, action.target);
return;
}
if (/^https?:\/\//.test(to)) {
window.location.replace(to);
} else {
history.push(to);
}
},
2019-11-07 10:41:14 +08:00
isCurrentUrl: to => {
const history = this.props.history;
2019-11-07 10:41:14 +08:00
const link = normalizeLink(to);
const location = history.location;
let pathname = link;
let search = '';
const idx = link.indexOf('?');
if (~idx) {
pathname = link.substring(0, idx);
search = link.substring(idx);
}
if (search) {
if (pathname !== location.pathname || !location.search) {
return false;
}
const currentQuery = parseQuery(location);
const query = qsparse(search.substring(1));
return Object.keys(query).every(
key => query[key] === currentQuery[key]
);
} else if (pathname === location.pathname) {
return true;
}
return false;
2019-11-07 10:41:14 +08:00
},
2019-11-07 19:03:58 +08:00
fetcher: ({url, method, data, config, headers}) => {
config = config || {};
config.headers = headers || {};
2020-05-14 11:23:44 +08:00
if (config.cancelExecutor) {
config.cancelToken = new axios.CancelToken(config.cancelExecutor);
}
2019-11-07 10:41:14 +08:00
if (data && data instanceof FormData) {
// config.headers = config.headers || {};
// config.headers['Content-Type'] = 'multipart/form-data';
} else if (
data &&
typeof data !== 'string' &&
!(data instanceof Blob) &&
!(data instanceof ArrayBuffer)
) {
data = JSON.stringify(data);
config.headers['Content-Type'] = 'application/json';
}
2019-04-30 11:11:25 +08:00
2019-11-07 10:41:14 +08:00
if (method !== 'post' && method !== 'put' && method !== 'patch') {
if (data) {
if (method === 'delete') {
config.data = data;
} else {
config.params = data;
}
}
2019-04-30 11:11:25 +08:00
2019-11-07 10:41:14 +08:00
return axios[method](url, config);
}
2019-04-30 11:11:25 +08:00
2019-11-07 10:41:14 +08:00
return axios[method](url, data, config);
},
isCancel: value => axios.isCancel(value),
2021-10-13 11:41:43 +08:00
copy: (content, options) => {
copy(content, options);
toast.success('内容已复制到粘贴板');
},
blockRouting: fn => {
return history.block(fn);
},
tracker(eventTrack) {
console.debug('eventTrack', eventTrack);
},
...envOverrides
2019-11-07 10:41:14 +08:00
};
2019-04-30 11:11:25 +08:00
2019-11-07 10:41:14 +08:00
this.handleEditorMount = this.handleEditorMount.bind(this);
this.iframeRef = React.createRef();
this.watchIframeReady = this.watchIframeReady.bind(this);
window.addEventListener('message', this.watchIframeReady, false);
2019-11-07 10:41:14 +08:00
}
2019-04-30 11:11:25 +08:00
2019-11-07 10:41:14 +08:00
handleEditorMount(editor, monaco) {
2020-09-30 13:47:25 +08:00
let host = `${window.location.protocol}//${window.location.host}`;
// 如果在 gh-pages 里面
if (/^\/amis/.test(window.location.pathname)) {
host += '/amis';
}
const schemaUrl = `${host}/schema.json`;
2019-11-07 10:41:14 +08:00
monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
2020-09-30 13:47:25 +08:00
schemas: [
{
uri: schemaUrl,
fileMatch: ['*']
}
],
validate: true,
2019-11-07 10:41:14 +08:00
enableSchemaRequest: true,
2020-09-30 13:47:25 +08:00
allowComments: true
2019-11-07 10:41:14 +08:00
});
}
2019-04-30 11:11:25 +08:00
2019-11-07 10:41:14 +08:00
renderCode() {
return (
<LazyComponent
getComponent={loadEditor}
editorDidMount={this.handleEditorMount}
language="json"
value={schema}
placeholder="加载中,请稍后。。。"
disabled
/>
);
}
2019-04-30 11:11:25 +08:00
watchIframeReady(event) {
// iframe 里面的 amis 初始化了就可以发数据
if (event.data && event.data === 'amisReady') {
this.updateIframe();
}
}
updateIframe() {
if (this.iframeRef && this.iframeRef.current) {
this.iframeRef.current.contentWindow.postMessage(
{
schema: schema,
props: {
location: this.props.location,
theme: this.props.theme,
locale: this.props.locale
}
},
'*'
);
}
}
componentWillUnmount() {
this.props.setAsideFolded && this.props.setAsideFolded(false);
window.removeEventListener('message', this.watchIframeReady, false);
document.title = this.originalTitle;
}
componentDidMount() {
if (schema.title) {
document.title = schema.title;
}
}
2019-11-07 10:41:14 +08:00
renderSchema() {
const {location, theme, locale} = this.props;
2019-11-07 10:41:14 +08:00
if (viewMode === 'mobile') {
return (
<iframe
width="375"
height="100%"
frameBorder={0}
className="mobile-frame"
ref={this.iframeRef}
// @ts-ignore
src={__uri('../mobile.html')}
></iframe>
);
}
2019-11-07 10:41:14 +08:00
return render(
schema,
{
location,
2020-06-02 20:41:51 +08:00
theme,
locale
2019-11-07 10:41:14 +08:00
},
this.env
);
}
render() {
const ns = this.props.classPrefix;
const finalShowCode = this.props.showCode ?? showCode;
2019-11-07 10:41:14 +08:00
return (
2020-07-28 18:23:02 +08:00
<>
<div className="schema-wrapper">
{finalShowCode !== false ? (
2022-06-01 15:06:00 +08:00
<Drawer
2020-07-28 18:23:02 +08:00
classPrefix={ns}
size="lg"
onHide={this.close}
show={this.state.open}
2020-07-29 15:33:25 +08:00
// overlay={false}
2020-07-28 18:23:02 +08:00
closeOnOutside={true}
position="right"
>
{this.state.open ? this.renderCode() : null}
2022-06-01 15:06:00 +08:00
</Drawer>
2020-07-28 18:23:02 +08:00
) : null}
{this.renderSchema()}
</div>
{finalShowCode !== false ? (
2020-07-28 18:23:02 +08:00
// <div className="schema-toolbar-wrapper">
// <div onClick={this.toggleCode}>
// 查看页面配置 <i className="fa fa-code p-l-xs"></i>
// </div>
// <div onClick={this.copyCode}>
// 复制页面配置 <i className="fa fa-copy p-l-xs"></i>
// </div>
// </div>
<Portal
container={() => document.getElementById('Header-toolbar')}
>
<div className="hidden-xs hidden-sm ml-3">
<div>
<div className="Doc-headingList">
<div className="Doc-headingList-item">
<a onClick={this.toggleCode}>
查看配置 <i className="fa fa-code p-l-xs"></i>
</a>
</div>
<div className="Doc-headingList-item">
<a onClick={this.copyCode}>
复制配置 <i className="fa fa-copy p-l-xs"></i>
</a>
</div>
2020-07-29 15:33:25 +08:00
</div>
2020-07-28 18:23:02 +08:00
</div>
</div>
</Portal>
2019-11-07 10:41:14 +08:00
) : null}
2020-07-28 18:23:02 +08:00
</>
2019-11-07 10:41:14 +08:00
);
}
}
);
2019-04-30 11:11:25 +08:00
}