mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-03-10 09:56:20 +00:00
refactor: remove iceluna-SDK
This commit is contained in:
parent
7167767f29
commit
7db1378fad
@ -33,13 +33,24 @@
|
|||||||
"prepublish": "npm run build"
|
"prepublish": "npm run build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ali/iceluna-sdk": "^1.0.7-beta.12",
|
"@ali/b3-one": "^0.0.17",
|
||||||
|
"@ali/bzb-request": "2.6.1",
|
||||||
|
"@ali/lib-mtop": "^2.5.1",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"debug": "^4.1.1",
|
"debug": "^4.1.1",
|
||||||
"lodash.isempty": "^4.4.0",
|
"events": "^3.0.0",
|
||||||
|
"fetch-jsonp": "^1.1.3",
|
||||||
|
"intl-messageformat": "^7.7.2",
|
||||||
|
"jsonuri": "^2.1.2",
|
||||||
|
"keymaster": "^1.6.2",
|
||||||
|
"lodash": "^4.17.11",
|
||||||
|
"moment": "^2.24.0",
|
||||||
"rax-find-dom-node": "^1.0.1",
|
"rax-find-dom-node": "^1.0.1",
|
||||||
"rax-text": "^1.1.6",
|
"rax-text": "^1.1.6",
|
||||||
"rax-view": "^1.0.0"
|
"rax-view": "^1.0.0",
|
||||||
|
"react-is": "^16.10.1",
|
||||||
|
"serialize-javascript": "^1.7.0",
|
||||||
|
"whatwg-fetch": "^3.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@alib/build-scripts": "^0.1.0",
|
"@alib/build-scripts": "^0.1.0",
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { Component, createElement } from 'rax';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Debug from 'debug';
|
import Debug from 'debug';
|
||||||
import View from 'rax-view';
|
import View from 'rax-view';
|
||||||
import DataHelper from '@ali/iceluna-sdk/lib/utils/dataHelper';
|
import DataHelper from '../utils/dataHelper';
|
||||||
import {
|
import {
|
||||||
forEach,
|
forEach,
|
||||||
getValue,
|
getValue,
|
||||||
@ -18,7 +18,7 @@ import {
|
|||||||
checkPropTypes,
|
checkPropTypes,
|
||||||
generateI18n,
|
generateI18n,
|
||||||
acceptsRef,
|
acceptsRef,
|
||||||
} from '@ali/iceluna-sdk/lib/utils';
|
} from '../utils';
|
||||||
import VisualDom from '../comp/visualDom';
|
import VisualDom from '../comp/visualDom';
|
||||||
import AppContext from '../context/appContext';
|
import AppContext from '../context/appContext';
|
||||||
import CompWrapper from '../hoc/compWrapper';
|
import CompWrapper from '../hoc/compWrapper';
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { createElement } from 'rax';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Debug from 'debug';
|
import Debug from 'debug';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { isSchema, getFileCssName } from '@ali/iceluna-sdk/lib/utils';
|
import { isSchema, getFileCssName } from '../utils';
|
||||||
import BaseEngine from './base';
|
import BaseEngine from './base';
|
||||||
|
|
||||||
const debug = Debug('engine:block');
|
const debug = Debug('engine:block');
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { createElement } from 'rax';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Debug from 'debug';
|
import Debug from 'debug';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { isSchema, getFileCssName } from '@ali/iceluna-sdk/lib/utils';
|
import { isSchema, getFileCssName } from '../utils';
|
||||||
import BaseEngine from './base';
|
import BaseEngine from './base';
|
||||||
|
|
||||||
const debug = Debug('engine:comp');
|
const debug = Debug('engine:comp');
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import { Component, createElement } from 'rax';
|
import { Component, createElement } from 'rax';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Debug from 'debug';
|
import Debug from 'debug';
|
||||||
import * as isEmpty from 'lodash.isempty';
|
import * as isEmpty from 'lodash/isEmpty';
|
||||||
import findDOMNode from 'rax-find-dom-node';
|
import findDOMNode from 'rax-find-dom-node';
|
||||||
import { isFileSchema, goldlog } from '@ali/iceluna-sdk/lib/utils';
|
import { isFileSchema, goldlog } from '../utils';
|
||||||
import AppContext from '../context/appContext';
|
import AppContext from '../context/appContext';
|
||||||
import Page from './pageEngine';
|
import Page from './pageEngine';
|
||||||
import CustomComp from './compEngine';
|
import CustomComp from './compEngine';
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { createElement } from 'rax';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Debug from 'debug';
|
import Debug from 'debug';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { isSchema, getFileCssName } from '@ali/iceluna-sdk/lib/utils';
|
import { isSchema, getFileCssName } from '../utils';
|
||||||
import BaseEngine from './base';
|
import BaseEngine from './base';
|
||||||
|
|
||||||
const debug = Debug('engine:page');
|
const debug = Debug('engine:page');
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { createElement } from 'rax';
|
import { createElement } from 'rax';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Debug from 'debug';
|
import Debug from 'debug';
|
||||||
import { isSchema } from '@ali/iceluna-sdk/lib/utils';
|
import { isSchema } from '../utils';
|
||||||
import AppContext from '../context/appContext';
|
import AppContext from '../context/appContext';
|
||||||
import BaseEngine from './base';
|
import BaseEngine from './base';
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { Component, createElement } from 'rax';
|
import { Component, createElement } from 'rax';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import AppHelper from '@ali/iceluna-sdk/lib/utils/appHelper';
|
import AppHelper from '../utils/appHelper';
|
||||||
import { forEach, isFileSchema } from '@ali/iceluna-sdk/lib/utils';
|
import { forEach, isFileSchema } from '../utils';
|
||||||
import CompEngine from '../engine/compEngine';
|
import CompEngine from '../engine/compEngine';
|
||||||
import BlockEngine from '../engine/blockEngine';
|
import BlockEngine from '../engine/blockEngine';
|
||||||
import AppContext from '../context/appContext';
|
import AppContext from '../context/appContext';
|
||||||
|
|||||||
49
packages/rax-render/src/utils/appHelper.js
Normal file
49
packages/rax-render/src/utils/appHelper.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import EventEmitter from 'events';
|
||||||
|
|
||||||
|
let instance = null;
|
||||||
|
|
||||||
|
EventEmitter.defaultMaxListeners = 100;
|
||||||
|
|
||||||
|
export default class AppHelper extends EventEmitter {
|
||||||
|
static getInstance = () => {
|
||||||
|
if (!instance) {
|
||||||
|
instance = new AppHelper();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(config) {
|
||||||
|
super();
|
||||||
|
instance = this;
|
||||||
|
Object.assign(this, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
get(key) {
|
||||||
|
return this[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
set(key, val) {
|
||||||
|
if (typeof key === 'string') {
|
||||||
|
this[key] = val;
|
||||||
|
} else if (typeof key === 'object') {
|
||||||
|
Object.keys(key).forEach((item) => {
|
||||||
|
this[item] = key[item];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
batchOn(events, lisenter) {
|
||||||
|
if (!Array.isArray(events)) return;
|
||||||
|
events.forEach((event) => this.on(event, lisenter));
|
||||||
|
}
|
||||||
|
|
||||||
|
batchOnce(events, lisenter) {
|
||||||
|
if (!Array.isArray(events)) return;
|
||||||
|
events.forEach((event) => this.once(event, lisenter));
|
||||||
|
}
|
||||||
|
|
||||||
|
batchOff(events, lisenter) {
|
||||||
|
if (!Array.isArray(events)) return;
|
||||||
|
events.forEach((event) => this.off(event, lisenter));
|
||||||
|
}
|
||||||
|
}
|
||||||
299
packages/rax-render/src/utils/dataHelper.js
Normal file
299
packages/rax-render/src/utils/dataHelper.js
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
import { transformArrayToMap, isJSFunction, transformStringToFunction, clone } from './index';
|
||||||
|
import { jsonp, mtop, request, get, post, bzb } from './request';
|
||||||
|
|
||||||
|
const DS_STATUS = {
|
||||||
|
INIT: 'init',
|
||||||
|
LOADING: 'loading',
|
||||||
|
LOADED: 'loaded',
|
||||||
|
ERROR: 'error'
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class DataHelper {
|
||||||
|
constructor(comp, config = {}, appHelper, parser) {
|
||||||
|
this.host = comp;
|
||||||
|
this.config = config;
|
||||||
|
this.parser = parser;
|
||||||
|
this.ajaxList = (config && config.list) || [];
|
||||||
|
this.ajaxMap = transformArrayToMap(this.ajaxList, 'id');
|
||||||
|
this.dataSourceMap = this.generateDataSourceMap();
|
||||||
|
this.appHelper = appHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置config,dataSourceMap状态会被重置;
|
||||||
|
resetConfig(config = {}) {
|
||||||
|
this.config = config;
|
||||||
|
this.ajaxList = (config && config.list) || [];
|
||||||
|
this.ajaxMap = transformArrayToMap(this.ajaxList, 'id');
|
||||||
|
this.dataSourceMap = this.generateDataSourceMap();
|
||||||
|
return this.dataSourceMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新config,只会更新配置,状态保存;
|
||||||
|
updateConfig(config = {}) {
|
||||||
|
this.config = config;
|
||||||
|
this.ajaxList = (config && config.list) || [];
|
||||||
|
const ajaxMap = transformArrayToMap(this.ajaxList, 'id');
|
||||||
|
// 删除已经移除的接口
|
||||||
|
Object.keys(this.ajaxMap).forEach(key => {
|
||||||
|
if (!ajaxMap[key]) {
|
||||||
|
delete this.dataSourceMap[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.ajaxMap = ajaxMap;
|
||||||
|
// 添加未加入到dataSourceMap中的接口
|
||||||
|
this.ajaxList.forEach(item => {
|
||||||
|
if (!this.dataSourceMap[item.id]) {
|
||||||
|
this.dataSourceMap[item.id] = {
|
||||||
|
status: DS_STATUS.INIT,
|
||||||
|
load: (...args) => {
|
||||||
|
return this.getDataSource(item.id, ...args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return this.dataSourceMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
generateDataSourceMap() {
|
||||||
|
const res = {};
|
||||||
|
this.ajaxList.forEach(item => {
|
||||||
|
res[item.id] = {
|
||||||
|
status: DS_STATUS.INIT,
|
||||||
|
load: (...args) => {
|
||||||
|
return this.getDataSource(item.id, ...args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDataSourceMap(id, data, error) {
|
||||||
|
this.dataSourceMap[id].error = error ? error : undefined;
|
||||||
|
this.dataSourceMap[id].data = data;
|
||||||
|
this.dataSourceMap[id].status = error ? DS_STATUS.ERROR : DS_STATUS.LOADED;
|
||||||
|
}
|
||||||
|
|
||||||
|
getInitData() {
|
||||||
|
const initSyncData = this.parser(this.ajaxList).filter(item => {
|
||||||
|
if (item.isInit) {
|
||||||
|
this.dataSourceMap[item.id].status = DS_STATUS.LOADING;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
return this.asyncDataHandler(initSyncData).then(res => {
|
||||||
|
let dataHandler = this.config.dataHandler;
|
||||||
|
if (isJSFunction(dataHandler)) {
|
||||||
|
dataHandler = transformStringToFunction(dataHandler.value);
|
||||||
|
}
|
||||||
|
if (!dataHandler || typeof dataHandler !== 'function') return res;
|
||||||
|
try {
|
||||||
|
return dataHandler.call(this.host, res);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('请求数据处理函数运行出错', e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getDataSource(id, params, otherOptions, callback) {
|
||||||
|
const req = this.parser(this.ajaxMap[id]);
|
||||||
|
const options = req.options || {};
|
||||||
|
if (typeof otherOptions === 'function') {
|
||||||
|
callback = otherOptions;
|
||||||
|
otherOptions = {};
|
||||||
|
}
|
||||||
|
const { headers, ...otherProps } = otherOptions || {};
|
||||||
|
if (!req) {
|
||||||
|
console.warn(`getDataSource API named ${id} not exist`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return this.asyncDataHandler([
|
||||||
|
{
|
||||||
|
...req,
|
||||||
|
options: {
|
||||||
|
...options,
|
||||||
|
// 支持参数为array的情况,当参数为array时,不做参数合并
|
||||||
|
params:
|
||||||
|
Array.isArray(options.params) || Array.isArray(params)
|
||||||
|
? params || options.params
|
||||||
|
: {
|
||||||
|
...options.params,
|
||||||
|
...params
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
...options.headers,
|
||||||
|
...headers
|
||||||
|
},
|
||||||
|
...otherProps
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
.then(res => {
|
||||||
|
try {
|
||||||
|
callback && callback(res && res[id]);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('load请求回调函数报错', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res && res[id];
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
try {
|
||||||
|
callback && callback(null, err);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('load请求回调函数报错', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
asyncDataHandler(asyncDataList) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const allReq = [];
|
||||||
|
const doserReq = [];
|
||||||
|
const doserList = [];
|
||||||
|
const beforeRequest = this.appHelper && this.appHelper.utils && this.appHelper.utils.beforeRequest;
|
||||||
|
const afterRequest = this.appHelper && this.appHelper.utils && this.appHelper.utils.afterRequest;
|
||||||
|
const csrfInput = document.getElementById('_csrf_token');
|
||||||
|
const _tb_token_ = csrfInput && csrfInput.value;
|
||||||
|
asyncDataList.map(req => {
|
||||||
|
const { id, type, options } = req;
|
||||||
|
if (!id || !type) return;
|
||||||
|
if (type === 'doServer') {
|
||||||
|
const { uri, params } = options || {};
|
||||||
|
if (!uri) return;
|
||||||
|
doserList.push(id);
|
||||||
|
doserReq.push({ name: uri, package: 'cms', params });
|
||||||
|
} else {
|
||||||
|
allReq.push(req);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (doserReq.length > 0) {
|
||||||
|
allReq.push({
|
||||||
|
type: 'doServer',
|
||||||
|
options: {
|
||||||
|
uri: '/nrsService.do',
|
||||||
|
cors: true,
|
||||||
|
method: 'POST',
|
||||||
|
params: {
|
||||||
|
data: JSON.stringify(doserReq),
|
||||||
|
_tb_token_
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (allReq.length === 0) resolve({});
|
||||||
|
const res = {};
|
||||||
|
Promise.all(
|
||||||
|
allReq.map(item => {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const { type, id, dataHandler, options } = item;
|
||||||
|
const doFetch = (type, options) => {
|
||||||
|
this.fetchOne(type, options)
|
||||||
|
.then(async data => {
|
||||||
|
if (afterRequest) {
|
||||||
|
this.appHelper.utils.afterRequest(item, data, undefined, async (data, error) => {
|
||||||
|
await fetchHandler(data, error);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await fetchHandler(data, undefined);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(async err => {
|
||||||
|
if (afterRequest) {
|
||||||
|
// 必须要这么调用,否则beforeRequest中的this会丢失
|
||||||
|
this.appHelper.utils.afterRequest(item, undefined, err, async (data, error) => {
|
||||||
|
await fetchHandler(data, error);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await fetchHandler(undefined, err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const fetchHandler = async (data, error) => {
|
||||||
|
if (type === 'doServer') {
|
||||||
|
if (!Array.isArray(data)) {
|
||||||
|
data = [data];
|
||||||
|
}
|
||||||
|
doserList.forEach(async (id, idx) => {
|
||||||
|
const req = this.ajaxMap[id];
|
||||||
|
if (req) {
|
||||||
|
res[id] = await this.dataHandler(id, req.dataHandler, data && data[idx], error);
|
||||||
|
this.updateDataSourceMap(id, res[id], error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res[id] = await this.dataHandler(id, dataHandler, data, error);
|
||||||
|
this.updateDataSourceMap(id, res[id], error);
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (type === 'doServer') {
|
||||||
|
doserList.forEach(item => {
|
||||||
|
this.dataSourceMap[item].status = DS_STATUS.LOADING;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.dataSourceMap[id].status = DS_STATUS.LOADING;
|
||||||
|
}
|
||||||
|
// 请求切片
|
||||||
|
if (beforeRequest) {
|
||||||
|
// 必须要这么调用,否则beforeRequest中的this会丢失
|
||||||
|
this.appHelper.utils.beforeRequest(item, clone(options), options => doFetch(type, options));
|
||||||
|
} else {
|
||||||
|
doFetch(type, options);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
resolve(res);
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
reject(e);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async dataHandler(id, dataHandler, data, error) {
|
||||||
|
if (isJSFunction(dataHandler)) {
|
||||||
|
dataHandler = transformStringToFunction(dataHandler.value);
|
||||||
|
}
|
||||||
|
if (!dataHandler || typeof dataHandler !== 'function') return data;
|
||||||
|
try {
|
||||||
|
return await dataHandler.call(this.host, data, error);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[' + id + ']单个请求数据处理函数运行出错', e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchOne(type, options) {
|
||||||
|
let { uri, method = 'GET', headers, params, ...otherProps } = options;
|
||||||
|
otherProps = otherProps || {};
|
||||||
|
switch (type) {
|
||||||
|
case 'mtop':
|
||||||
|
method && (otherProps.method = method);
|
||||||
|
return mtop(uri, params, otherProps);
|
||||||
|
case 'jsonp':
|
||||||
|
return jsonp(uri, params, otherProps);
|
||||||
|
case 'bzb':
|
||||||
|
return bzb(uri, params, {
|
||||||
|
method,
|
||||||
|
headers,
|
||||||
|
...otherProps
|
||||||
|
});
|
||||||
|
default:
|
||||||
|
method = method.toUpperCase();
|
||||||
|
if (method === 'GET') {
|
||||||
|
return get(uri, params, headers, otherProps);
|
||||||
|
} else if (method === 'POST') {
|
||||||
|
return post(uri, params, headers, otherProps);
|
||||||
|
}
|
||||||
|
return request(uri, method, params, headers, otherProps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
718
packages/rax-render/src/utils/index.js
Normal file
718
packages/rax-render/src/utils/index.js
Normal file
@ -0,0 +1,718 @@
|
|||||||
|
import Debug from 'debug';
|
||||||
|
import _keymaster from 'keymaster';
|
||||||
|
import { forEach as _forEach, shallowEqual as _shallowEqual } from '@ali/b3-one/lib/obj';
|
||||||
|
import { serialize as serializeParams } from '@ali/b3-one/lib/url';
|
||||||
|
import _moment from 'moment';
|
||||||
|
import 'moment/locale/zh-cn';
|
||||||
|
import _pick from 'lodash/pick';
|
||||||
|
import _deepEqual from 'lodash/isEqualWith';
|
||||||
|
import _clone from 'lodash/cloneDeep';
|
||||||
|
import _isEmpty from 'lodash/isEmpty';
|
||||||
|
import _throttle from 'lodash/throttle';
|
||||||
|
import _debounce from 'lodash/debounce';
|
||||||
|
import _serialize from 'serialize-javascript';
|
||||||
|
import * as _jsonuri from 'jsonuri';
|
||||||
|
import IntlMessageFormat from 'intl-messageformat';
|
||||||
|
import pkg from '../../package.json';
|
||||||
|
|
||||||
|
window.sdkVersion = pkg.version;
|
||||||
|
|
||||||
|
export const moment = _moment;
|
||||||
|
moment.locale('zh-cn');
|
||||||
|
export const forEach = _forEach;
|
||||||
|
export const shallowEqual = _shallowEqual;
|
||||||
|
export const keymaster = _keymaster;
|
||||||
|
export const pick = _pick;
|
||||||
|
export const deepEqual = _deepEqual;
|
||||||
|
export const clone = _clone;
|
||||||
|
export const isEmpty = _isEmpty;
|
||||||
|
export const throttle = _throttle;
|
||||||
|
export const debounce = _debounce;
|
||||||
|
export const serialize = _serialize;
|
||||||
|
export const jsonuri = _jsonuri;
|
||||||
|
export { get, post, jsonp, mtop, request } from './request';
|
||||||
|
|
||||||
|
const ReactIs = require('react-is');
|
||||||
|
|
||||||
|
const ReactPropTypesSecret = require('prop-types/lib/ReactPropTypesSecret');
|
||||||
|
|
||||||
|
const factoryWithTypeCheckers = require('prop-types/factoryWithTypeCheckers');
|
||||||
|
|
||||||
|
const PropTypes2 = factoryWithTypeCheckers(ReactIs.isElement, true);
|
||||||
|
|
||||||
|
const EXPRESSION_TYPE = {
|
||||||
|
JSEXPRESSION: 'JSExpression',
|
||||||
|
JSFUNCTION: 'JSFunction',
|
||||||
|
JSSLOT: 'JSSlot'
|
||||||
|
};
|
||||||
|
const EXPRESSION_REG = /^\{\{(\{.*\}|.*?)\}\}$/;
|
||||||
|
const hasSymbol = typeof Symbol === 'function' && Symbol['for'];
|
||||||
|
const REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol['for']('react.forward_ref') : 0xead0;
|
||||||
|
const debug = Debug('utils:index');
|
||||||
|
|
||||||
|
const ENV = {
|
||||||
|
TBE: 'TBE',
|
||||||
|
WEBIDE: 'WEB-IDE',
|
||||||
|
VSCODE: 'VSCODE',
|
||||||
|
WEB: 'WEB'
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name isSchema
|
||||||
|
* @description 判断是否是模型结构
|
||||||
|
*/
|
||||||
|
export function isSchema(schema, ignoreArr) {
|
||||||
|
if (isEmpty(schema)) return false;
|
||||||
|
if (!ignoreArr && Array.isArray(schema)) return schema.every(item => isSchema(item));
|
||||||
|
return !!(schema.componentName && schema.props && (typeof schema.props === 'object' || isJSExpression(schema.props)));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isFileSchema(schema) {
|
||||||
|
if (isEmpty(schema)) return false;
|
||||||
|
return ['Page', 'Block', 'Component', 'Addon', 'Temp'].includes(schema.componentName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断当前页面是否被嵌入到同域的页面中
|
||||||
|
export function inSameDomain() {
|
||||||
|
try {
|
||||||
|
return window.parent !== window && window.parent.location.host === window.location.host;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getFileCssName(fileName) {
|
||||||
|
if (!fileName) return;
|
||||||
|
let name = fileName.replace(/([A-Z])/g, '-$1').toLowerCase();
|
||||||
|
return ('luna-' + name)
|
||||||
|
.split('-')
|
||||||
|
.filter(p => !!p)
|
||||||
|
.join('-');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isJSSlot(obj) {
|
||||||
|
return obj && typeof obj === 'object' && EXPRESSION_TYPE.JSSLOT === obj.type;
|
||||||
|
}
|
||||||
|
export function isJSFunction(obj) {
|
||||||
|
return obj && typeof obj === 'object' && EXPRESSION_TYPE.JSFUNCTION === obj.type;
|
||||||
|
}
|
||||||
|
export function isJSExpression(obj) {
|
||||||
|
//兼容两种写法,有js构造表达式的情况
|
||||||
|
const isJSExpressionObj =
|
||||||
|
obj && typeof obj === 'object' && EXPRESSION_TYPE.JSEXPRESSION === obj.type && typeof obj.value === 'string';
|
||||||
|
const isJSExpressionStr = typeof obj === 'string' && EXPRESSION_REG.test(obj.trim());
|
||||||
|
return isJSExpressionObj || isJSExpressionStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name wait
|
||||||
|
* @description 等待函数
|
||||||
|
*/
|
||||||
|
export function wait(ms) {
|
||||||
|
return new Promise(resolve => setTimeout(() => resolve(true), ms));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function curry(Comp, hocs = []) {
|
||||||
|
return hocs.reverse().reduce((pre, cur) => {
|
||||||
|
return cur(pre);
|
||||||
|
}, Comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取parent window上的值,需要做同域判断
|
||||||
|
* @param {string} key
|
||||||
|
*/
|
||||||
|
export function getParentWinValue(key) {
|
||||||
|
if (inSameDomain()) {
|
||||||
|
return window.parent && window.parent[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getValue(obj, path, defaultValue) {
|
||||||
|
if (isEmpty(obj) || typeof obj !== 'object') return defaultValue;
|
||||||
|
const res = path.split('.').reduce((pre, cur) => {
|
||||||
|
return pre && pre[cur];
|
||||||
|
}, obj);
|
||||||
|
if (res === undefined) return defaultValue;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseObj(schemaStr) {
|
||||||
|
if (typeof schemaStr !== 'string') return schemaStr;
|
||||||
|
//默认调用顶层窗口的parseObj,保障new Function的window对象是顶层的window对象
|
||||||
|
try {
|
||||||
|
if (inSameDomain() && window.parent.__newFunc) {
|
||||||
|
return window.parent.__newFunc(`"use strict"; return ${schemaStr}`)();
|
||||||
|
}
|
||||||
|
return new Function(`"use strict"; return ${schemaStr}`)();
|
||||||
|
} catch (err) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseSearch(search) {
|
||||||
|
if (!search || typeof search !== 'string') {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const str = search.replace(/^\?/, '');
|
||||||
|
const paramStr = str.split('&');
|
||||||
|
const res = {};
|
||||||
|
paramStr.forEach(item => {
|
||||||
|
const regRes = item.split('=');
|
||||||
|
if (regRes[0] && regRes[1]) {
|
||||||
|
res[regRes[0]] = decodeURIComponent(regRes[1]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fastClone(obj) {
|
||||||
|
return parseObj(serialize(obj, { unsafe: true }));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新obj的内容但不改变obj的指针
|
||||||
|
export function fillObj(receiver = {}, ...suppliers) {
|
||||||
|
Object.keys(receiver).forEach(item => {
|
||||||
|
delete receiver[item];
|
||||||
|
});
|
||||||
|
Object.assign(receiver, ...suppliers);
|
||||||
|
return receiver;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 中划线转驼峰
|
||||||
|
export function toHump(name) {
|
||||||
|
return name.replace(/\-(\w)/g, function(all, letter) {
|
||||||
|
return letter.toUpperCase();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 驼峰转中划线
|
||||||
|
export function toLine(name) {
|
||||||
|
return name.replace(/([A-Z])/g, '-$1').toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前环境
|
||||||
|
export function getEnv() {
|
||||||
|
const userAgent = navigator.userAgent;
|
||||||
|
const isVscode = /Electron\//.test(userAgent);
|
||||||
|
if (isVscode) return ENV.VSCODE;
|
||||||
|
const isTheia = window.is_theia === true;
|
||||||
|
if (isTheia) return ENV.WEBIDE;
|
||||||
|
return ENV.WEB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合并skeleton配置
|
||||||
|
* @param {*} 骨架默认配置
|
||||||
|
* @param {*} 用户自定义配置
|
||||||
|
*/
|
||||||
|
export function comboSkeletonConfig(defaultConfig = {}, customConfig) {
|
||||||
|
const { skeleton, theme, addons, hooks, shortCuts, extensions, constants, utils, i18n } = customConfig || {};
|
||||||
|
|
||||||
|
if (skeleton && skeleton.handler && typeof skeleton.handler === 'function') {
|
||||||
|
return skeleton.handler({
|
||||||
|
skeleton,
|
||||||
|
...defaultConfig
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultShortCuts = transformArrayToMap(defaultConfig.shortCuts || [], 'keyboard');
|
||||||
|
const customShortCuts = transformArrayToMap(shortCuts || [], 'keyboard');
|
||||||
|
const localeList = ['zh-CN', 'zh-TW', 'en-US', 'ja-JP'];
|
||||||
|
const i18nConfig = {};
|
||||||
|
localeList.forEach(key => {
|
||||||
|
i18nConfig[key] = {
|
||||||
|
...(defaultConfig.i18n && defaultConfig.i18n[key]),
|
||||||
|
...(i18n && i18n[key])
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
skeleton,
|
||||||
|
theme: {
|
||||||
|
...defaultConfig.theme,
|
||||||
|
...theme
|
||||||
|
},
|
||||||
|
addons: {
|
||||||
|
...defaultConfig.addons,
|
||||||
|
...addons
|
||||||
|
},
|
||||||
|
hooks: [...(defaultConfig.hooks || []), ...(hooks || [])],
|
||||||
|
shortCuts: Object.values({
|
||||||
|
...defaultShortCuts,
|
||||||
|
...customShortCuts
|
||||||
|
}),
|
||||||
|
extensions: {
|
||||||
|
...defaultConfig.extensions,
|
||||||
|
...extensions
|
||||||
|
},
|
||||||
|
constants: {
|
||||||
|
...defaultConfig.constants,
|
||||||
|
...constants
|
||||||
|
},
|
||||||
|
utils: [...(defaultConfig.utils || []), ...(utils || [])],
|
||||||
|
i18n: i18nConfig
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用于构造国际化字符串处理函数
|
||||||
|
* @param {*} locale 国际化标识,例如 zh-CN、en-US
|
||||||
|
* @param {*} messages 国际化语言包
|
||||||
|
*/
|
||||||
|
export function generateI18n(locale = 'zh-CN', messages = {}) {
|
||||||
|
return (key, values = {}) => {
|
||||||
|
if (!messages || !messages[key]) return '';
|
||||||
|
const formater = new IntlMessageFormat(messages[key], locale);
|
||||||
|
return formater.format(values);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断当前组件是否能够设置ref
|
||||||
|
* @param {*} Comp 需要判断的组件
|
||||||
|
*/
|
||||||
|
export function acceptsRef(Comp) {
|
||||||
|
return (
|
||||||
|
(Comp.$$typeof && Comp.$$typeof === REACT_FORWARD_REF_TYPE) || (Comp.prototype && Comp.prototype.isReactComponent)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 黄金令箭埋点
|
||||||
|
* @param {String} gmKey 为黄金令箭业务类型
|
||||||
|
* @param {Object} params 参数
|
||||||
|
* @param {String} logKey 属性串
|
||||||
|
*/
|
||||||
|
export function goldlog(gmKey, params = {}, logKey = 'other') {
|
||||||
|
// vscode 黄金令箭API
|
||||||
|
const sendIDEMessage = window.sendIDEMessage || getParentWinValue('sendIDEMessage');
|
||||||
|
const goKey = serializeParams({
|
||||||
|
sdkVersion: pkg.version,
|
||||||
|
env: getEnv(),
|
||||||
|
...params
|
||||||
|
});
|
||||||
|
if (sendIDEMessage) {
|
||||||
|
sendIDEMessage({
|
||||||
|
action: 'goldlog',
|
||||||
|
data: {
|
||||||
|
logKey: `/iceluna.core.${logKey}`,
|
||||||
|
gmKey,
|
||||||
|
goKey
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
window.goldlog && window.goldlog.record(`/iceluna.core.${logKey}`, gmKey, goKey, 'POST');
|
||||||
|
}
|
||||||
|
|
||||||
|
// utils为编辑器打包生成的utils文件内容,utilsConfig为数据库存放的utils配置
|
||||||
|
export function generateUtils(utils, utilsConfig) {
|
||||||
|
if (!Array.isArray(utilsConfig)) return { ...utils };
|
||||||
|
const res = {};
|
||||||
|
utilsConfig.forEach(item => {
|
||||||
|
if (!item.name || !item.type || !item.content) return;
|
||||||
|
if (item.type === 'function' && typeof item.content === 'function') {
|
||||||
|
res[item.name] = item.content;
|
||||||
|
} else if (item.type === 'npm' && utils[item.name]) {
|
||||||
|
res[item.name] = utils[item.name];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
// 复制到粘贴板
|
||||||
|
export function setClipboardData(str) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (typeof str !== 'string') reject('不支持拷贝');
|
||||||
|
if (navigator.clipboard) {
|
||||||
|
navigator.clipboard
|
||||||
|
.writeText(str)
|
||||||
|
.then(() => {
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
reject('复制失败,请重试!', err);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const textArea = document.createElement('textarea');
|
||||||
|
textArea.value = str;
|
||||||
|
document.body.appendChild(textArea);
|
||||||
|
textArea.focus();
|
||||||
|
textArea.select();
|
||||||
|
try {
|
||||||
|
let successful = document.execCommand('copy');
|
||||||
|
if (successful) {
|
||||||
|
document.body.removeChild(textArea);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
document.body.removeChild(textArea);
|
||||||
|
reject('复制失败,请重试!', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 获取粘贴板数据
|
||||||
|
export function getClipboardData() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (window.clipboardData) {
|
||||||
|
resolve(window.clipboardData.getData('text'));
|
||||||
|
} else if (navigator.clipboard) {
|
||||||
|
return navigator.clipboard
|
||||||
|
.readText()
|
||||||
|
.then(res => {
|
||||||
|
resolve(res);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
reject('粘贴板获取失败', err);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
reject('粘贴板获取失败');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 将函数返回结果转成promise形式,如果函数有返回值则根据返回值的bool类型判断是reject还是resolve,若函数无返回值默认执行resolve
|
||||||
|
export function transformToPromise(input) {
|
||||||
|
if (input instanceof Promise) return input;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (input || input === undefined) {
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function moveArrayItem(arr, sourceIdx, distIdx, direction) {
|
||||||
|
if (
|
||||||
|
!Array.isArray(arr) ||
|
||||||
|
sourceIdx === distIdx ||
|
||||||
|
sourceIdx < 0 ||
|
||||||
|
sourceIdx >= arr.length ||
|
||||||
|
distIdx < 0 ||
|
||||||
|
distIdx >= arr.length
|
||||||
|
)
|
||||||
|
return arr;
|
||||||
|
const item = arr[sourceIdx];
|
||||||
|
if (direction === 'after') {
|
||||||
|
arr.splice(distIdx + 1, 0, item);
|
||||||
|
} else {
|
||||||
|
arr.splice(distIdx, 0, item);
|
||||||
|
}
|
||||||
|
if (sourceIdx < distIdx) {
|
||||||
|
arr.splice(sourceIdx, 1);
|
||||||
|
} else {
|
||||||
|
arr.splice(sourceIdx + 1, 1);
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function transformArrayToMap(arr, key, overwrite = true) {
|
||||||
|
if (isEmpty(arr) || !Array.isArray(arr)) return {};
|
||||||
|
const res = {};
|
||||||
|
arr.forEach(item => {
|
||||||
|
const curKey = item[key];
|
||||||
|
if (item[key] === undefined) return;
|
||||||
|
if (res[curKey] && !overwrite) return;
|
||||||
|
res[curKey] = item;
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function checkPropTypes(value, name, rule, componentName) {
|
||||||
|
if (typeof rule === 'string') {
|
||||||
|
rule = new Function(`"use strict"; const PropTypes = arguments[0]; return ${rule}`)(PropTypes2);
|
||||||
|
}
|
||||||
|
if (!rule || typeof rule !== 'function') {
|
||||||
|
console.warn('checkPropTypes should have a function type rule argument');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const err = rule(
|
||||||
|
{
|
||||||
|
[name]: value
|
||||||
|
},
|
||||||
|
name,
|
||||||
|
componentName,
|
||||||
|
'prop',
|
||||||
|
null,
|
||||||
|
ReactPropTypesSecret
|
||||||
|
);
|
||||||
|
if (err) {
|
||||||
|
console.warn(err);
|
||||||
|
}
|
||||||
|
return !err;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function transformSchemaToPure(obj) {
|
||||||
|
const pureObj = obj => {
|
||||||
|
if (Array.isArray(obj)) {
|
||||||
|
return obj.map(item => pureObj(item));
|
||||||
|
} else if (typeof obj === 'object') {
|
||||||
|
// 对于undefined及null直接返回
|
||||||
|
if (!obj) return obj;
|
||||||
|
const res = {};
|
||||||
|
forEach(obj, (val, key) => {
|
||||||
|
if (key.startsWith('__') && key !== '__ignoreParse') return;
|
||||||
|
res[key] = pureObj(val);
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
};
|
||||||
|
return pureObj(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function transformSchemaToStandard(obj) {
|
||||||
|
const standardObj = obj => {
|
||||||
|
if (Array.isArray(obj)) {
|
||||||
|
return obj.map(item => standardObj(item));
|
||||||
|
} else if (typeof obj === 'object') {
|
||||||
|
// 对于undefined及null直接返回
|
||||||
|
if (!obj) return obj;
|
||||||
|
const res = {};
|
||||||
|
forEach(obj, (val, key) => {
|
||||||
|
if (key.startsWith('__') && key !== '__ignoreParse') return;
|
||||||
|
if (isSchema(val) && key !== 'children' && obj.type !== 'JSSlot') {
|
||||||
|
res[key] = {
|
||||||
|
type: 'JSSlot',
|
||||||
|
value: standardObj(val)
|
||||||
|
};
|
||||||
|
// table特殊处理
|
||||||
|
if (key === 'cell') {
|
||||||
|
res[key].params = ['value', 'index', 'record'];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res[key] = standardObj(val);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
} else if (typeof obj === 'function') {
|
||||||
|
return {
|
||||||
|
type: 'JSFunction',
|
||||||
|
value: obj.toString()
|
||||||
|
};
|
||||||
|
} else if (typeof obj === 'string' && EXPRESSION_REG.test(obj.trim())) {
|
||||||
|
const regRes = obj.trim().match(EXPRESSION_REG);
|
||||||
|
return {
|
||||||
|
type: 'JSExpression',
|
||||||
|
value: (regRes && regRes[1]) || ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
};
|
||||||
|
return standardObj(obj, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function transformStringToFunction(str) {
|
||||||
|
if (typeof str !== 'string') return str;
|
||||||
|
if (inSameDomain() && window.parent.__newFunc) {
|
||||||
|
return window.parent.__newFunc(`"use strict"; return ${str}`)();
|
||||||
|
} else {
|
||||||
|
return new Function(`"use strict"; return ${str}`)();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addCssTag(id, content) {
|
||||||
|
let styleTag = document.getElementById(id);
|
||||||
|
if (styleTag) {
|
||||||
|
styleTag.innerHTML = content;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
styleTag = document.createElement('style');
|
||||||
|
styleTag.id = id;
|
||||||
|
styleTag.class = 'luna-style';
|
||||||
|
styleTag.innerHTML = content;
|
||||||
|
document.head.appendChild(styleTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册快捷
|
||||||
|
export function registShortCuts(config, appHelper) {
|
||||||
|
const keyboardFilter = (keymaster.filter = event => {
|
||||||
|
const eTarget = event.target || event.srcElement;
|
||||||
|
const tagName = eTarget.tagName;
|
||||||
|
const isInput = !!(tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA');
|
||||||
|
const isContenteditable = target => {
|
||||||
|
while (target) {
|
||||||
|
if (target.contentEditable === 'true') return true;
|
||||||
|
target = target.parentNode;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
if (isInput || isContenteditable(eTarget)) {
|
||||||
|
if (event.metaKey === true && [70, 83].includes(event.keyCode)) event.preventDefault(); //禁止触发chrome原生的页面保存或查找
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const ideMessage = appHelper.utils && appHelper.utils.ideMessage;
|
||||||
|
|
||||||
|
//复制
|
||||||
|
if (!document.copyListener) {
|
||||||
|
document.copyListener = e => {
|
||||||
|
if (!keyboardFilter(e) || appHelper.isCopying) return;
|
||||||
|
const schema = appHelper.schemaHelper && appHelper.schemaHelper.schemaMap[appHelper.activeKey];
|
||||||
|
if (!schema || !isSchema(schema)) return;
|
||||||
|
appHelper.isCopying = true;
|
||||||
|
const schemaStr = serialize(transformSchemaToPure(schema), {
|
||||||
|
unsafe: true
|
||||||
|
});
|
||||||
|
setClipboardData(schemaStr)
|
||||||
|
.then(() => {
|
||||||
|
ideMessage && ideMessage('success', '当前内容已复制到剪贴板,请使用快捷键Command+v进行粘贴');
|
||||||
|
appHelper.emit('schema.copy', schemaStr, schema);
|
||||||
|
appHelper.isCopying = false;
|
||||||
|
})
|
||||||
|
.catch(errMsg => {
|
||||||
|
ideMessage && ideMessage('error', errMsg);
|
||||||
|
appHelper.isCopying = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
document.addEventListener('copy', document.copyListener);
|
||||||
|
if (getParentWinValue('vscode')) {
|
||||||
|
keymaster('command+c', document.copyListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//粘贴
|
||||||
|
if (!document.pasteListener) {
|
||||||
|
const doPaste = (e, text) => {
|
||||||
|
if (!keyboardFilter(e) || appHelper.isPasting) return;
|
||||||
|
const schemaHelper = appHelper.schemaHelper;
|
||||||
|
let targetKey = appHelper.activeKey;
|
||||||
|
let direction = 'after';
|
||||||
|
const topKey = schemaHelper.schema && schemaHelper.schema.__ctx && schemaHelper.schema.__ctx.lunaKey;
|
||||||
|
if (!targetKey || topKey === targetKey) {
|
||||||
|
const schemaHelper = appHelper.schemaHelper;
|
||||||
|
const topKey = schemaHelper.schema && schemaHelper.schema.__ctx && schemaHelper.schema.__ctx.lunaKey;
|
||||||
|
if (!topKey) return;
|
||||||
|
targetKey = topKey;
|
||||||
|
direction = 'in';
|
||||||
|
}
|
||||||
|
appHelper.isPasting = true;
|
||||||
|
const schema = parseObj(text);
|
||||||
|
if (!isSchema(schema)) {
|
||||||
|
appHelper.emit('illegalSchema.paste', text);
|
||||||
|
// ideMessage && ideMessage('error', '当前内容不是模型结构,不能粘贴进来!');
|
||||||
|
console.warn('paste schema illegal');
|
||||||
|
appHelper.isPasting = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
appHelper.emit('material.add', {
|
||||||
|
schema,
|
||||||
|
targetKey,
|
||||||
|
direction
|
||||||
|
});
|
||||||
|
appHelper.isPasting = false;
|
||||||
|
appHelper.emit('schema.paste', schema);
|
||||||
|
};
|
||||||
|
document.pasteListener = e => {
|
||||||
|
const clipboardData = e.clipboardData || window.clipboardData;
|
||||||
|
const text = clipboardData && clipboardData.getData('text');
|
||||||
|
doPaste(e, text);
|
||||||
|
};
|
||||||
|
document.addEventListener('paste', document.pasteListener);
|
||||||
|
if (getParentWinValue('vscode')) {
|
||||||
|
keymaster('command+v', e => {
|
||||||
|
const sendIDEMessage = getParentWinValue('sendIDEMessage');
|
||||||
|
sendIDEMessage &&
|
||||||
|
sendIDEMessage({
|
||||||
|
action: 'readClipboard'
|
||||||
|
})
|
||||||
|
.then(text => {
|
||||||
|
doPaste(e, text);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.warn(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(config || []).forEach(item => {
|
||||||
|
keymaster(item.keyboard, ev => {
|
||||||
|
ev.preventDefault();
|
||||||
|
item.handler(ev, appHelper, keymaster);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取消注册快捷
|
||||||
|
export function unRegistShortCuts(config) {
|
||||||
|
(config || []).forEach(item => {
|
||||||
|
keymaster.unbind(item.keyboard);
|
||||||
|
});
|
||||||
|
if (getParentWinValue('vscode')) {
|
||||||
|
keymaster.unbind('command+c');
|
||||||
|
keymaster.unbind('command+v');
|
||||||
|
}
|
||||||
|
if (document.copyListener) {
|
||||||
|
document.removeEventListener('copy', document.copyListener);
|
||||||
|
delete document.copyListener;
|
||||||
|
}
|
||||||
|
if (document.pasteListener) {
|
||||||
|
document.removeEventListener('paste', document.pasteListener);
|
||||||
|
delete document.pasteListener;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseData(schema, self) {
|
||||||
|
if (isJSExpression(schema)) {
|
||||||
|
return parseExpression(schema, self);
|
||||||
|
} else if (typeof schema === 'string') {
|
||||||
|
return schema.trim();
|
||||||
|
} else if (Array.isArray(schema)) {
|
||||||
|
return schema.map(item => parseData(item, self));
|
||||||
|
} else if (typeof schema === 'function') {
|
||||||
|
return schema.bind(self);
|
||||||
|
} else if (typeof schema === 'object') {
|
||||||
|
// 对于undefined及null直接返回
|
||||||
|
if (!schema) return schema;
|
||||||
|
const res = {};
|
||||||
|
forEach(schema, (val, key) => {
|
||||||
|
if (key.startsWith('__')) return;
|
||||||
|
res[key] = parseData(val, self);
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*全匹配{{开头,}}结尾的变量表达式,或者对象类型JSExpression,且均不支持省略this */
|
||||||
|
export function parseExpression(str, self) {
|
||||||
|
try {
|
||||||
|
const contextArr = ['"use strict";', 'var __self = arguments[0];'];
|
||||||
|
contextArr.push('return ');
|
||||||
|
let tarStr;
|
||||||
|
//向前兼容,支持标准协议新格式
|
||||||
|
if (typeof str === 'string') {
|
||||||
|
const regRes = str.trim().match(EXPRESSION_REG);
|
||||||
|
tarStr = regRes[1];
|
||||||
|
} else {
|
||||||
|
tarStr = (str.value || '').trim();
|
||||||
|
}
|
||||||
|
tarStr = tarStr.replace(/this(\W|$)/g, (a, b) => `__self${b}`);
|
||||||
|
tarStr = contextArr.join('\n') + tarStr;
|
||||||
|
//默认调用顶层窗口的parseObj,保障new Function的window对象是顶层的window对象
|
||||||
|
if (inSameDomain() && window.parent.__newFunc) {
|
||||||
|
return window.parent.__newFunc(tarStr)(self);
|
||||||
|
}
|
||||||
|
return new Function(tarStr)(self);
|
||||||
|
} catch (err) {
|
||||||
|
debug('parseExpression.error', err, str, self);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断组件配置中是否有reactNode且type为function的props
|
||||||
|
* @param {*} componentInfo
|
||||||
|
*/
|
||||||
|
export function hasReactNodeFuncProps(componentInfo) {
|
||||||
|
const isReactNodeFuncProps = config => {
|
||||||
|
if (config.type === 'ReactNode') {
|
||||||
|
return config.props && config.props.type === 'function';
|
||||||
|
} else if (config.type === 'Mixin') {
|
||||||
|
return config.props && config.props.reactNodeProps && config.props.reactNodeProps.type === 'function';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return componentInfo && (componentInfo.props || []).some(item => isReactNodeFuncProps(item));
|
||||||
|
}
|
||||||
171
packages/rax-render/src/utils/request.js
Normal file
171
packages/rax-render/src/utils/request.js
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
import 'whatwg-fetch';
|
||||||
|
import fetchMtop from '@ali/lib-mtop';
|
||||||
|
import fetchJsonp from 'fetch-jsonp';
|
||||||
|
import bzbRequest from '@ali/bzb-request';
|
||||||
|
import { serialize, buildUrl, parseUrl } from '@ali/b3-one/lib/url';
|
||||||
|
|
||||||
|
export function get(dataAPI, params = {}, headers = {}, otherProps = {}) {
|
||||||
|
headers = {
|
||||||
|
Accept: 'application/json',
|
||||||
|
...headers
|
||||||
|
};
|
||||||
|
dataAPI = buildUrl(dataAPI, params);
|
||||||
|
return request(dataAPI, 'GET', null, headers, otherProps);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function post(dataAPI, params = {}, headers = {}, otherProps = {}) {
|
||||||
|
headers = {
|
||||||
|
Accept: 'application/json',
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
...headers
|
||||||
|
};
|
||||||
|
return request(
|
||||||
|
dataAPI,
|
||||||
|
'POST',
|
||||||
|
headers['Content-Type'].indexOf('application/json') > -1 || Array.isArray(params)
|
||||||
|
? JSON.stringify(params)
|
||||||
|
: serialize(params),
|
||||||
|
headers,
|
||||||
|
otherProps
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function request(dataAPI, method = 'GET', data, headers = {}, otherProps = {}) {
|
||||||
|
switch (method) {
|
||||||
|
case 'PUT':
|
||||||
|
case 'DELETE':
|
||||||
|
headers = {
|
||||||
|
Accept: 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
...headers
|
||||||
|
};
|
||||||
|
data = JSON.stringify(data || {});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (otherProps.timeout) {
|
||||||
|
setTimeout(() => {
|
||||||
|
reject(new Error('timeout'));
|
||||||
|
}, otherProps.timeout);
|
||||||
|
}
|
||||||
|
fetch(dataAPI, {
|
||||||
|
method,
|
||||||
|
credentials: 'include',
|
||||||
|
headers,
|
||||||
|
body: data,
|
||||||
|
...otherProps
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
switch (response.status) {
|
||||||
|
case 200:
|
||||||
|
case 201:
|
||||||
|
case 202:
|
||||||
|
return response.json();
|
||||||
|
case 204:
|
||||||
|
if (method === 'DELETE') {
|
||||||
|
return {
|
||||||
|
success: true
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
__success: false,
|
||||||
|
code: response.status
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case 400:
|
||||||
|
case 401:
|
||||||
|
case 403:
|
||||||
|
case 404:
|
||||||
|
case 406:
|
||||||
|
case 410:
|
||||||
|
case 422:
|
||||||
|
case 500:
|
||||||
|
return response
|
||||||
|
.json()
|
||||||
|
.then(res => {
|
||||||
|
return {
|
||||||
|
__success: false,
|
||||||
|
code: response.status,
|
||||||
|
data: res
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
return {
|
||||||
|
__success: false,
|
||||||
|
code: response.status
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
.then(json => {
|
||||||
|
if (json && json.__success !== false) {
|
||||||
|
resolve(json);
|
||||||
|
} else {
|
||||||
|
delete json.__success;
|
||||||
|
reject(json);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function jsonp(dataAPI, params = {}, otherProps = {}) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
otherProps = {
|
||||||
|
timeout: 5000,
|
||||||
|
...otherProps
|
||||||
|
};
|
||||||
|
fetchJsonp(buildUrl(dataAPI, params), otherProps)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(json => {
|
||||||
|
if (json) {
|
||||||
|
resolve(json);
|
||||||
|
} else {
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mtop(dataAPI, params, otherProps = {}) {
|
||||||
|
fetchMtop.config.subDomain = otherProps.subDomain || 'm';
|
||||||
|
return fetchMtop.request({
|
||||||
|
api: dataAPI,
|
||||||
|
v: '1.0',
|
||||||
|
data: params,
|
||||||
|
ecode: otherProps.ecode || 0,
|
||||||
|
type: otherProps.method || 'GET',
|
||||||
|
dataType: otherProps.dataType || 'jsonp',
|
||||||
|
AntiFlood: true, // 防刷
|
||||||
|
timeout: otherProps.timeout || 20000
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bzb(apiCode, params, otherProps = {}) {
|
||||||
|
// 通过url参数设置小二工作台请求环境
|
||||||
|
const getUrlEnv = () => {
|
||||||
|
try {
|
||||||
|
if (window.parent && window.parent.location.host === window.location.host) {
|
||||||
|
const urlInfo = parseUrl(window.parent && window.parent.location.href);
|
||||||
|
return urlInfo && urlInfo.params && urlInfo.params._env;
|
||||||
|
}
|
||||||
|
const urlInfo = parseUrl(window.location.href);
|
||||||
|
return urlInfo && urlInfo.params && urlInfo.params._env;
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
otherProps.method = otherProps.method || 'GET';
|
||||||
|
otherProps.env = getUrlEnv() || otherProps.env || 'prod';
|
||||||
|
return bzbRequest(apiCode, {
|
||||||
|
data: params,
|
||||||
|
...otherProps
|
||||||
|
});
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user