@ -0,0 +1,44 @@ |
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const workerCmd = require('./worker/cli.worker'); |
||||||
|
|
||||||
|
function getArgs (startIndex = 1) { |
||||||
|
const args = {}; |
||||||
|
process.argv |
||||||
|
.slice(startIndex, process.argv.length) |
||||||
|
.forEach(arg => { |
||||||
|
// long arg
|
||||||
|
if (arg.slice(0, 2) === '--') { |
||||||
|
const longArg = arg.split('='); |
||||||
|
const longArgFlag = longArg[0].slice(2, longArg[0].length); |
||||||
|
const longArgValue = longArg.length > 1 ? longArg[1] : true; |
||||||
|
args[longArgFlag] = longArgValue; |
||||||
|
// flags
|
||||||
|
} else if (arg[0] === '-') { |
||||||
|
const flags = arg.slice(1, arg.length); |
||||||
|
args[flags] = true; |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
return args; |
||||||
|
} |
||||||
|
|
||||||
|
const cmds = new Map([ |
||||||
|
['worker', workerCmd], |
||||||
|
]); |
||||||
|
|
||||||
|
const baseCmd = 'fui-cli'; |
||||||
|
|
||||||
|
const startIndex = process.argv.findIndex(argv => argv.indexOf(baseCmd) !== -1); |
||||||
|
|
||||||
|
if (startIndex === -1) { |
||||||
|
throw new Error(`Command ${baseCmd} not found in args`); |
||||||
|
} |
||||||
|
|
||||||
|
const cmd = process.argv[startIndex + 1]; |
||||||
|
|
||||||
|
if (cmds.has(cmd)) { |
||||||
|
cmds.get(cmd)?.exec(getArgs(startIndex + 2)); |
||||||
|
} else { |
||||||
|
throw new Error(`Command ${cmd} not supported`); |
||||||
|
} |
@ -0,0 +1,76 @@ |
|||||||
|
const fs = require('fs'); |
||||||
|
const path = require('path'); |
||||||
|
|
||||||
|
function first2UpperCase(str) { |
||||||
|
return str.toLowerCase().replace(/( |^)[a-z]/g, L => L.toUpperCase()); |
||||||
|
} |
||||||
|
|
||||||
|
function scanAndCreate(structure, workerName, root = process.env.INIT_CWD) { |
||||||
|
Object.keys(structure) |
||||||
|
.forEach(name => { |
||||||
|
if (typeof structure[name] === 'object') { |
||||||
|
fs.mkdirSync(path.resolve(root, name)); |
||||||
|
|
||||||
|
scanAndCreate(structure[name], workerName, path.resolve(root, `./${name}`)); |
||||||
|
} else if (structure[name] === '') { |
||||||
|
fs.appendFileSync(path.resolve(root, name), ''); |
||||||
|
} else if (typeof structure[name] === 'string') { |
||||||
|
let content = fs.readFileSync(structure[name]).toString(); |
||||||
|
|
||||||
|
content = content |
||||||
|
.replace(/\${WorkerName}/g, first2UpperCase(workerName)) |
||||||
|
.replace(/\${workerName}/g, workerName); |
||||||
|
|
||||||
|
fs.appendFileSync(path.resolve(root, name), content); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
exec: async args => { |
||||||
|
if (!args.init) { |
||||||
|
throw new Error(`Command init not found in args`); |
||||||
|
} |
||||||
|
|
||||||
|
if (!args.name) { |
||||||
|
throw new Error('Command --name=... not found in args'); |
||||||
|
} |
||||||
|
|
||||||
|
const name = args.name; |
||||||
|
|
||||||
|
const structure = { |
||||||
|
[`${name}_worker`]: { |
||||||
|
'main_thread': { |
||||||
|
action: { |
||||||
|
'action.worker_ability_test.ts': path.resolve(__dirname, './template/main_thread/action/action.worker_ability_test.t'), |
||||||
|
}, |
||||||
|
[`${name}_main_thread.ts`]: path.resolve(__dirname, './template/main_thread/main_thread.t'), |
||||||
|
}, |
||||||
|
utils: { |
||||||
|
'action_type.ts': path.resolve(__dirname, './template/utils/action_type.t'), |
||||||
|
'payload_type.ts': path.resolve(__dirname, './template/utils/payload_type.t'), |
||||||
|
}, |
||||||
|
'worker_thread': { |
||||||
|
action: { |
||||||
|
'action.worker_ability_test.ts': path.resolve(__dirname, './template/worker_thread/action/action.worker_ability_test.t'), |
||||||
|
}, |
||||||
|
[`${name}_worker_thread.ts`]: path.resolve(__dirname, './template/worker_thread/worker_thread.t'), |
||||||
|
}, |
||||||
|
[`${name}_main_thread.helper.ts`]: path.resolve(__dirname, './template/main_thread.helper.t'), |
||||||
|
}, |
||||||
|
}; |
||||||
|
|
||||||
|
scanAndCreate(structure, name); |
||||||
|
}, |
||||||
|
}; |
||||||
|
|
||||||
|
// 结构
|
||||||
|
// -xxx_worker
|
||||||
|
// -|--main_thread
|
||||||
|
// -|--|--action
|
||||||
|
// -|--|--xxx_main_thread.ts
|
||||||
|
// -|--utils
|
||||||
|
// -|--|--action_type.ts
|
||||||
|
// -|--worker_thread
|
||||||
|
// -|--|--action
|
||||||
|
// -|--|--worker_main_thread.ts
|
@ -0,0 +1,45 @@ |
|||||||
|
import { ${WorkerName}MainThreadWorker } from './main_thread/${workerName}_main_thread'; |
||||||
|
// 不需要一起打包的话则不需要引入这行 |
||||||
|
import { workerUrl } from 'fui-worker!./worker_thread/${workerName}_worker_thread'; |
||||||
|
|
||||||
|
export class ${WorkerName}WorkerHelper { |
||||||
|
private worker: ${WorkerName}MainThreadWorker; |
||||||
|
|
||||||
|
/** |
||||||
|
* 拿到helper中的worker |
||||||
|
*/ |
||||||
|
public getWorker() { |
||||||
|
if (this.worker) { |
||||||
|
return this.worker; |
||||||
|
} |
||||||
|
|
||||||
|
this.worker = BI.Workers.createWorker(${WorkerName}MainThreadWorker, { |
||||||
|
workerUrl: this.urlFormatter(workerUrl), |
||||||
|
workerName: BI.UUID(), |
||||||
|
}); |
||||||
|
|
||||||
|
return this.worker; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 格式化worker url,比如补充一些环境信息到参数里 |
||||||
|
* @param url worker url |
||||||
|
*/ |
||||||
|
private urlFormatter(url: string) { |
||||||
|
return url; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 终止worker |
||||||
|
*/ |
||||||
|
public terminate() { |
||||||
|
this.worker?.terminate(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 使用示例 |
||||||
|
// const workerHelper = new ${WorkerName}WorkerHelper(); |
||||||
|
|
||||||
|
// workerHelper.getWorker() |
||||||
|
// .testCommunication() |
||||||
|
// .then(res => console.log(res)); |
@ -0,0 +1,13 @@ |
|||||||
|
import { WorkerAbilityTestActionType } from '../../utils/action_type'; |
||||||
|
import { WorkerAbilityTestPayload, WorkerAbilityTestReponse } from '../../utils/payload_type'; |
||||||
|
|
||||||
|
export class WorkerAbilityTestMainThreadAction extends BI.Workers.WorkerBaseAction { |
||||||
|
/** |
||||||
|
* 通信能力检测 |
||||||
|
*/ |
||||||
|
public communicationTest(): Promise<WorkerAbilityTestReponse['CommunicationTest']> { |
||||||
|
const mainThreadPostTime: WorkerAbilityTestPayload['CommunicationTest'] = Date.now(); |
||||||
|
|
||||||
|
return this.controller.requestPromise(WorkerAbilityTestActionType.CommunicationTest, mainThreadPostTime); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
import { WorkerAbilityTestMainThreadAction } from './action/action.worker_ability_test'; |
||||||
|
|
||||||
|
export class ${WorkerName}MainThreadWorker extends BI.Workers.MainThreadWorker { |
||||||
|
private communicationTest: WorkerAbilityTestMainThreadAction; |
||||||
|
|
||||||
|
public initActions(): void { |
||||||
|
this.communicationTest = this.createAction(WorkerAbilityTestMainThreadAction); |
||||||
|
} |
||||||
|
|
||||||
|
public testCommunication() { |
||||||
|
return this.communicationTest.communicationTest(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,8 @@ |
|||||||
|
/* |
||||||
|
* Worker 事务标识 |
||||||
|
* 每类事务有命名空间, 包含多个具体事务 |
||||||
|
*/ |
||||||
|
|
||||||
|
export const enum WorkerAbilityTestActionType { |
||||||
|
CommunicationTest = 'CommunicationTest', |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
/** |
||||||
|
* 跨线程通信各事务的发送数据类型声明 |
||||||
|
*/ |
||||||
|
export interface WorkerAbilityTestPayload { |
||||||
|
CommunicationTest: number; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 跨线程通信各事务的响应数据类型声明 |
||||||
|
*/ |
||||||
|
export interface WorkerAbilityTestReponse { |
||||||
|
CommunicationTest: number; |
||||||
|
} |
@ -0,0 +1,24 @@ |
|||||||
|
import { WorkerAbilityTestActionType } from '../../utils/action_type'; |
||||||
|
import { WorkerAbilityTestPayload, WorkerAbilityTestReponse } from '../../utils/payload_type'; |
||||||
|
|
||||||
|
export class WorkerAbilityTestWorkerThreadAction extends BI.Workers.WorkerBaseAction { |
||||||
|
protected addActionHandler(): void { |
||||||
|
this.controller.addActionHandler( |
||||||
|
WorkerAbilityTestActionType.CommunicationTest, |
||||||
|
this.communicationTest.bind(this) |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 通信能力检测的处理器 |
||||||
|
*/ |
||||||
|
private communicationTest( |
||||||
|
payload: WorkerAbilityTestPayload['CommunicationTest'] |
||||||
|
): WorkerAbilityTestReponse['CommunicationTest'] { |
||||||
|
const mainThreadPostTime = payload; |
||||||
|
// 收到主线程信息的耗时 |
||||||
|
const workerGetMessageDuration = Date.now() - mainThreadPostTime; |
||||||
|
|
||||||
|
return workerGetMessageDuration; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
// TODO: 这边需要先import fineui资源 |
||||||
|
import { WorkerAbilityTestWorkerThreadAction } from './action/action.worker_ability_test'; |
||||||
|
|
||||||
|
class ${WorkerName}WorkerTreadWorker extends BI.Workers.WorkerThreadWorker { |
||||||
|
public communicationTest: WorkerAbilityTestWorkerThreadAction; |
||||||
|
|
||||||
|
public initActions(): void { |
||||||
|
this.communicationTest = this.createAction(WorkerAbilityTestWorkerThreadAction); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export const ${workerName}WorkerTreadWorker = BI.Workers.createWorker(${WorkerName}WorkerTreadWorker); |
Before Width: | Height: | Size: 371 B After Width: | Height: | Size: 394 B |
Before Width: | Height: | Size: 454 B After Width: | Height: | Size: 473 B |
Before Width: | Height: | Size: 494 B After Width: | Height: | Size: 509 B |
Before Width: | Height: | Size: 462 B After Width: | Height: | Size: 476 B |
Before Width: | Height: | Size: 417 B After Width: | Height: | Size: 434 B |
Before Width: | Height: | Size: 308 B After Width: | Height: | Size: 330 B |
Before Width: | Height: | Size: 393 B After Width: | Height: | Size: 409 B |
Before Width: | Height: | Size: 431 B After Width: | Height: | Size: 466 B |
Before Width: | Height: | Size: 401 B After Width: | Height: | Size: 415 B |
Before Width: | Height: | Size: 352 B After Width: | Height: | Size: 376 B |
Before Width: | Height: | Size: 178 B After Width: | Height: | Size: 216 B |
Before Width: | Height: | Size: 217 B After Width: | Height: | Size: 233 B |
Before Width: | Height: | Size: 255 B After Width: | Height: | Size: 255 B |
Before Width: | Height: | Size: 215 B After Width: | Height: | Size: 215 B |
Before Width: | Height: | Size: 429 B After Width: | Height: | Size: 495 B |
Before Width: | Height: | Size: 505 B After Width: | Height: | Size: 581 B |
Before Width: | Height: | Size: 547 B After Width: | Height: | Size: 619 B |
Before Width: | Height: | Size: 515 B After Width: | Height: | Size: 580 B |
Before Width: | Height: | Size: 468 B After Width: | Height: | Size: 538 B |
Before Width: | Height: | Size: 336 B After Width: | Height: | Size: 392 B |
Before Width: | Height: | Size: 419 B After Width: | Height: | Size: 476 B |
Before Width: | Height: | Size: 458 B After Width: | Height: | Size: 513 B |
Before Width: | Height: | Size: 429 B After Width: | Height: | Size: 477 B |
Before Width: | Height: | Size: 381 B After Width: | Height: | Size: 434 B |
Before Width: | Height: | Size: 217 B After Width: | Height: | Size: 233 B |
Before Width: | Height: | Size: 255 B After Width: | Height: | Size: 255 B |
Before Width: | Height: | Size: 215 B After Width: | Height: | Size: 215 B |
Before Width: | Height: | Size: 117 B After Width: | Height: | Size: 216 B |
@ -0,0 +1,15 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html lang="en"> |
||||||
|
<head> |
||||||
|
<meta charset="UTF-8"> |
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
||||||
|
<title>Document</title> |
||||||
|
<link rel="stylesheet" type="text/css" href="http://fanruan.design/fineui/2.0/fineui.min.css" /> |
||||||
|
<script src="http://fanruan.design/fineui/2.0/fineui.min.js"></script> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<div id="wrapper"></div> |
||||||
|
<script src="./worker_new/index.js"></script> |
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,105 @@ |
|||||||
|
document.cookie = "test=demo"; |
||||||
|
|
||||||
|
// worker获取主线程资源
|
||||||
|
var CookieAction = BI.inherit(BI.Workers.WorkerBaseAction, { |
||||||
|
addActionHandler: function() { |
||||||
|
this.controller.addActionHandler("Cookie", this.getCookie.bind(this)); |
||||||
|
}, |
||||||
|
|
||||||
|
getCookie: function() { |
||||||
|
return document.cookie; |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
// 调用worker计算
|
||||||
|
var FibonacciAction = BI.inherit(BI.Workers.WorkerBaseAction, { |
||||||
|
addActionHandler: function() {}, |
||||||
|
|
||||||
|
getResult: function(times) { |
||||||
|
return this.controller.requestPromise("Fibonacci", { times: times }) |
||||||
|
.then(function(v) { |
||||||
|
console.log(v); |
||||||
|
}); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
// 主线程与worker多次交互
|
||||||
|
const HeartBeatCheckAction = BI.inherit(BI.Workers.WorkerBaseAction, { |
||||||
|
addActionHandler: function() { |
||||||
|
this.controller.addActionHandler("HeartBeatChecked", this.recieveHeartBeatChecked.bind(this)); |
||||||
|
}, |
||||||
|
|
||||||
|
recieveHeartBeatChecked: function (payload) { |
||||||
|
console.log("heartbeat: " + payload.time); |
||||||
|
}, |
||||||
|
|
||||||
|
startHeatBeatCheck: function() { |
||||||
|
return this.controller.request("HeartBeatCheckStart"); |
||||||
|
}, |
||||||
|
|
||||||
|
stopHeatBeatCheck: function() { |
||||||
|
return this.controller.request("HeartBeatCheckStop"); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
var MainThreadWorker = BI.inherit(BI.Workers.MainThreadWorker, { |
||||||
|
initActions: function() { |
||||||
|
this.cookieAction = this.createAction(CookieAction); |
||||||
|
|
||||||
|
this.fibonacciAction = this.createAction(FibonacciAction); |
||||||
|
|
||||||
|
this.heartBeatCheckAction = this.createAction(HeartBeatCheckAction); |
||||||
|
}, |
||||||
|
|
||||||
|
calculateFibonacci: function(times) { |
||||||
|
this.fibonacciAction.getResult(times); |
||||||
|
}, |
||||||
|
|
||||||
|
startHeatBeatCheck: function() { |
||||||
|
this.heartBeatCheckAction.startHeatBeatCheck(); |
||||||
|
}, |
||||||
|
|
||||||
|
stopHeatBeatCheck: function() { |
||||||
|
this.heartBeatCheckAction.stopHeatBeatCheck(); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
var mainThreadWorker = BI.Workers.createWorker(MainThreadWorker, { |
||||||
|
workerUrl: "./worker_new/worker.js", |
||||||
|
workerName: "demo" |
||||||
|
}); |
||||||
|
|
||||||
|
BI.createWidget({ |
||||||
|
type: "bi.vertical", |
||||||
|
element: "#wrapper", |
||||||
|
vgap: 10, |
||||||
|
hgap: 10, |
||||||
|
items: [ |
||||||
|
{ |
||||||
|
type: "bi.button", |
||||||
|
text: "点击计算斐波那契数列第40项", |
||||||
|
width: 200, |
||||||
|
handler: function() { |
||||||
|
console.log("click"); |
||||||
|
|
||||||
|
mainThreadWorker.calculateFibonacci(40); |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
type: "bi.button", |
||||||
|
text: "开始心跳", |
||||||
|
width: 200, |
||||||
|
handler: function() { |
||||||
|
mainThreadWorker.startHeatBeatCheck(); |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
type: "bi.button", |
||||||
|
text: "停止心跳", |
||||||
|
width: 200, |
||||||
|
handler: function() { |
||||||
|
mainThreadWorker.stopHeatBeatCheck(); |
||||||
|
} |
||||||
|
} |
||||||
|
] |
||||||
|
}); |
@ -0,0 +1,80 @@ |
|||||||
|
self.importScripts("https://fanruan.design/fineui/fineui_without_jquery_polyfill.js"); |
||||||
|
|
||||||
|
var CookieAction = BI.inherit(BI.Workers.WorkerBaseAction, { |
||||||
|
addActionHandler: function() {}, |
||||||
|
|
||||||
|
getCookie: function() { |
||||||
|
return this.controller.requestPromise("Cookie"); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
function fibonacci(n) { |
||||||
|
if (n === 1 || n === 2) { |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
return fibonacci(n - 2) + fibonacci(n - 1); |
||||||
|
} |
||||||
|
|
||||||
|
var FibonacciAction = BI.inherit(BI.Workers.WorkerBaseAction, { |
||||||
|
addActionHandler: function() { |
||||||
|
this.controller.addActionHandler("Fibonacci", this.getResult.bind(this)); |
||||||
|
}, |
||||||
|
|
||||||
|
getResult: function(payload) { |
||||||
|
return fibonacci(payload.times); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
const HeartBeatCheckAction = BI.inherit(BI.Workers.WorkerBaseAction, { |
||||||
|
addActionHandler: function() { |
||||||
|
this.controller.addActionHandler("HeartBeatCheckStart", this.startHeatBeatCheck.bind(this)); |
||||||
|
this.controller.addActionHandler("HeartBeatCheckStop", this.stopHeatBeatCheck.bind(this)); |
||||||
|
}, |
||||||
|
|
||||||
|
startHeatBeatCheck: function() { |
||||||
|
var self = this; |
||||||
|
|
||||||
|
if (!this.timer) { |
||||||
|
console.log("heart beat check started"); |
||||||
|
|
||||||
|
this.timer = setInterval(function() { |
||||||
|
// 模拟请求
|
||||||
|
setTimeout(function() { |
||||||
|
self.controller.request("HeartBeatChecked", { |
||||||
|
time: new Date() |
||||||
|
}); |
||||||
|
}, 50); |
||||||
|
}, 5 * 1000); |
||||||
|
} else { |
||||||
|
console.log("heart beat has already started!"); |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
stopHeatBeatCheck: function() { |
||||||
|
console.log("heart beat check stopped"); |
||||||
|
|
||||||
|
clearInterval(this.timer); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
var MainThreadWorker = BI.inherit(BI.Workers.WorkerThreadWorker, { |
||||||
|
initActions: function() { |
||||||
|
this.cookieAction = this.createAction(CookieAction); |
||||||
|
|
||||||
|
this.fibonacciAction = this.createAction(FibonacciAction); |
||||||
|
|
||||||
|
this.heartBeatCheckAction = this.createAction(HeartBeatCheckAction); |
||||||
|
}, |
||||||
|
|
||||||
|
fetchCookie: function() { |
||||||
|
return this.cookieAction.getCookie() |
||||||
|
.then(function (v) { |
||||||
|
console.log(v); |
||||||
|
}); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
var workerThreadWorker = BI.Workers.createWorker(MainThreadWorker); |
||||||
|
|
||||||
|
workerThreadWorker.fetchCookie(); |
@ -0,0 +1,104 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html lang="en"> |
||||||
|
|
||||||
|
<head> |
||||||
|
<meta charset="UTF-8"> |
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
||||||
|
<title>Document</title> |
||||||
|
<link rel="stylesheet" type="text/css" href="https://fanruan.design/fineui/2.0/fineui_without_normalize.css" /> |
||||||
|
<!-- <script src="/fineui.js"></script> --> |
||||||
|
<script src="https://fanruan.design/fineui/2.0/fineui.js"></script> |
||||||
|
</head> |
||||||
|
|
||||||
|
<body> |
||||||
|
<div id="wrapper"></div> |
||||||
|
<script> |
||||||
|
var LoadingPane = BI.inherit(BI.Pane, {}); |
||||||
|
|
||||||
|
BI.shortcut("demo.loading_pane", LoadingPane); |
||||||
|
|
||||||
|
var loadingPane; |
||||||
|
|
||||||
|
BI.createWidget({ |
||||||
|
type: "bi.vertical", |
||||||
|
element: "#wrapper", |
||||||
|
items: [{ |
||||||
|
type: "bi.vertical", |
||||||
|
items: [{ |
||||||
|
type: "demo.loading_pane", |
||||||
|
width: 800, |
||||||
|
height: 600, |
||||||
|
cls: "bi-border", |
||||||
|
ref: function(ref) { |
||||||
|
loadingPane = ref; |
||||||
|
}, |
||||||
|
}, { |
||||||
|
type: "bi.left", |
||||||
|
rgap: 10, |
||||||
|
items: [{ |
||||||
|
type: "bi.button", |
||||||
|
text: "开始loading", |
||||||
|
handler: function () { |
||||||
|
loadingPane.loading(); |
||||||
|
}, |
||||||
|
}, { |
||||||
|
type: "bi.button", |
||||||
|
text: "停止loading", |
||||||
|
handler: function () { |
||||||
|
loadingPane.loaded(); |
||||||
|
}, |
||||||
|
}, { |
||||||
|
type: "bi.button", |
||||||
|
text: "设置文字loading", |
||||||
|
handler: function () { |
||||||
|
BI.config("bi.provider.system", function (provider) { |
||||||
|
provider.setLoadingCreator(function () { |
||||||
|
return { |
||||||
|
type: "bi.label", |
||||||
|
text: "我是被替换了的loading" |
||||||
|
}; |
||||||
|
}); |
||||||
|
}); |
||||||
|
}, |
||||||
|
}, { |
||||||
|
type: "bi.button", |
||||||
|
text: "恢复波浪线loading", |
||||||
|
handler: function () { |
||||||
|
BI.config("bi.provider.system", function (provider) { |
||||||
|
provider.setLoadingCreator(function () { |
||||||
|
return { |
||||||
|
type: "bi.horizontal", |
||||||
|
cls: "bi-loading-widget", |
||||||
|
height: 30, |
||||||
|
width: 30, |
||||||
|
hgap: 5, |
||||||
|
vgap: 2.5, |
||||||
|
items: [{ |
||||||
|
type: "bi.layout", |
||||||
|
cls: "animate-rect rect1", |
||||||
|
height: 25, |
||||||
|
width: 2.5 |
||||||
|
}, { |
||||||
|
type: "bi.layout", |
||||||
|
cls: "animate-rect rect2", |
||||||
|
height: 25, |
||||||
|
width: 2.5 |
||||||
|
}, { |
||||||
|
type: "bi.layout", |
||||||
|
cls: "animate-rect rect3", |
||||||
|
height: 25, |
||||||
|
width: 2.5 |
||||||
|
}] |
||||||
|
}; |
||||||
|
}); |
||||||
|
}); |
||||||
|
}, |
||||||
|
}] |
||||||
|
}], |
||||||
|
}], |
||||||
|
}); |
||||||
|
</script> |
||||||
|
</body> |
||||||
|
|
||||||
|
</html> |
@ -0,0 +1,9 @@ |
|||||||
|
const WorkerPluginName = 'FuiWorkerPlugin'; |
||||||
|
const WorkerLoaderName = 'FuiWorkerWorkerLoader'; |
||||||
|
const FileNamePrefix = 'worker-'; |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
WorkerPluginName, |
||||||
|
WorkerLoaderName, |
||||||
|
FileNamePrefix, |
||||||
|
}; |
@ -0,0 +1,45 @@ |
|||||||
|
/* |
||||||
|
* worker-plugin |
||||||
|
*/ |
||||||
|
|
||||||
|
const path = require('path'); |
||||||
|
const webpack = require('webpack'); |
||||||
|
const { WorkerPluginName } = require('./constants'); |
||||||
|
|
||||||
|
class FuiWorkerPlugin { |
||||||
|
constructor(options = {}) { |
||||||
|
this.options = options; |
||||||
|
} |
||||||
|
|
||||||
|
apply(compiler) { |
||||||
|
// 为主线程构建添加 __WORKER__ 环境变量, 构建中区分不同线程源码, 实现代码拆减
|
||||||
|
compiler.hooks.afterPlugins.tap(WorkerPluginName, compiler => { |
||||||
|
new webpack.DefinePlugin({ |
||||||
|
// __WORKER__ 表示当前所在线程是否是 worker 线程
|
||||||
|
// 主线程构建中为 false
|
||||||
|
__WORKER__: false, |
||||||
|
}).apply(compiler); |
||||||
|
}); |
||||||
|
|
||||||
|
// 添加自定义的worker entry-loader
|
||||||
|
compiler.hooks.afterResolvers.tap(WorkerPluginName, compiler => { |
||||||
|
/** |
||||||
|
* https://webpack.js.org/configuration/resolve/#resolveloader
|
||||||
|
* 使用 resolveloader 添加自定义的 worker loader |
||||||
|
*/ |
||||||
|
if (!compiler.options.resolveLoader) { |
||||||
|
compiler.options.resolveLoader = { |
||||||
|
alias: {}, |
||||||
|
}; |
||||||
|
} |
||||||
|
if (!compiler.options.resolveLoader.alias) { |
||||||
|
compiler.options.resolveLoader.alias = {}; |
||||||
|
} |
||||||
|
|
||||||
|
// 动态添加 worker 的 worker-loader, 命名为 "fui-worker"
|
||||||
|
compiler.options.resolveLoader.alias['fui-worker'] = path.resolve(__dirname, './worker-loader.js'); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = FuiWorkerPlugin; |
@ -0,0 +1,109 @@ |
|||||||
|
/* |
||||||
|
* fui-worker worker-loader |
||||||
|
*/ |
||||||
|
|
||||||
|
const webpack = require('webpack'); |
||||||
|
const loaderUtils = require('loader-utils'); |
||||||
|
const SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin'); |
||||||
|
const { WorkerLoaderName, FileNamePrefix } = require('./constants'); |
||||||
|
|
||||||
|
// 正常 loader 处理逻辑
|
||||||
|
function loader() { |
||||||
|
const callback = this.async(); |
||||||
|
this.cacheable(false); |
||||||
|
|
||||||
|
// 过滤掉当前的 worker-loader, 保留 worker 侧构建需要的其他 loader(babel-loader/ts-loader 等)
|
||||||
|
const otherLoaders = this.loaders.filter((loader, index) => { |
||||||
|
if (index === this.loaderIndex) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
}); |
||||||
|
/** |
||||||
|
* 拼接构建需要的 loader 字符串, 用于指定 childCompiler 的构建 loader |
||||||
|
* 比如: /path/to/babel-loader/lib/index.js!/path/to/ts-loader/index.js! |
||||||
|
*/ |
||||||
|
const loaderPath = otherLoaders.reduce((pre, loader) => `${pre}${loader.path}!`, ''); |
||||||
|
|
||||||
|
/** |
||||||
|
* worker 独立构建的 entry |
||||||
|
* 构建 loader + worker 源码入口文件路径 |
||||||
|
* |
||||||
|
* https://webpack.js.org/concepts/loaders/#inline
|
||||||
|
* `!!` 实现在 childCompiler 中忽略其他所有 loader, 只保留主构建的 loader |
||||||
|
* 不然 worker 入口在 childCompiler 中会继续由 worker-loader 处理, 造成死循环 |
||||||
|
*/ |
||||||
|
const workerEntry = `!!${loaderPath}${this.resourcePath}`; |
||||||
|
|
||||||
|
// 把资源纳入构建流程的依赖, 实现 dev 模式下的 watch
|
||||||
|
this.addDependency(workerEntry); |
||||||
|
|
||||||
|
// 生成的 service 独立 bundle 名称
|
||||||
|
const entryFileName = `${FileNamePrefix}index`; |
||||||
|
|
||||||
|
// 获取传递给 loader 的 options
|
||||||
|
loaderUtils.getOptions(this) || {}; |
||||||
|
|
||||||
|
// 创建 childCompiler, 用于实现 worker 构建为独立 js 资源
|
||||||
|
const childCompiler = this._compilation.createChildCompiler(WorkerLoaderName, { |
||||||
|
globalObject: 'this', |
||||||
|
}); |
||||||
|
childCompiler.context = this._compiler.context; |
||||||
|
|
||||||
|
// 指定独立构建的 entry 和生成 js 资源名称
|
||||||
|
new SingleEntryPlugin(this.context, workerEntry, entryFileName).apply(childCompiler); |
||||||
|
|
||||||
|
// 设置 worker 侧的环境变量
|
||||||
|
new webpack.DefinePlugin({ |
||||||
|
__WORKER__: true, |
||||||
|
}).apply(childCompiler); |
||||||
|
|
||||||
|
// 添加 window 全局对象, 映射为 worker 线程全局对象 self
|
||||||
|
// 如果在 worker 源码中添加, 可能没有前置到所有引用模块前
|
||||||
|
new webpack.BannerPlugin({ |
||||||
|
banner: 'self.window = self;', |
||||||
|
raw: true, |
||||||
|
entryOnly: true, |
||||||
|
}).apply(childCompiler); |
||||||
|
|
||||||
|
const subCache = `subcache ${__dirname} ${workerEntry}`; |
||||||
|
childCompiler.hooks.compilation.tap(WorkerLoaderName, compilation => { |
||||||
|
if (compilation.cache) { |
||||||
|
if (!compilation.cache[subCache]) compilation.cache[subCache] = {}; |
||||||
|
compilation.cache = compilation.cache[subCache]; |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
childCompiler.runAsChild((error, entries, compilation) => { |
||||||
|
if (!error && compilation.errors && compilation.errors.length) { |
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
error = compilation.errors[0]; |
||||||
|
} |
||||||
|
|
||||||
|
// compatible with Array (v4) and Set (v5) prototypes
|
||||||
|
const entry = entries && entries[0] && entries[0].files.values().next().value; |
||||||
|
if (!error && !entry) { |
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
error = Error(`${WorkerLoaderName}, no entry for ${workerEntry}`); |
||||||
|
} |
||||||
|
|
||||||
|
if (error) { |
||||||
|
return callback(error); |
||||||
|
} |
||||||
|
|
||||||
|
return callback( |
||||||
|
null, |
||||||
|
// 插入代码的转译和压缩由主构建配置的 babel/ts loader 处理, 不需要 worker-worker 来处理
|
||||||
|
// 添加 @ts-nocheck 避免 ts-check 报错
|
||||||
|
`// @ts-nocheck
|
||||||
|
const servicePath = __webpack_public_path__ + ${JSON.stringify(entry)}; |
||||||
|
export const workerUrl = servicePath; |
||||||
|
` |
||||||
|
); |
||||||
|
}); |
||||||
|
|
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = loader; |
@ -1,7 +1,7 @@ |
|||||||
|
|
||||||
if (!window.$ && !window.jQuery) { |
if (!_global.$ && !_global.jQuery) { |
||||||
window.jQuery = window.$ = BI.jQuery; |
_global.jQuery = _global.$ = BI.jQuery; |
||||||
} |
} |
||||||
if (!window._) { |
if (!_global._) { |
||||||
window._ = BI._; |
_global._ = BI._; |
||||||
} |
} |
||||||
|
@ -0,0 +1,74 @@ |
|||||||
|
import { registFunction } from './plugins'; |
||||||
|
|
||||||
|
export function Element(widget, attribs) { |
||||||
|
this.l = this.r = this.t = this.b = 0; // 边框
|
||||||
|
this.marginLeft = this.marginRight = this.marginTop = this.marginBottom = 0; //间距
|
||||||
|
this.position = {}; |
||||||
|
this.classMap = {}; |
||||||
|
this.classList = []; |
||||||
|
this.children = []; |
||||||
|
this.attribs = attribs || {}; |
||||||
|
this.styles = {}; |
||||||
|
// 兼容处理
|
||||||
|
this['0'] = this; |
||||||
|
this.style = {}; |
||||||
|
if (!widget) { |
||||||
|
this.nodeName = 'body'; |
||||||
|
this.position.x = 0; |
||||||
|
this.position.y = 0; |
||||||
|
this.attribs.id = 'body'; |
||||||
|
} else if (BI.isWidget(widget)) { |
||||||
|
this.widget = widget; |
||||||
|
this.nodeName = widget.options.tagName; |
||||||
|
this.textBaseLine = widget.options.textBaseLine; |
||||||
|
} else if (BI.isString(widget)) { |
||||||
|
this.nodeName = widget; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
initElement(Element); |
||||||
|
registFunction(Element); |
||||||
|
|
||||||
|
function initElement(element) { |
||||||
|
element.prototype = { |
||||||
|
appendChild(child) { |
||||||
|
child.parent = this; |
||||||
|
if (this.children.push(child) !== 1) { |
||||||
|
var sibling = this.children[this.children.length - 2]; |
||||||
|
sibling.next = child; |
||||||
|
child.prev = sibling; |
||||||
|
child.next = null; |
||||||
|
} |
||||||
|
}, |
||||||
|
append(child) { |
||||||
|
child.parent = this; |
||||||
|
if (this.children.push(child) !== 1) { |
||||||
|
var sibling = this.children[this.children.length - 2]; |
||||||
|
sibling.next = child; |
||||||
|
child.prev = sibling; |
||||||
|
child.next = null; |
||||||
|
} |
||||||
|
}, |
||||||
|
getParent() { |
||||||
|
return this.parent; |
||||||
|
}, |
||||||
|
getSiblings() { |
||||||
|
var parent = this.getParent(); |
||||||
|
return parent ? parent.getChildren() : [this]; |
||||||
|
}, |
||||||
|
getChildren() { |
||||||
|
return this.children; |
||||||
|
}, |
||||||
|
|
||||||
|
getBounds() { |
||||||
|
return {}; |
||||||
|
}, |
||||||
|
|
||||||
|
width() { |
||||||
|
|
||||||
|
}, |
||||||
|
height() { |
||||||
|
|
||||||
|
} |
||||||
|
}; |
||||||
|
} |
@ -0,0 +1,31 @@ |
|||||||
|
import { Element } from './element'; |
||||||
|
|
||||||
|
BI.Element = Element; |
||||||
|
BI.Element.renderEngine = { |
||||||
|
createElement: (widget) => { |
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
if (BI.isWidget(widget)) { |
||||||
|
var o = widget.options; |
||||||
|
if (o.element instanceof Element) { |
||||||
|
return o.element; |
||||||
|
} |
||||||
|
if (typeof o.element === 'string' && o.element !== 'body') { |
||||||
|
o.root = false; |
||||||
|
return new Element(widget); |
||||||
|
} |
||||||
|
|
||||||
|
if (o.root === true) { |
||||||
|
return new Element(); |
||||||
|
} |
||||||
|
} |
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
if (BI.isString(widget)) { |
||||||
|
return new Element(widget); |
||||||
|
} |
||||||
|
return new Element(widget); |
||||||
|
}, |
||||||
|
|
||||||
|
createFragment() { |
||||||
|
return new Element(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,22 @@ |
|||||||
|
export const registAttrFun = (Element) => { |
||||||
|
Element.registerFunction('attr', function (key, value) { |
||||||
|
var self = this; |
||||||
|
if (BI.isObject(key)) { |
||||||
|
BI.each(key, (k, v) => { |
||||||
|
self.attr(k, v); |
||||||
|
}); |
||||||
|
return this; |
||||||
|
} |
||||||
|
if (BI.isNull(value)) { |
||||||
|
return this.attribs[key]; |
||||||
|
} |
||||||
|
this.attribs[key] = value; |
||||||
|
return this; |
||||||
|
}); |
||||||
|
Element.registerFunction('hasAttrib', function (key) { |
||||||
|
return this.attribs[key] != null; |
||||||
|
}); |
||||||
|
Element.registerFunction('removeAttr', function (key) { |
||||||
|
delete this.attribs[key]; |
||||||
|
}); |
||||||
|
}; |
@ -0,0 +1,23 @@ |
|||||||
|
export const registClassFun = (Element) => { |
||||||
|
Element.registerFunction('addClass', function (classList) { |
||||||
|
var self = this; |
||||||
|
BI.each(classList.split(' '), (i, cls) => { |
||||||
|
if (cls && !self.classMap[cls]) { |
||||||
|
self.classList.push(cls); |
||||||
|
} |
||||||
|
cls && (self.classMap[cls] = true); |
||||||
|
}); |
||||||
|
return this; |
||||||
|
}); |
||||||
|
|
||||||
|
Element.registerFunction('removeClass', function (classList) { |
||||||
|
var self = this; |
||||||
|
BI.each(classList.split(' '), (i, cls) => { |
||||||
|
if (cls && self.classMap[cls]) { |
||||||
|
delete self.classMap[cls]; |
||||||
|
self.classList.splice(self.classList.indexOf(cls), 1); |
||||||
|
} |
||||||
|
}); |
||||||
|
return this; |
||||||
|
}); |
||||||
|
}; |
@ -0,0 +1,22 @@ |
|||||||
|
export const registCssFun = (Element) => { |
||||||
|
Element.registerFunction('css', function (key, value) { |
||||||
|
var self = this; |
||||||
|
if (BI.isObject(key)) { |
||||||
|
BI.each(key, (k, v) => { |
||||||
|
self.css(k, v); |
||||||
|
}); |
||||||
|
return this; |
||||||
|
} |
||||||
|
key = BI.trim(BI.camelize(key)); |
||||||
|
return css(this, key, value); |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
const css = (elem, key, value) => { |
||||||
|
key = BI.trim(BI.camelize(key)); |
||||||
|
if (BI.isNull(value)) { |
||||||
|
return elem.styles[key]; |
||||||
|
} |
||||||
|
elem.styles[key] = value; |
||||||
|
return elem; |
||||||
|
}; |
@ -0,0 +1,12 @@ |
|||||||
|
export const registDataFun = (Element) => { |
||||||
|
Element.registerFunction('data', function (key, value) { |
||||||
|
if (!this._data) { |
||||||
|
this._data = {}; |
||||||
|
} |
||||||
|
if (BI.isNull(value)) { |
||||||
|
return this._data[key]; |
||||||
|
} |
||||||
|
this._data[key] = value; |
||||||
|
return this; |
||||||
|
}); |
||||||
|
}; |
@ -0,0 +1,9 @@ |
|||||||
|
export const registEmptyFun = (Element) => { |
||||||
|
Element.registerFunction('empty', function (text) { |
||||||
|
this.children = []; |
||||||
|
return this; |
||||||
|
}); |
||||||
|
Element.registerFunction('destroy', function (text) { |
||||||
|
return this; |
||||||
|
}); |
||||||
|
}; |
@ -0,0 +1,32 @@ |
|||||||
|
var returnThis = function () { |
||||||
|
return this; |
||||||
|
}; |
||||||
|
export const registEventFun = (Element) => { |
||||||
|
[ |
||||||
|
'mousedown', |
||||||
|
'mouseup', |
||||||
|
'mousewheel', |
||||||
|
'keydown', |
||||||
|
'keyup', |
||||||
|
'focus', |
||||||
|
'focusin', |
||||||
|
'focusout', |
||||||
|
'click', |
||||||
|
'on', |
||||||
|
'off', |
||||||
|
'bind', |
||||||
|
'unbind', |
||||||
|
'trigger', |
||||||
|
'hover', |
||||||
|
'scroll', |
||||||
|
'scrollLeft', |
||||||
|
'scrollTop', |
||||||
|
'resize', |
||||||
|
'show', |
||||||
|
'hide', |
||||||
|
'dblclick', |
||||||
|
'blur', |
||||||
|
].forEach((event) => { |
||||||
|
Element.registerFunction(event, returnThis); |
||||||
|
}); |
||||||
|
}; |
@ -0,0 +1,15 @@ |
|||||||
|
export const registHtmlFun = (Element) => { |
||||||
|
Element.registerFunction('html', function (text) { |
||||||
|
if (text && text.charAt(0) === '<') { |
||||||
|
BI.createWidget({ |
||||||
|
type: 'bi.html', |
||||||
|
element: this.widget, |
||||||
|
html: text, |
||||||
|
}); |
||||||
|
this.originalHtml = text; |
||||||
|
} else { |
||||||
|
this.text = BI.htmlDecode(text); |
||||||
|
} |
||||||
|
return this; |
||||||
|
}); |
||||||
|
}; |
@ -0,0 +1,31 @@ |
|||||||
|
import { registAttrFun } from './attr'; |
||||||
|
import { registClassFun } from './class'; |
||||||
|
import { registCssFun } from './css'; |
||||||
|
import { registDataFun } from './data'; |
||||||
|
import { registEmptyFun } from './empty'; |
||||||
|
import { registEventFun } from './event'; |
||||||
|
import { registHtmlFun } from './html'; |
||||||
|
import { registKeywordMarkFun } from './keywordMark'; |
||||||
|
import { registRenderToHtmlFun } from './renderToHtml'; |
||||||
|
import { registRenderToStringFun } from './renderToString'; |
||||||
|
import { registTextFun } from './text'; |
||||||
|
import { registValFun } from './val'; |
||||||
|
|
||||||
|
export const registFunction = (Element) => { |
||||||
|
var functionMap = {}; |
||||||
|
Element.registerFunction = (key, fn) => { |
||||||
|
Element.prototype[key] = functionMap[key] = fn; |
||||||
|
}; |
||||||
|
registAttrFun(Element); |
||||||
|
registClassFun(Element); |
||||||
|
registCssFun(Element); |
||||||
|
registDataFun(Element); |
||||||
|
registEmptyFun(Element); |
||||||
|
registEventFun(Element); |
||||||
|
registHtmlFun(Element); |
||||||
|
registKeywordMarkFun(Element); |
||||||
|
registRenderToStringFun(Element); |
||||||
|
registRenderToHtmlFun(Element); |
||||||
|
registTextFun(Element); |
||||||
|
registValFun(Element); |
||||||
|
}; |
@ -0,0 +1,6 @@ |
|||||||
|
export const registKeywordMarkFun = (Element) => { |
||||||
|
Element.registerFunction('__textKeywordMarked__', function (text) { |
||||||
|
this[0].textContent = text; |
||||||
|
return this; |
||||||
|
}); |
||||||
|
}; |
@ -0,0 +1,65 @@ |
|||||||
|
var skipArray = []; |
||||||
|
var pxStyle = ['font-size', 'width', 'height']; |
||||||
|
var _renderToHtml = function (root) { |
||||||
|
var str = ''; |
||||||
|
if (BI.isNull(root.originalHtml)) { |
||||||
|
if (root.tag !== 'body') { |
||||||
|
str += `<${root.tag}`; |
||||||
|
if (root.classList.length > 0) { |
||||||
|
str += ' class="'; |
||||||
|
BI.each(root.classList, (i, cls) => { |
||||||
|
str += ` ${cls}`; |
||||||
|
}); |
||||||
|
str += '"'; |
||||||
|
} |
||||||
|
str += ' style="'; |
||||||
|
BI.each(root.originalStyles, (key, stl) => { |
||||||
|
if ( |
||||||
|
skipArray.contains(key) || |
||||||
|
(key == 'height' && root.classList.contains('bi-design-components-data-data-table-cell')) |
||||||
|
) { |
||||||
|
return; |
||||||
|
} |
||||||
|
key = BI.hyphenate(key); |
||||||
|
if (key === 'font-family') { |
||||||
|
stl = stl.replace(/\"/g, ''); |
||||||
|
} |
||||||
|
if (pxStyle.contains(key) && BI.isNumeric(stl)) { |
||||||
|
stl += 'px'; |
||||||
|
} |
||||||
|
if (BI.isKey(stl)) { |
||||||
|
str += ` ${key}:${stl};`; |
||||||
|
} |
||||||
|
}); |
||||||
|
str += '"'; |
||||||
|
BI.each(root.attribs, (key, attr) => { |
||||||
|
if (BI.isKey(attr)) { |
||||||
|
str += ` ${key}=${attr}`; |
||||||
|
} |
||||||
|
}); |
||||||
|
if (root.textContent) { |
||||||
|
str += ` title=${root.textContent}`; |
||||||
|
} |
||||||
|
str += '>'; |
||||||
|
} |
||||||
|
// 特殊处理,spread_table的行列元素是不取配置里的高度的,使用stretch拉伸的(leaves取了高度),但是功能代码里给单元格默认高度了,导致拉伸不了
|
||||||
|
// 而spread_grid_table的行列元素是取配置里的高度的,拉不拉伸都一样
|
||||||
|
BI.each(root.children, (i, child) => { |
||||||
|
str += _renderToHtml(child); |
||||||
|
}); |
||||||
|
} else { |
||||||
|
str += root.originalHtml; |
||||||
|
} |
||||||
|
if (root.tag !== 'body') { |
||||||
|
if (root.textContent) { |
||||||
|
str += root.textContent; |
||||||
|
} |
||||||
|
str += `</${root.tag}>`; |
||||||
|
} |
||||||
|
return str; |
||||||
|
}; |
||||||
|
export const registRenderToHtmlFun = (Element) => { |
||||||
|
Element.registerFunction('renderToHtml', function () { |
||||||
|
return _renderToHtml(this); |
||||||
|
}); |
||||||
|
}; |
@ -0,0 +1,50 @@ |
|||||||
|
var skipArray = ['width', 'height']; |
||||||
|
var _renderToString = function (root) { |
||||||
|
var str = ''; |
||||||
|
if (root.nodeName !== 'body') { |
||||||
|
str += `<${root.nodeName}`; |
||||||
|
if (root.classList.length > 0) { |
||||||
|
str += ' class="'; |
||||||
|
BI.each(root.classList, (i, cls) => { |
||||||
|
str += ` ${cls}`; |
||||||
|
}); |
||||||
|
str += '"'; |
||||||
|
} |
||||||
|
str += ' style="'; |
||||||
|
BI.each(root.styles, (key, stl) => { |
||||||
|
if (skipArray.includes(key)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
key = BI.hyphenate(key); |
||||||
|
str += ` ${key}:${stl};`; |
||||||
|
}); |
||||||
|
str += ` width:${root.width}px;`; |
||||||
|
str += ` height:${root.height}px;`; |
||||||
|
str += ' position: fixed;'; |
||||||
|
str += ` left: ${root.position.x}px;`; |
||||||
|
str += ` top: ${root.position.y}px;`; |
||||||
|
str += '"'; |
||||||
|
BI.each(root.attribs, (key, attr) => { |
||||||
|
str += ` ${key}:${attr}`; |
||||||
|
}); |
||||||
|
str += '>'; |
||||||
|
} |
||||||
|
BI.each(root.children, (i, child) => { |
||||||
|
str += _renderToString(child); |
||||||
|
}); |
||||||
|
// if (root.htmlContent) {
|
||||||
|
// str += root.htmlContent;
|
||||||
|
// }
|
||||||
|
if (root.nodeName !== 'body') { |
||||||
|
if (root.text) { |
||||||
|
str += root.text; |
||||||
|
} |
||||||
|
str += `</${root.nodeName}>`; |
||||||
|
} |
||||||
|
return str; |
||||||
|
}; |
||||||
|
export const registRenderToStringFun = (Element) => { |
||||||
|
Element.registerFunction('renderToString', function () { |
||||||
|
return _renderToString(this); |
||||||
|
}); |
||||||
|
}; |
@ -0,0 +1,10 @@ |
|||||||
|
export const registTextFun = (Element) => { |
||||||
|
Element.registerFunction('setText', function (text) { |
||||||
|
this.text = text; |
||||||
|
return this; |
||||||
|
}); |
||||||
|
Element.registerFunction('setValue', function (text) { |
||||||
|
this.text = text; |
||||||
|
return this; |
||||||
|
}); |
||||||
|
}; |
@ -0,0 +1,9 @@ |
|||||||
|
export const registValFun = (Element) => { |
||||||
|
Element.registerFunction('val', function (value) { |
||||||
|
if (BI.isNotNull(value)) { |
||||||
|
this.text = `${value}`; |
||||||
|
return this; |
||||||
|
} |
||||||
|
return this.text; |
||||||
|
}); |
||||||
|
}; |