neo.mjs 6.41.0 → 6.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/ServiceWorker.mjs +2 -2
- package/apps/portal/view/learn/ContentView.mjs +1 -1
- package/apps/portal/view/services/Component.mjs +1 -1
- package/docs/app/view/MainContainerController.mjs +1 -1
- package/examples/ServiceWorker.mjs +2 -2
- package/package.json +1 -1
- package/resources/data/deck/learnneo/pages/benefits/FormsEngine.md +2 -2
- package/resources/data/deck/learnneo/pages/benefits/Multi-Threading.md +2 -2
- package/resources/scss/src/apps/portal/HeaderToolbar.scss +3 -5
- package/resources/scss/src/apps/portal/home/ContentBox.scss +41 -8
- package/resources/scss/src/toolbar/Base.scss +4 -0
- package/src/DefaultConfig.mjs +2 -2
- package/src/component/Video.mjs +21 -16
- package/src/main/DomAccess.mjs +6 -3
- package/src/main/addon/AmCharts.mjs +66 -61
- package/src/main/addon/Base.mjs +88 -1
- package/src/main/addon/HighlightJS.mjs +41 -68
- package/src/main/addon/MonacoEditor.mjs +64 -31
- package/src/worker/Manager.mjs +3 -0
package/apps/ServiceWorker.mjs
CHANGED
@@ -55,7 +55,7 @@ class ContentView extends Component {
|
|
55
55
|
scope : me
|
56
56
|
});
|
57
57
|
|
58
|
-
Neo.main.addon.HighlightJS.
|
58
|
+
Neo.main.addon.HighlightJS.loadFiles({
|
59
59
|
appName : me.appName,
|
60
60
|
highlightJsPath: '../../docs/resources/highlight/highlight.pack.js',
|
61
61
|
themePath : '../../docs/resources/highlightjs-custom-github-theme.css'
|
@@ -24,7 +24,7 @@ class Component extends BaseComponent {
|
|
24
24
|
{cls: ['info-block'], cn: [
|
25
25
|
{tag: 'h2', html: 'Weekly Workshops'},
|
26
26
|
{tag: 'p', html: [
|
27
|
-
'We are doing weekly workshops on Thursdays
|
27
|
+
'We are doing weekly workshops on Thursdays 18:30 CEST (12:30am EST) for 60m free of charge.</br>',
|
28
28
|
'Ping us inside our ',
|
29
29
|
'<a href="https://join.slack.com/t/neomjs/shared_invite/zt-6c50ueeu-3E1~M4T9xkNnb~M_prEEOA">Slack Channel</a>, ',
|
30
30
|
'in case you would like to join us.'
|
package/package.json
CHANGED
@@ -248,8 +248,8 @@ In a nutshell:
|
|
248
248
|
{
|
249
249
|
module: TabContainer,
|
250
250
|
items : [
|
251
|
-
{module: () => import('./MyChildForm1')},
|
252
|
-
{module: () => import('./MyChildForm2')}
|
251
|
+
{module: () => import('./MyChildForm1.mjs')},
|
252
|
+
{module: () => import('./MyChildForm2.mjs')}
|
253
253
|
]
|
254
254
|
}
|
255
255
|
</pre>
|
@@ -24,7 +24,7 @@ On its own, a Browser will just use ***one*** core per tab / window.
|
|
24
24
|
Meaning: your Angular or React apps look like this:
|
25
25
|
|
26
26
|
<p style="overflow-x: auto;">
|
27
|
-
<img alt="Current State of Apps" src="https://raw.githubusercontent.com/neomjs/pages/main/resources_pub/images/apps-today.png">
|
27
|
+
<img style="height: 279px; width: 481px;" alt="Current State of Apps" src="https://raw.githubusercontent.com/neomjs/pages/main/resources_pub/images/apps-today.png">
|
28
28
|
</p>
|
29
29
|
|
30
30
|
The more JavaScript tasks are running inside your app, the slower it will get.
|
@@ -82,7 +82,7 @@ To resolve this performance bottleneck, we want to get main threads as idle as p
|
|
82
82
|
rendering / dynamically manipulating the DOM:
|
83
83
|
|
84
84
|
<p style="overflow-x: auto;">
|
85
|
-
<img alt="App Worker Concept" src="https://raw.githubusercontent.com/neomjs/pages/main/resources_pub/images/app-worker.png">
|
85
|
+
<img style="height: 481px; width: 442px;" alt="App Worker Concept" src="https://raw.githubusercontent.com/neomjs/pages/main/resources_pub/images/app-worker.png">
|
86
86
|
</p>
|
87
87
|
|
88
88
|
The worst case that could happen now is that your app worker will slow down and this core runs at 100%. However,
|
@@ -1,28 +1,61 @@
|
|
1
1
|
.portal-content-box {
|
2
2
|
border-radius : 3px;
|
3
3
|
box-shadow : 0 3px 6px rgba(0, 0, 0, 0.3);
|
4
|
-
cursor : pointer;
|
5
4
|
color : #000;
|
5
|
+
cursor : pointer;
|
6
6
|
min-width : 300px;
|
7
7
|
padding : 0 1em 1em 1em;
|
8
|
+
position : relative;
|
8
9
|
text-decoration: none;
|
9
10
|
|
10
11
|
&:hover {
|
11
12
|
background-color: var(--sem-color-surface-primary-background);
|
13
|
+
|
14
|
+
&:after {
|
15
|
+
background-color: var(--purple-200);
|
16
|
+
border-radius : 2px;
|
17
|
+
bottom : 10px;
|
18
|
+
content : attr(href) ' \2192';
|
19
|
+
font-size : 0.7em;
|
20
|
+
left : -1px;
|
21
|
+
opacity : 0.7;
|
22
|
+
padding : 3px 20px;
|
23
|
+
position : absolute;
|
24
|
+
right : -1px;
|
25
|
+
text-align : center;
|
26
|
+
}
|
27
|
+
|
28
|
+
.portal-content-box-headline {
|
29
|
+
border-bottom-color: #b7c0da;
|
30
|
+
}
|
12
31
|
}
|
13
32
|
|
14
33
|
.portal-content-box-content {
|
34
|
+
margin-top : 0.75em;
|
15
35
|
padding-left: 1.3em;
|
16
|
-
margin-top: 0.75em;
|
17
36
|
}
|
18
37
|
|
19
38
|
.portal-content-box-headline {
|
20
|
-
border-bottom: 1px solid #ececec;
|
39
|
+
border-bottom : 1px solid #ececec;
|
40
|
+
letter-spacing: 1.5px !important;
|
41
|
+
margin : 1em auto 0 auto;
|
42
|
+
max-width : 85%;
|
21
43
|
padding-bottom: 0.75em;
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
44
|
+
text-align : center;
|
45
|
+
word-spacing : 1.5px;
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
.neo-no-mouse {
|
50
|
+
.portal-content-box {
|
51
|
+
&:after {
|
52
|
+
bottom : .5em;
|
53
|
+
color : var(--purple-200);
|
54
|
+
content : '\f08e';
|
55
|
+
font-family: var(--fa-style-family-classic);
|
56
|
+
font-weight: 600;
|
57
|
+
position : absolute;
|
58
|
+
right : .5em;
|
59
|
+
}
|
27
60
|
}
|
28
61
|
}
|
package/src/DefaultConfig.mjs
CHANGED
@@ -260,12 +260,12 @@ const DefaultConfig = {
|
|
260
260
|
useVdomWorker: true,
|
261
261
|
/**
|
262
262
|
* buildScripts/injectPackageVersion.mjs will update this value
|
263
|
-
* @default '6.
|
263
|
+
* @default '6.42.0'
|
264
264
|
* @memberOf! module:Neo
|
265
265
|
* @name config.version
|
266
266
|
* @type String
|
267
267
|
*/
|
268
|
-
version: '6.
|
268
|
+
version: '6.42.0'
|
269
269
|
};
|
270
270
|
|
271
271
|
Object.assign(DefaultConfig, {
|
package/src/component/Video.mjs
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
import BaseComponent from '../component/Base.mjs';
|
2
|
-
import VDomUtil
|
2
|
+
import VDomUtil from '../util/VDom.mjs';
|
3
|
+
|
4
|
+
let isOperaMini = null;
|
3
5
|
|
4
6
|
/**
|
5
7
|
* @class Neo.component.Video
|
@@ -39,7 +41,7 @@ class Video extends BaseComponent {
|
|
39
41
|
autoplay: false,
|
40
42
|
/**
|
41
43
|
* In case the browser does not support the video source the component should show an error.
|
42
|
-
* @member {
|
44
|
+
* @member {String} errorMsg='The browser does not support the video'
|
43
45
|
*/
|
44
46
|
errorMsg: 'Your browser does not support the video tag.',
|
45
47
|
/**
|
@@ -109,32 +111,35 @@ class Video extends BaseComponent {
|
|
109
111
|
}
|
110
112
|
|
111
113
|
/**
|
112
|
-
* afterSetUrl
|
113
114
|
* Add a source element into the video element containing the url
|
114
|
-
*
|
115
115
|
* @param {String} value
|
116
116
|
* @param {String|null} oldValue
|
117
117
|
*/
|
118
|
-
afterSetUrl(value, oldValue) {
|
118
|
+
async afterSetUrl(value, oldValue) {
|
119
119
|
if (!value) return;
|
120
120
|
|
121
|
-
let
|
122
|
-
|
123
|
-
|
124
|
-
|
121
|
+
let me = this,
|
122
|
+
{vdom} = me,
|
123
|
+
media = VDomUtil.getFlags(vdom, 'media')[0],
|
124
|
+
userAgent;
|
125
|
+
|
126
|
+
if (isOperaMini === null) {
|
127
|
+
userAgent = await Neo.Main.getByPath({path: 'navigator.userAgent'});
|
128
|
+
isOperaMini = userAgent.includes('Opera Mini');
|
129
|
+
}
|
125
130
|
|
126
131
|
media.cn = [{
|
127
|
-
tag: 'source',
|
128
|
-
src: value,
|
129
|
-
type:
|
132
|
+
tag : 'source',
|
133
|
+
src : value,
|
134
|
+
type: me.type
|
130
135
|
}];
|
131
136
|
|
132
137
|
// Opera Mini might not support the video-source => check the user agent string
|
133
138
|
if (isOperaMini) {
|
134
139
|
media.cn.push({
|
135
|
-
tag: 'span',
|
136
|
-
html:
|
137
|
-
})
|
140
|
+
tag : 'span',
|
141
|
+
html: me.errorMsg
|
142
|
+
})
|
138
143
|
}
|
139
144
|
|
140
145
|
this.update()
|
@@ -144,7 +149,7 @@ class Video extends BaseComponent {
|
|
144
149
|
* autoplay - run the event listeners
|
145
150
|
* Only called in constructor and sets playing => calls update already
|
146
151
|
*
|
147
|
-
* Rationale: update() sends the vdom & vnode on a workers roundtrip to get the deltas.
|
152
|
+
* Rationale: update() sends the vdom & vnode on a workers roundtrip to get the deltas.
|
148
153
|
* While this is happening, the component locks itself for future updates until the new vnode got back (async).
|
149
154
|
* After the delay the framework would trigger a 2nd roundtrip to get the deltas for the visible node.
|
150
155
|
*
|
package/src/main/DomAccess.mjs
CHANGED
@@ -566,18 +566,21 @@ class DomAccess extends Base {
|
|
566
566
|
|
567
567
|
/**
|
568
568
|
* Include a script into the document.head
|
569
|
+
* You can add more attributes if needed. See: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script
|
569
570
|
* @param {String} src
|
570
|
-
* @param {
|
571
|
+
* @param {Object} opts=defer:true}
|
572
|
+
* @param {Boolean} [opts.async]
|
573
|
+
* @param {Boolean} [opts.defer]
|
571
574
|
* @returns {Promise<unknown>}
|
572
575
|
*/
|
573
|
-
loadScript(src,
|
576
|
+
loadScript(src, opts={defer:true}) {
|
574
577
|
let script;
|
575
578
|
|
576
579
|
return new Promise((resolve, reject) => {
|
577
580
|
script = document.createElement('script');
|
578
581
|
|
579
582
|
Object.assign(script, {
|
580
|
-
|
583
|
+
...opts,
|
581
584
|
onerror: reject,
|
582
585
|
onload : resolve,
|
583
586
|
src
|
@@ -20,12 +20,6 @@ class AmCharts extends Base {
|
|
20
20
|
* @protected
|
21
21
|
*/
|
22
22
|
charts: {},
|
23
|
-
/**
|
24
|
-
* Stores all chart config objects which arrived before the chart lib scripts got loaded
|
25
|
-
* @member {Object[]} chartsToCreate=[]
|
26
|
-
* @protected
|
27
|
-
*/
|
28
|
-
chartsToCreate: [],
|
29
23
|
/**
|
30
24
|
* Stores all chart data inside an object. key => chart id
|
31
25
|
* No array since in case a chart gets loaded multiple times, we only want to apply the last data on mount.
|
@@ -45,7 +39,7 @@ class AmCharts extends Base {
|
|
45
39
|
fallbackPath: 'https://neomjs.github.io/pages/resources_pub/amCharts/',
|
46
40
|
/**
|
47
41
|
* Remote method access for other workers
|
48
|
-
* @member {Object} remote
|
42
|
+
* @member {Object} remote
|
49
43
|
* @protected
|
50
44
|
*/
|
51
45
|
remote: {
|
@@ -57,39 +51,21 @@ class AmCharts extends Base {
|
|
57
51
|
'setProperty',
|
58
52
|
'updateData'
|
59
53
|
]
|
60
|
-
}
|
61
|
-
/**
|
62
|
-
* @member {Boolean} scriptsLoaded_=true
|
63
|
-
* @protected
|
64
|
-
*/
|
65
|
-
scriptsLoaded_: false
|
66
|
-
}
|
67
|
-
|
68
|
-
/**
|
69
|
-
* @param {Object} config
|
70
|
-
*/
|
71
|
-
construct(config) {
|
72
|
-
super.construct(config);
|
73
|
-
|
74
|
-
this.insertAmChartsScripts()
|
54
|
+
}
|
75
55
|
}
|
76
56
|
|
77
57
|
/**
|
78
|
-
* Triggered after the
|
58
|
+
* Triggered after the isReady config got changed
|
79
59
|
* @param {Boolean} value
|
80
60
|
* @param {Boolean} oldValue
|
81
61
|
* @protected
|
82
62
|
*/
|
83
|
-
|
63
|
+
afterSetIsReady(value, oldValue) {
|
64
|
+
super.afterSetIsReady(value, oldValue);
|
65
|
+
|
84
66
|
if (value) {
|
85
67
|
let me = this;
|
86
68
|
|
87
|
-
me.chartsToCreate.forEach(config => {
|
88
|
-
me.create(config)
|
89
|
-
});
|
90
|
-
|
91
|
-
me.chartsToCreate = [];
|
92
|
-
|
93
69
|
me.timeout(1000).then(() => {
|
94
70
|
Object.entries(me.dataMap).forEach(([key, dataValue]) => {
|
95
71
|
me.updateData(dataValue)
|
@@ -107,15 +83,21 @@ class AmCharts extends Base {
|
|
107
83
|
* @param {Array} [data.params]
|
108
84
|
*/
|
109
85
|
callMethod(data) {
|
110
|
-
|
111
|
-
let chart = this.charts[data.id],
|
112
|
-
pathArray = data.path.split('.'),
|
113
|
-
methodName = pathArray.pop(),
|
114
|
-
scope = pathArray.length < 1 ? chart: Neo.ns(pathArray.join('.'), false, chart);
|
86
|
+
let me = this;
|
115
87
|
|
116
|
-
|
88
|
+
if (!me.isReady) {
|
89
|
+
return me.cacheMethodCall({fn: 'callMethod', data})
|
117
90
|
} else {
|
118
|
-
|
91
|
+
if (me.hasChart(data.id)) {
|
92
|
+
let chart = me.charts[data.id],
|
93
|
+
pathArray = data.path.split('.'),
|
94
|
+
methodName = pathArray.pop(),
|
95
|
+
scope = pathArray.length < 1 ? chart: Neo.ns(pathArray.join('.'), false, chart);
|
96
|
+
|
97
|
+
scope[methodName].call(scope, ...data.params || [])
|
98
|
+
} else {
|
99
|
+
// todo
|
100
|
+
}
|
119
101
|
}
|
120
102
|
}
|
121
103
|
|
@@ -149,11 +131,10 @@ class AmCharts extends Base {
|
|
149
131
|
create(data) {
|
150
132
|
let me = this;
|
151
133
|
|
152
|
-
if (!me.
|
153
|
-
me.
|
134
|
+
if (!me.isReady) {
|
135
|
+
return me.cacheMethodCall({fn: 'create', data})
|
154
136
|
} else {
|
155
137
|
// todo: check if globalThis[data.package] exists, if not load it and call create afterwards
|
156
|
-
|
157
138
|
am4core.useTheme(am4themes_dark);
|
158
139
|
|
159
140
|
me.charts[data.id] = am4core.createFromConfig(data.config, data.id, globalThis[data.package][data.type || 'XYChart']);
|
@@ -181,8 +162,14 @@ class AmCharts extends Base {
|
|
181
162
|
* @param {String} data.id
|
182
163
|
*/
|
183
164
|
destroy(data) {
|
184
|
-
this
|
185
|
-
|
165
|
+
let me = this;
|
166
|
+
|
167
|
+
if (!me.isReady) {
|
168
|
+
return me.cacheMethodCall({fn: 'destroy', data})
|
169
|
+
} else {
|
170
|
+
me.charts[data.id]?.dispose?.();
|
171
|
+
delete me.charts[data.id]
|
172
|
+
}
|
186
173
|
}
|
187
174
|
|
188
175
|
/**
|
@@ -197,11 +184,14 @@ class AmCharts extends Base {
|
|
197
184
|
* Async approach
|
198
185
|
* core.js has to arrive first or the other scripts will cause JS errors since they rely on it
|
199
186
|
* => fetching the other files after core.js is loaded
|
187
|
+
* @param {Boolean} useFallback=false
|
200
188
|
*/
|
201
|
-
|
189
|
+
loadFiles(useFallback=false) {
|
202
190
|
let me = this,
|
203
191
|
basePath = useFallback ? me.fallbackPath : me.downloadPath;
|
204
192
|
|
193
|
+
me.isLoading = true;
|
194
|
+
|
205
195
|
DomAccess.loadScript(basePath + 'core.js').then(() => {
|
206
196
|
Promise.all([
|
207
197
|
DomAccess.loadScript(basePath + 'charts.js'),
|
@@ -209,11 +199,12 @@ class AmCharts extends Base {
|
|
209
199
|
DomAccess.loadScript(basePath + 'themes/dark.js'),
|
210
200
|
DomAccess.loadScript(basePath + 'geodata/worldLow.js')
|
211
201
|
]).then(() => {
|
212
|
-
me.
|
213
|
-
|
202
|
+
me.isLoading = false;
|
203
|
+
me.isReady = true
|
204
|
+
})
|
214
205
|
}).catch(e => {
|
215
206
|
console.log('Download from amcharts.com failed, switching to fallback', e);
|
216
|
-
me.
|
207
|
+
me.loadFiles(true)
|
217
208
|
})
|
218
209
|
}
|
219
210
|
|
@@ -223,13 +214,19 @@ class AmCharts extends Base {
|
|
223
214
|
* @param {Object} data.properties
|
224
215
|
*/
|
225
216
|
setProperties(data) {
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
217
|
+
let me = this;
|
218
|
+
|
219
|
+
if (!me.isReady) {
|
220
|
+
return me.cacheMethodCall({fn: 'setProperties', data})
|
221
|
+
} else {
|
222
|
+
Object.entries(data.properties).forEach(([key, value]) => {
|
223
|
+
me.setProperty({
|
224
|
+
id : data.id,
|
225
|
+
path : key,
|
226
|
+
value
|
227
|
+
})
|
231
228
|
})
|
232
|
-
}
|
229
|
+
}
|
233
230
|
}
|
234
231
|
|
235
232
|
/**
|
@@ -240,15 +237,21 @@ class AmCharts extends Base {
|
|
240
237
|
* @param {*} data.value
|
241
238
|
*/
|
242
239
|
setProperty(data) {
|
243
|
-
|
244
|
-
let chart = this.charts[data.id],
|
245
|
-
pathArray = data.path.split('.'),
|
246
|
-
propertyName = pathArray.pop(),
|
247
|
-
scope = Neo.ns(pathArray.join('.'), false, chart);
|
240
|
+
let me = this;
|
248
241
|
|
249
|
-
|
242
|
+
if (!me.isReady) {
|
243
|
+
return me.cacheMethodCall({fn: 'setProperty', data})
|
250
244
|
} else {
|
251
|
-
|
245
|
+
if (this.hasChart(data.id)) {
|
246
|
+
let chart = this.charts[data.id],
|
247
|
+
pathArray = data.path.split('.'),
|
248
|
+
propertyName = pathArray.pop(),
|
249
|
+
scope = Neo.ns(pathArray.join('.'), false, chart);
|
250
|
+
|
251
|
+
scope[propertyName] = data.isColor ? am4core.color(data.value) : data.value
|
252
|
+
} else {
|
253
|
+
// todo
|
254
|
+
}
|
252
255
|
}
|
253
256
|
}
|
254
257
|
|
@@ -261,10 +264,12 @@ class AmCharts extends Base {
|
|
261
264
|
updateData(data) {
|
262
265
|
let me = this;
|
263
266
|
|
264
|
-
if (!me.
|
267
|
+
if (!me.isReady) {
|
268
|
+
return me.cacheMethodCall({fn: 'updateData', data})
|
269
|
+
} else if (!me.hasChart(data.id)) {
|
265
270
|
me.dataMap[data.id] = data
|
266
271
|
} else {
|
267
|
-
|
272
|
+
let chart = me.charts[data.id];
|
268
273
|
|
269
274
|
if (data.dataPath === '') {
|
270
275
|
chart.data = data.data
|
package/src/main/addon/Base.mjs
CHANGED
@@ -17,7 +17,94 @@ class Base extends CoreBase {
|
|
17
17
|
* @member {Boolean} isMainThreadAddon=true
|
18
18
|
* @protected
|
19
19
|
*/
|
20
|
-
isMainThreadAddon: true
|
20
|
+
isMainThreadAddon: true,
|
21
|
+
/**
|
22
|
+
* Will get set to true once all addon related files got loaded (if there is a need to load)
|
23
|
+
* @member {Boolean} isReady_=false
|
24
|
+
* @protected
|
25
|
+
*/
|
26
|
+
isReady_: false,
|
27
|
+
/**
|
28
|
+
* Amount in ms to delay the loading of library files, unless remote method access happens
|
29
|
+
* Change the value to false in case you don't want an automated preloading
|
30
|
+
* @member {Boolean|Number} preloadFilesDelay=5000
|
31
|
+
* @protected
|
32
|
+
*/
|
33
|
+
preloadFilesDelay: 5000,
|
34
|
+
}
|
35
|
+
|
36
|
+
/**
|
37
|
+
* @member {Object[]} cache=[]
|
38
|
+
*/
|
39
|
+
cache = []
|
40
|
+
/**
|
41
|
+
* Will get set to true once we start loading Monaco related files
|
42
|
+
* @member {Boolean} isLoading=false
|
43
|
+
*/
|
44
|
+
isLoading = false
|
45
|
+
/**
|
46
|
+
* Internal flag to store the setTimeout() id for loading external files
|
47
|
+
* @member {Number|null} loadingTimeoutId=null
|
48
|
+
*/
|
49
|
+
loadingTimeoutId = null
|
50
|
+
|
51
|
+
/**
|
52
|
+
* @param {Object} config
|
53
|
+
*/
|
54
|
+
construct(config) {
|
55
|
+
super.construct(config);
|
56
|
+
|
57
|
+
let me = this;
|
58
|
+
|
59
|
+
if (me.loadFiles) {
|
60
|
+
if (me.preloadFilesDelay === 0) {
|
61
|
+
me.loadFiles()
|
62
|
+
} else if (Neo.isNumber(me.preloadFilesDelay)) {
|
63
|
+
me.loadingTimeoutId = setTimeout(() => {
|
64
|
+
me.loadFiles()
|
65
|
+
}, me.preloadFilesDelay)
|
66
|
+
}
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
/**
|
71
|
+
* Triggered after the isReady config got changed
|
72
|
+
* @param {Boolean} value
|
73
|
+
* @param {Boolean} oldValue
|
74
|
+
* @protected
|
75
|
+
*/
|
76
|
+
afterSetIsReady(value, oldValue) {
|
77
|
+
if (value) {
|
78
|
+
let me = this,
|
79
|
+
returnValue;
|
80
|
+
|
81
|
+
me.cache.forEach(item => {
|
82
|
+
returnValue = me[item.fn](item.data);
|
83
|
+
item.resolve(returnValue)
|
84
|
+
});
|
85
|
+
|
86
|
+
me.cache = []
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
/**
|
91
|
+
* Internally caches call when isReady===false
|
92
|
+
* Loads the library files in case this is not already happening
|
93
|
+
* @param item
|
94
|
+
* @returns {Promise<unknown>}
|
95
|
+
*/
|
96
|
+
cacheMethodCall(item) {
|
97
|
+
let me = this;
|
98
|
+
|
99
|
+
if (!me.isLoading) {
|
100
|
+
me.loadingTimeoutId && clearTimeout(me.loadingTimeoutId);
|
101
|
+
me.loadingTimeoutId = null;
|
102
|
+
me.loadFiles()
|
103
|
+
}
|
104
|
+
|
105
|
+
return new Promise((resolve, reject) => {
|
106
|
+
me.cache.push({...item, resolve})
|
107
|
+
})
|
21
108
|
}
|
22
109
|
}
|
23
110
|
|
@@ -23,11 +23,6 @@ class HighlightJS extends Base {
|
|
23
23
|
* @protected
|
24
24
|
*/
|
25
25
|
highlightJsLineNumbersPath: Neo.config.basePath + 'node_modules/highlightjs-line-numbers.js/dist/highlightjs-line-numbers.min.js',
|
26
|
-
/**
|
27
|
-
* @member {Boolean} libraryLoaded_=true
|
28
|
-
* @protected
|
29
|
-
*/
|
30
|
-
libraryLoaded_: false,
|
31
26
|
/**
|
32
27
|
* Remote method access for other workers
|
33
28
|
* @member {Object} remote
|
@@ -36,7 +31,7 @@ class HighlightJS extends Base {
|
|
36
31
|
remote: {
|
37
32
|
app: [
|
38
33
|
'highlightAuto',
|
39
|
-
'
|
34
|
+
'loadFiles',
|
40
35
|
'scrollIntoView',
|
41
36
|
'syntaxHighlight',
|
42
37
|
'switchTheme',
|
@@ -51,43 +46,6 @@ class HighlightJS extends Base {
|
|
51
46
|
themePath: './resources/highlightjs-custom-github-theme.css'
|
52
47
|
}
|
53
48
|
|
54
|
-
/**
|
55
|
-
* @member {Object[]} cache=[]
|
56
|
-
* @protected
|
57
|
-
*/
|
58
|
-
cache = []
|
59
|
-
|
60
|
-
/**
|
61
|
-
* Triggered after the libraryLoaded config got changed
|
62
|
-
* @param {Boolean} value
|
63
|
-
* @param {Boolean} oldValue
|
64
|
-
* @protected
|
65
|
-
*/
|
66
|
-
afterSetLibraryLoaded(value, oldValue) {
|
67
|
-
if (value) {
|
68
|
-
let me = this,
|
69
|
-
returnValue;
|
70
|
-
|
71
|
-
me.cache.forEach(item => {
|
72
|
-
returnValue = me[item.fn](item.data);
|
73
|
-
item.resolve(returnValue)
|
74
|
-
});
|
75
|
-
|
76
|
-
me.cache = []
|
77
|
-
}
|
78
|
-
}
|
79
|
-
|
80
|
-
/**
|
81
|
-
* Internally caches call when the hljs namespace does not exist yet
|
82
|
-
* @param item
|
83
|
-
* @returns {Promise<unknown>}
|
84
|
-
*/
|
85
|
-
cacheMethodCall(item) {
|
86
|
-
return new Promise((resolve, reject) => {
|
87
|
-
this.cache.push({...item, resolve})
|
88
|
-
})
|
89
|
-
}
|
90
|
-
|
91
49
|
/**
|
92
50
|
* See: https://highlightjs.readthedocs.io/en/latest/api.html#highlightauto
|
93
51
|
* @param {Object} data
|
@@ -95,31 +53,42 @@ class HighlightJS extends Base {
|
|
95
53
|
* @returns {Object} of the form {language, relevance, value, secondBest}
|
96
54
|
*/
|
97
55
|
highlightAuto(data) {
|
98
|
-
if (
|
99
|
-
return hljs.highlightAuto(data.html)
|
100
|
-
} else {
|
56
|
+
if (!this.isReady) {
|
101
57
|
return this.cacheMethodCall({fn: 'highlightAuto', data})
|
102
58
|
}
|
59
|
+
|
60
|
+
return hljs.highlightAuto(data.html)
|
103
61
|
}
|
104
62
|
|
105
63
|
/**
|
106
64
|
* @param {Object} data
|
107
65
|
* @returns {Boolean}
|
108
66
|
*/
|
109
|
-
async
|
110
|
-
delete data.appName;
|
111
|
-
|
67
|
+
async loadFiles(data) {
|
112
68
|
let me = this;
|
113
69
|
|
114
|
-
me.
|
70
|
+
if (me.isLoading || me.isReady) {
|
71
|
+
return true
|
72
|
+
}
|
73
|
+
|
74
|
+
me.isLoading = true;
|
75
|
+
|
76
|
+
if (data) {
|
77
|
+
delete data.appName;
|
78
|
+
delete data.windowId;
|
79
|
+
|
80
|
+
me.set(data);
|
81
|
+
}
|
115
82
|
|
116
|
-
await DomAccess.loadScript(me.highlightJsPath)
|
117
|
-
DomAccess.addScript({src: me.highlightJsLineNumbersPath})
|
118
|
-
});
|
83
|
+
await DomAccess.loadScript(me.highlightJsPath);
|
119
84
|
|
120
|
-
|
85
|
+
await Promise.all([
|
86
|
+
DomAccess.loadScript(me.highlightJsLineNumbersPath),
|
87
|
+
Neo.main.addon.Stylesheet.createStyleSheet(null, 'hljs-theme', me.themePath)
|
88
|
+
]);
|
121
89
|
|
122
|
-
|
90
|
+
me.isLoading = false;
|
91
|
+
me.isReady = true;
|
123
92
|
|
124
93
|
return true
|
125
94
|
}
|
@@ -131,6 +100,10 @@ class HighlightJS extends Base {
|
|
131
100
|
* @protected
|
132
101
|
*/
|
133
102
|
scrollIntoView(data) {
|
103
|
+
if (!this.isReady) {
|
104
|
+
return this.cacheMethodCall({fn: 'scrollIntoView', data})
|
105
|
+
}
|
106
|
+
|
134
107
|
let parentEl = DomAccess.getElement(data.vnodeId),
|
135
108
|
el = parentEl.querySelector('[data-list-header="' + data.text + '"]');
|
136
109
|
|
@@ -162,28 +135,28 @@ class HighlightJS extends Base {
|
|
162
135
|
* @param {String} data.vnodeId
|
163
136
|
*/
|
164
137
|
syntaxHighlight(data) {
|
165
|
-
if (
|
166
|
-
let node = document.getElementById(data.vnodeId);
|
167
|
-
|
168
|
-
if (node) {
|
169
|
-
hljs.highlightBlock(node);
|
170
|
-
hljs.lineNumbersBlock(node)
|
171
|
-
}
|
172
|
-
} else {
|
138
|
+
if (!this.isReady) {
|
173
139
|
return this.cacheMethodCall({fn: 'syntaxHighlight', data})
|
174
140
|
}
|
141
|
+
|
142
|
+
let node = document.getElementById(data.vnodeId);
|
143
|
+
|
144
|
+
if (node) {
|
145
|
+
hljs.highlightBlock(node);
|
146
|
+
hljs.lineNumbersBlock(node)
|
147
|
+
}
|
175
148
|
}
|
176
149
|
|
177
150
|
/**
|
178
151
|
* @param {Object} data
|
179
152
|
*/
|
180
153
|
syntaxHighlightInit(data) {
|
181
|
-
if (
|
182
|
-
let blocks = document.querySelectorAll('pre code:not(.hljs)');
|
183
|
-
Array.prototype.forEach.call(blocks, hljs.highlightBlock)
|
184
|
-
} else {
|
154
|
+
if (!this.isReady) {
|
185
155
|
return this.cacheMethodCall({fn: 'syntaxHighlightInit', data})
|
186
156
|
}
|
157
|
+
|
158
|
+
let blocks = document.querySelectorAll('pre code:not(.hljs)');
|
159
|
+
Array.prototype.forEach.call(blocks, hljs.highlightBlock)
|
187
160
|
}
|
188
161
|
|
189
162
|
/**
|
@@ -193,7 +166,7 @@ class HighlightJS extends Base {
|
|
193
166
|
* @param {Number} data.removeLine
|
194
167
|
*/
|
195
168
|
syntaxHighlightLine(data) {
|
196
|
-
if (!
|
169
|
+
if (!this.isReady) {
|
197
170
|
return this.cacheMethodCall({fn: 'syntaxHighlightLine', data})
|
198
171
|
}
|
199
172
|
|
@@ -39,25 +39,12 @@ class MonacoEditor extends Base {
|
|
39
39
|
}
|
40
40
|
}
|
41
41
|
|
42
|
-
/**
|
43
|
-
* Will get set to true once all Monaco related files got loaded
|
44
|
-
* @member {Boolean} isReady=false
|
45
|
-
*/
|
46
|
-
isReady = false
|
47
42
|
/**
|
48
43
|
* Stores component DOM ids as keys and editor instances as values
|
49
44
|
* @member {Object} map={}
|
50
45
|
*/
|
51
46
|
map = {}
|
52
47
|
|
53
|
-
/**
|
54
|
-
* @param {Object} config
|
55
|
-
*/
|
56
|
-
construct(config) {
|
57
|
-
super.construct(config);
|
58
|
-
this.loadFiles()
|
59
|
-
}
|
60
|
-
|
61
48
|
/**
|
62
49
|
* For a complete list of options see:
|
63
50
|
* https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IEditorOptions.html
|
@@ -68,12 +55,16 @@ class MonacoEditor extends Base {
|
|
68
55
|
{id} = data,
|
69
56
|
editor;
|
70
57
|
|
71
|
-
|
72
|
-
|
58
|
+
if (!me.isReady) {
|
59
|
+
return me.cacheMethodCall({fn: 'createInstance', data})
|
60
|
+
} else {
|
61
|
+
delete data.appName;
|
62
|
+
delete data.id;
|
73
63
|
|
74
|
-
|
64
|
+
editor = me.map[id] = monaco.editor.create(DomAccess.getElement(id), data);
|
75
65
|
|
76
|
-
|
66
|
+
editor.getModel().onDidChangeContent(me.onContentChange.bind(me, id))
|
67
|
+
}
|
77
68
|
}
|
78
69
|
|
79
70
|
/**
|
@@ -81,8 +72,14 @@ class MonacoEditor extends Base {
|
|
81
72
|
* @param {String} data.id
|
82
73
|
*/
|
83
74
|
destroyInstance(data) {
|
84
|
-
|
85
|
-
|
75
|
+
let me = this;
|
76
|
+
|
77
|
+
if (!me.isReady) {
|
78
|
+
return me.cacheMethodCall({fn: 'destroyInstance', data})
|
79
|
+
} else {
|
80
|
+
// todo: destroy the editor instance if possible
|
81
|
+
delete this.map[data.id]
|
82
|
+
}
|
86
83
|
}
|
87
84
|
|
88
85
|
/**
|
@@ -91,7 +88,13 @@ class MonacoEditor extends Base {
|
|
91
88
|
* @returns {Object}
|
92
89
|
*/
|
93
90
|
getValue(data) {
|
94
|
-
|
91
|
+
let me = this;
|
92
|
+
|
93
|
+
if (!me.isReady) {
|
94
|
+
return me.cacheMethodCall({fn: 'getValue', data})
|
95
|
+
} else {
|
96
|
+
return me.map[data.id].getModel().getValue()
|
97
|
+
}
|
95
98
|
}
|
96
99
|
|
97
100
|
/**
|
@@ -100,23 +103,29 @@ class MonacoEditor extends Base {
|
|
100
103
|
* @param {String} data.id
|
101
104
|
*/
|
102
105
|
layoutEditor(data) {
|
103
|
-
this.map[data.id].layout()
|
106
|
+
this.isReady && this.map[data.id].layout()
|
104
107
|
}
|
105
108
|
|
106
109
|
/**
|
107
110
|
*
|
108
111
|
*/
|
109
112
|
async loadFiles() {
|
110
|
-
let
|
113
|
+
let me = this,
|
114
|
+
path = me.libraryBasePath;
|
115
|
+
|
116
|
+
me.isLoading = true;
|
111
117
|
|
112
118
|
window.require = {paths: {vs: path}};
|
113
119
|
|
114
|
-
await
|
115
|
-
|
116
|
-
|
117
|
-
|
120
|
+
await Promise.all([
|
121
|
+
DomAccess.loadStylesheet(path + '/editor/editor.main.css', {name: 'vs/editor/editor.main'}),
|
122
|
+
DomAccess.loadScript(path + '/loader.js'),
|
123
|
+
DomAccess.loadScript(path + '/editor/editor.main.nls.js'),
|
124
|
+
DomAccess.loadScript(path + '/editor/editor.main.js')
|
125
|
+
])
|
118
126
|
|
119
|
-
|
127
|
+
me.isLoading = false;
|
128
|
+
me.isReady = true
|
120
129
|
}
|
121
130
|
|
122
131
|
/**
|
@@ -143,7 +152,13 @@ class MonacoEditor extends Base {
|
|
143
152
|
* @param {String} data.value
|
144
153
|
*/
|
145
154
|
setLanguage(data) {
|
146
|
-
this
|
155
|
+
let me = this;
|
156
|
+
|
157
|
+
if (!me.isReady) {
|
158
|
+
return me.cacheMethodCall({fn: 'setLanguage', data})
|
159
|
+
} else {
|
160
|
+
me.map[data.id].getModel().setLanguage(data.value)
|
161
|
+
}
|
147
162
|
}
|
148
163
|
|
149
164
|
/**
|
@@ -152,7 +167,13 @@ class MonacoEditor extends Base {
|
|
152
167
|
* @param {String} data.value
|
153
168
|
*/
|
154
169
|
setTheme(data) {
|
155
|
-
this
|
170
|
+
let me = this;
|
171
|
+
|
172
|
+
if (!me.isReady) {
|
173
|
+
return me.cacheMethodCall({fn: 'setTheme', data})
|
174
|
+
} else {
|
175
|
+
me.map[data.id]._themeService.setTheme(data.value)
|
176
|
+
}
|
156
177
|
}
|
157
178
|
|
158
179
|
/**
|
@@ -161,7 +182,13 @@ class MonacoEditor extends Base {
|
|
161
182
|
* @param {String} data.value
|
162
183
|
*/
|
163
184
|
setValue(data) {
|
164
|
-
this
|
185
|
+
let me = this;
|
186
|
+
|
187
|
+
if (!me.isReady) {
|
188
|
+
return me.cacheMethodCall({fn: 'setValue', data})
|
189
|
+
} else {
|
190
|
+
me.map[data.id].getModel().setValue(data.value)
|
191
|
+
}
|
165
192
|
}
|
166
193
|
|
167
194
|
/**
|
@@ -170,7 +197,13 @@ class MonacoEditor extends Base {
|
|
170
197
|
* @param {Object} data.options
|
171
198
|
*/
|
172
199
|
updateOptions(data) {
|
173
|
-
this
|
200
|
+
let me = this;
|
201
|
+
|
202
|
+
if (!me.isReady) {
|
203
|
+
return me.cacheMethodCall({fn: 'updateOptions', data})
|
204
|
+
} else {
|
205
|
+
me.map[data.id].updateOptions(data.options)
|
206
|
+
}
|
174
207
|
}
|
175
208
|
}
|
176
209
|
|
package/src/worker/Manager.mjs
CHANGED
@@ -231,6 +231,9 @@ class Manager extends Base {
|
|
231
231
|
NeoConfig.hasMouseEvents = matchMedia('(pointer:fine)').matches;
|
232
232
|
NeoConfig.hasTouchEvents = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0);
|
233
233
|
|
234
|
+
// Useful for styling
|
235
|
+
!NeoConfig.hasMouseEvents && document.body.classList.add('neo-no-mouse');
|
236
|
+
|
234
237
|
if (window.Worker) {
|
235
238
|
me.webWorkersEnabled = true
|
236
239
|
} else {
|