1
- import { EmptyContent } from "components/EmptyContent" ;
2
- import { HelpText } from "components/HelpText" ;
3
- import { Tabs } from "components/Tabs" ;
4
- import {
5
- clearMockWindow ,
6
- clearStyleEval ,
7
- ConstructorToComp ,
8
- evalFunc ,
9
- evalStyle ,
10
- RecordConstructorToComp ,
11
- } from "lowcoder-core" ;
12
- import { CodeTextControl } from "comps/controls/codeTextControl" ;
13
- import SimpleStringControl from "comps/controls/simpleStringControl" ;
14
- import { MultiCompBuilder , withPropertyViewFn } from "comps/generators" ;
15
- import { list } from "comps/generators/list" ;
16
- import { BaseSection , CustomModal , PlusIcon , ScrollBar } from "lowcoder-design" ;
17
- import React , { useContext , useEffect , useState } from "react" ;
18
- import styled from "styled-components" ;
19
- import { ExternalEditorContext } from "util/context/ExternalEditorContext" ;
20
- import { runScriptInHost } from "util/commonUtils" ;
21
- import { getGlobalSettings } from "comps/utils/globalSettings" ;
22
- import { trans } from "i18n" ;
23
- import log from "loglevel" ;
24
- import { JSLibraryModal } from "components/JSLibraryModal" ;
25
- import { JSLibraryTree } from "components/JSLibraryTree" ;
26
- import { fetchJSLibrary } from "util/jsLibraryUtils" ;
27
-
28
- export interface ExternalPreload {
29
- css ?: string ;
30
- libs ?: string [ ] ;
31
- script ?: string ;
32
- runJavaScriptInHost ?: boolean ;
33
- }
34
-
35
- interface RunAndClearable < T > {
36
- run ( id : string , externalPreload ?: T ) : Promise < any > ;
37
-
38
- clear ( ) : Promise < any > ;
39
- }
40
-
41
- class LibsCompBase extends list ( SimpleStringControl ) implements RunAndClearable < string [ ] > {
42
- success : Record < string , boolean > = { } ;
43
- globalVars : Record < string , string [ ] > = { } ;
44
- externalLibs : string [ ] = [ ] ;
45
- runInHost : boolean = false ;
46
-
47
- getAllLibs ( ) {
48
- return this . externalLibs . concat ( this . getView ( ) . map ( ( i ) => i . getView ( ) ) ) ;
49
- }
50
-
51
- async loadScript ( url : string ) {
52
- if ( this . success [ url ] ) {
53
- return ;
54
- }
55
- return fetchJSLibrary ( url ) . then ( ( code ) => {
56
- evalFunc (
57
- code ,
58
- { } ,
59
- { } ,
60
- {
61
- scope : "function" ,
62
- disableLimit : this . runInHost ,
63
- onSetGlobalVars : ( v : string ) => {
64
- this . globalVars [ url ] = this . globalVars [ url ] || [ ] ;
65
- if ( ! this . globalVars [ url ] . includes ( v ) ) {
66
- this . globalVars [ url ] . push ( v ) ;
67
- }
68
- } ,
69
- }
70
- ) ;
71
- this . success [ url ] = true ;
72
- } ) ;
73
- }
74
-
75
- async loadAllLibs ( ) {
76
- const scriptRunners = this . getAllLibs ( ) . map ( ( url ) =>
77
- this . loadScript ( url ) . catch ( ( e ) => {
78
- log . warn ( e ) ;
79
- } )
80
- ) ;
81
-
82
- try {
83
- await Promise . all ( scriptRunners ) ;
84
- } catch ( e ) {
85
- log . warn ( "load preload libs error:" , e ) ;
86
- }
87
- }
88
-
89
- async run ( id : string , externalLibs : string [ ] = [ ] , runInHost : boolean = false ) {
90
- this . externalLibs = externalLibs ;
91
- this . runInHost = runInHost ;
92
- return this . loadAllLibs ( ) ;
93
- }
94
-
95
- async clear ( ) : Promise < any > {
96
- clearMockWindow ( ) ;
97
- }
98
- }
99
-
100
- const LibsComp = withPropertyViewFn ( LibsCompBase , ( comp ) => {
101
- useEffect ( ( ) => {
102
- comp . loadAllLibs ( ) ;
103
- } , [ comp . getView ( ) . length ] ) ;
104
- return (
105
- < ScrollBar style = { { height : "295px" } } >
106
- { comp . getAllLibs ( ) . length === 0 && (
107
- < EmptyContent text = { trans ( "preLoad.jsLibraryEmptyContent" ) } style = { { margin : "0 16px" } } />
108
- ) }
109
- < JSLibraryTree
110
- mode = { "column" }
111
- libs = { comp
112
- . getView ( )
113
- . map ( ( i ) => ( {
114
- url : i . getView ( ) ,
115
- deletable : true ,
116
- exportedAs : comp . globalVars [ i . getView ( ) ] ?. [ 0 ] ,
117
- } ) )
118
- . concat (
119
- comp . externalLibs . map ( ( l ) => ( {
120
- url : l ,
121
- deletable : false ,
122
- exportedAs : comp . globalVars [ l ] ?. [ 0 ] ,
123
- } ) )
124
- ) }
125
- onDelete = { ( idx ) => {
126
- comp . dispatch ( comp . deleteAction ( idx ) ) ;
127
- } }
128
- />
129
- </ ScrollBar >
130
- ) ;
131
- } ) ;
132
-
133
- function runScript ( code : string , inHost ?: boolean ) {
134
- if ( inHost ) {
135
- runScriptInHost ( code ) ;
136
- return ;
137
- }
138
- try {
139
- evalFunc ( code , { } , { } ) ;
140
- } catch ( e ) {
141
- log . error ( e ) ;
142
- }
143
- }
144
-
145
- class ScriptComp extends CodeTextControl implements RunAndClearable < string > {
146
- runInHost : boolean = false ;
147
-
148
- runPreloadScript ( ) {
149
- const code = this . getView ( ) ;
150
- if ( ! code ) {
151
- return ;
152
- }
153
- runScript ( code , this . runInHost ) ;
154
- }
155
-
156
- async run ( id : string , externalScript : string = "" , runInHost : boolean = false ) {
157
- this . runInHost = runInHost ;
158
- if ( externalScript ) {
159
- runScript ( externalScript , runInHost ) ;
160
- }
161
- this . runPreloadScript ( ) ;
162
- }
163
-
164
- async clear ( ) : Promise < any > {
165
- clearMockWindow ( ) ;
166
- }
167
- }
168
-
169
- class CSSComp extends CodeTextControl implements RunAndClearable < string > {
170
- id = "" ;
171
- externalCSS : string = "" ;
172
-
173
- async applyAllCSS ( ) {
174
- const css = this . getView ( ) ;
175
- evalStyle ( this . id , [ this . externalCSS , css ] ) ;
176
- }
177
-
178
- async run ( id : string , externalCSS : string = "" ) {
179
- this . id = id ;
180
- this . externalCSS = externalCSS ;
181
- return this . applyAllCSS ( ) ;
182
- }
183
-
184
- async clear ( ) {
185
- clearStyleEval ( this . id ) ;
186
- }
187
- }
188
-
189
- class GlobalCSSComp extends CodeTextControl implements RunAndClearable < string > {
190
- id = "" ;
191
- externalCSS : string = "" ;
192
-
193
- async applyAllCSS ( ) {
194
- const css = this . getView ( ) ;
195
- evalStyle ( this . id , [ this . externalCSS , css ] , true ) ;
196
- }
197
-
198
- async run ( id : string , externalCSS : string = "" ) {
199
- this . id = id ;
200
- this . externalCSS = externalCSS ;
201
- return this . applyAllCSS ( ) ;
202
- }
203
-
204
- async clear ( ) {
205
- clearStyleEval ( this . id ) ;
206
- }
207
- }
208
-
209
- const childrenMap = {
210
- libs : LibsComp ,
211
- script : ScriptComp ,
212
- css : CSSComp ,
213
- globalCSS : GlobalCSSComp ,
214
- } ;
215
-
216
- type ChildrenInstance = RecordConstructorToComp < typeof childrenMap > ;
217
-
218
- function JavaScriptTabPane ( props : { comp : ConstructorToComp < typeof ScriptComp > } ) {
219
- useEffect ( ( ) => {
220
- props . comp . runPreloadScript ( ) ;
221
- } , [ props . comp ] ) ;
222
-
223
- const codePlaceholder = `window.name = 'Tom';\nwindow.greet = () => "hello world";` ;
224
-
225
- return (
226
- < >
227
- < HelpText style = { { marginBottom : 20 } } > { trans ( "preLoad.jsHelpText" ) } </ HelpText >
228
- { props . comp . propertyView ( {
229
- expandable : false ,
230
- styleName : "window" ,
231
- codeType : "Function" ,
232
- language : "javascript" ,
233
- placeholder : codePlaceholder ,
234
- } ) }
235
- </ >
236
- ) ;
237
- }
238
-
239
- function CSSTabPane ( props : { comp : CSSComp , isGlobal ?: boolean } ) {
240
- useEffect ( ( ) => {
241
- props . comp . applyAllCSS ( ) ;
242
- } , [ props . comp ] ) ;
243
-
244
- const codePlaceholder = `.top-header {\n background-color: red; \n}` ;
245
-
246
- return (
247
- < >
248
- < HelpText style = { { marginBottom : 20 } } > { trans ( "preLoad.cssHelpText" ) } </ HelpText >
249
- { props . comp . propertyView ( {
250
- expandable : false ,
251
- placeholder : codePlaceholder ,
252
- styleName : "window" ,
253
- language : "css" ,
254
- } ) }
255
- </ >
256
- ) ;
257
- }
258
-
259
- enum TabKey {
260
- JavaScript = "js" ,
261
- CSS = "css" ,
262
- GLOBAL_CSS = "global_css" ,
263
- }
264
-
265
- function PreloadConfigModal ( props : ChildrenInstance ) {
266
- const [ activeKey , setActiveKey ] = useState ( TabKey . JavaScript ) ;
267
- const { showScriptsAndStyleModal, changeExternalState } = useContext ( ExternalEditorContext ) ;
268
-
269
- const tabItems = [
270
- {
271
- key : TabKey . JavaScript ,
272
- label : 'JavaScript' ,
273
- children : < JavaScriptTabPane comp = { props . script } />
274
- } ,
275
- {
276
- key : TabKey . CSS ,
277
- label : 'CSS' ,
278
- children : < CSSTabPane comp = { props . css } />
279
- } ,
280
- {
281
- key : TabKey . GLOBAL_CSS ,
282
- label : 'Global CSS' ,
283
- children : < CSSTabPane comp = { props . globalCSS } isGlobal />
284
- } ,
285
- ]
286
- return (
287
- < CustomModal
288
- draggable
289
- mask = { activeKey !== TabKey . CSS }
290
- open = { showScriptsAndStyleModal }
291
- title = { trans ( "preLoad.scriptsAndStyles" ) }
292
- destroyOnHidden
293
- onCancel = { ( ) => changeExternalState ?.( { showScriptsAndStyleModal : false } ) }
294
- showOkButton = { false }
295
- showCancelButton = { false }
296
- width = "600px"
297
- >
298
- < Tabs
299
- onChange = { ( k ) => setActiveKey ( k as TabKey ) }
300
- style = { { marginBottom : 8 , marginTop : 4 } }
301
- activeKey = { activeKey }
302
- items = { tabItems }
303
- >
304
- </ Tabs >
305
- </ CustomModal >
306
- ) ;
307
- }
308
-
309
- const PreloadCompBase = new MultiCompBuilder ( childrenMap , ( ) => { } )
310
- . setPropertyViewFn ( ( children ) => < PreloadConfigModal { ...children } /> )
311
- . build ( ) ;
312
-
313
- const AddJSLibraryButton = styled . div `
314
- cursor: pointer;
315
- margin-right: 16px;
316
-
317
- g g {
318
- stroke: #8b8fa3;
319
- }
320
-
321
- &:hover {
322
- g g {
323
- stroke: #222222;
324
- }
325
- }
326
- ` ;
327
-
328
- const JSLibraryWrapper = styled . div `
329
- position: relative;
330
- ` ;
331
-
332
- export class PreloadComp extends PreloadCompBase {
333
- async clear ( ) {
334
- return Promise . allSettled ( Object . values ( this . children ) . map ( ( i ) => i . clear ( ) ) ) ;
335
- }
336
-
337
- async run ( id : string ) {
338
- const { orgCommonSettings = { } } = getGlobalSettings ( ) ;
339
- const { preloadCSS, preloadGlobalCSS, preloadJavaScript, preloadLibs, runJavaScriptInHost } = orgCommonSettings ;
340
- await this . children . css . run ( id , preloadCSS || "" ) ;
341
- await this . children . globalCSS . run ( 'body' , preloadGlobalCSS || "" ) ;
342
- await this . children . libs . run ( id , preloadLibs || [ ] , ! ! runJavaScriptInHost ) ;
343
- await this . children . script . run ( id , preloadJavaScript || "" , ! ! runJavaScriptInHost ) ;
344
- }
345
-
346
- getJSLibraryPropertyView ( ) {
347
- const libs = this . children . libs ;
348
- return (
349
- < JSLibraryWrapper >
350
- < BaseSection
351
- name = { trans ( "preLoad.jsLibrary" ) }
352
- width = { 288 }
353
- noMargin
354
- style = { {
355
- borderTop : "1px solid #e1e3eb" ,
356
- backgroundColor : "#fff" ,
357
- } }
358
- additionalButton = {
359
- < AddJSLibraryButton >
360
- < JSLibraryModal
361
- runInHost = { libs . runInHost }
362
- trigger = { < PlusIcon height = { "46px" } /> }
363
- onCheck = { ( url ) => ! libs . getAllLibs ( ) . includes ( url ) }
364
- onLoad = { ( url ) => libs . loadScript ( url ) }
365
- onSuccess = { ( url ) => libs . dispatch ( libs . pushAction ( url ) ) }
366
- />
367
- </ AddJSLibraryButton >
368
- }
369
- >
370
- { this . children . libs . getPropertyView ( ) }
371
- </ BaseSection >
372
- </ JSLibraryWrapper >
373
- ) ;
374
- }
375
- }
1
+ export { PreloadComp } from "./preLoadComp/preLoadComp" ;
0 commit comments