neo.mjs 5.10.4 → 5.10.6

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.
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='5.10.3'
23
+ * @member {String} version='5.10.6'
24
24
  */
25
- version: '5.10.3'
25
+ version: '5.10.6'
26
26
  }
27
27
 
28
28
  /**
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='5.10.3'
23
+ * @member {String} version='5.10.6'
24
24
  */
25
- version: '5.10.3'
25
+ version: '5.10.6'
26
26
  }
27
27
 
28
28
  /**
@@ -0,0 +1,71 @@
1
+ import ConfigurationViewport from '../../ConfigurationViewport.mjs';
2
+ import NumberField from '../../../src/form/field/Number.mjs';
3
+ import Progress from '../../../src/component/Progress.mjs';
4
+ import TextField from '../../../src/form/field/Text.mjs';
5
+
6
+ /**
7
+ * @class Neo.examples.component.progress.MainContainer
8
+ * @extends Neo.examples.ConfigurationViewport
9
+ */
10
+ class MainContainer extends ConfigurationViewport {
11
+ static config = {
12
+ className : 'Neo.examples.component.progress.MainContainer',
13
+ autoMount : true,
14
+ configItemLabelWidth: 110,
15
+ configItemWidth : 230,
16
+ layout : {ntype: 'hbox', align: 'stretch'}
17
+ }
18
+
19
+ createConfigurationComponents() {
20
+ let me = this;
21
+
22
+ return [{
23
+ module : NumberField,
24
+ clearable : true,
25
+ labelText : 'height',
26
+ listeners : {change: me.onConfigChange.bind(me, 'height')},
27
+ maxValue : 100,
28
+ minValue : 20,
29
+ stepSize : 2,
30
+ style : {marginTop: '10px'},
31
+ value : me.exampleComponent.height
32
+ }, {
33
+ module : TextField,
34
+ clearable : true,
35
+ labelText : 'labelText',
36
+ listeners : {change: me.onConfigChange.bind(me, 'labelText')},
37
+ style : {marginTop: '10px'},
38
+ value : me.exampleComponent.labelText
39
+ }, {
40
+ module : NumberField,
41
+ clearable : true,
42
+ labelText : 'width',
43
+ listeners : {change: me.onConfigChange.bind(me, 'width')},
44
+ maxValue : 300,
45
+ minValue : 100,
46
+ stepSize : 5,
47
+ value : me.exampleComponent.width
48
+ }, {
49
+ module : NumberField,
50
+ clearable : true,
51
+ labelText : 'value',
52
+ listeners : {change: me.onConfigChange.bind(me, 'value')},
53
+ maxValue : 100,
54
+ minValue : 0,
55
+ value : me.exampleComponent.value
56
+ }];
57
+ }
58
+
59
+ createExampleComponent() {
60
+ return Neo.create({
61
+ module : Progress,
62
+ height : 30,
63
+ labelText: 'Hello World',
64
+ value : 40
65
+ });
66
+ }
67
+ }
68
+
69
+ Neo.applyClassConfig(MainContainer);
70
+
71
+ export default MainContainer;
@@ -0,0 +1,6 @@
1
+ import MainContainer from './MainContainer.mjs';
2
+
3
+ export const onStart = () => Neo.app({
4
+ mainView: MainContainer,
5
+ name : 'Neo.examples.component.progress'
6
+ });
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE HTML>
2
+ <html>
3
+ <head>
4
+ <meta name="viewport" content="width=device-width, initial-scale=1">
5
+ <meta charset="UTF-8">
6
+ <title>Neo Progress</title>
7
+ </head>
8
+ <body>
9
+ <script src="../../../src/MicroLoader.mjs" type="module"></script>
10
+ </body>
11
+ </html>
@@ -0,0 +1,6 @@
1
+ {
2
+ "appPath" : "examples/component/progress/app.mjs",
3
+ "basePath" : "../../../",
4
+ "environment": "development",
5
+ "mainPath" : "./Main.mjs"
6
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "5.10.4",
3
+ "version": "5.10.6",
4
4
  "description": "The webworkers driven UI framework",
5
5
  "type": "module",
6
6
  "repository": {
@@ -52,14 +52,14 @@
52
52
  "envinfo": "^7.8.1",
53
53
  "fs-extra": "^11.1.1",
54
54
  "highlightjs-line-numbers.js": "^2.8.0",
55
- "inquirer": "^9.2.6",
55
+ "inquirer": "^9.2.7",
56
56
  "neo-jsdoc": "^1.0.1",
57
57
  "neo-jsdoc-x": "^1.0.5",
58
- "postcss": "^8.4.23",
59
- "sass": "^1.62.1",
60
- "webpack": "^5.84.1",
61
- "webpack-cli": "^5.1.1",
62
- "webpack-dev-server": "4.15.0",
58
+ "postcss": "^8.4.24",
59
+ "sass": "1.62.1",
60
+ "webpack": "^5.86.0",
61
+ "webpack-cli": "^5.1.4",
62
+ "webpack-dev-server": "4.15.1",
63
63
  "webpack-hook-plugin": "^1.0.7",
64
64
  "webpack-node-externals": "^3.0.0"
65
65
  },
@@ -0,0 +1,3 @@
1
+ .neo-progress {
2
+ color: v(progress-label-color);
3
+ }
@@ -6,7 +6,17 @@
6
6
  display: none;
7
7
  }
8
8
 
9
- > div {
9
+ .neo-header-toolbar {
10
+ padding: 1em;
11
+ align-items: baseline;
12
+
13
+ .neo-dialog-header-icon {
14
+ font-size: 16px;
15
+ margin-right: .25em;
16
+ }
17
+ }
18
+
19
+ .neo-dialog-content {
10
20
  padding: 1em;
11
21
  }
12
22
  }
@@ -0,0 +1,9 @@
1
+ $neoMap: map-merge($neoMap, (
2
+ 'progress-label-color': #fff
3
+ ));
4
+
5
+ @if $useCssVars == true {
6
+ :root .neo-theme-dark {
7
+ --progress-label-color: #{neo(progress-label-color)};
8
+ }
9
+ }
@@ -0,0 +1,9 @@
1
+ $neoMap: map-merge($neoMap, (
2
+ 'progress-label-color': #000
3
+ ));
4
+
5
+ @if $useCssVars == true {
6
+ :root .neo-theme-light {
7
+ --progress-label-color: #{neo(progress-label-color)};
8
+ }
9
+ }
@@ -236,12 +236,12 @@ const DefaultConfig = {
236
236
  useVdomWorker: true,
237
237
  /**
238
238
  * buildScripts/injectPackageVersion.mjs will update this value
239
- * @default '5.10.3'
239
+ * @default '5.10.6'
240
240
  * @memberOf! module:Neo
241
241
  * @name config.version
242
242
  * @type String
243
243
  */
244
- version: '5.10.3'
244
+ version: '5.10.6'
245
245
  };
246
246
 
247
247
  Object.assign(DefaultConfig, {
@@ -0,0 +1,113 @@
1
+ import Base from '../component/Base.mjs';
2
+
3
+ /**
4
+ * @class Neo.component.Progress
5
+ * @extends Neo.component.Base
6
+ */
7
+ class Progress extends Base {
8
+ static config = {
9
+ /**
10
+ * @member {String} className='Neo.component.Progress'
11
+ * @protected
12
+ */
13
+ className: 'Neo.component.Progress',
14
+ /**
15
+ * @member {String} ntype='progress'
16
+ * @protected
17
+ */
18
+ ntype: 'progress',
19
+ /**
20
+ * @member {String[]} baseCls=['neo-progress-label']
21
+ * @protected
22
+ */
23
+ baseCls: ['neo-progress'],
24
+ /**
25
+ * @member {String|null} labelText_=null
26
+ */
27
+ labelText_: null,
28
+ /**
29
+ * @member {Number} max_=100
30
+ */
31
+ max_: 100,
32
+ /**
33
+ * @member {Number|null} value_=null
34
+ */
35
+ value_: null,
36
+ /**
37
+ * @member {Object} _vdom
38
+ */
39
+ _vdom:
40
+ {tag: 'div', cls: ['neo-progress'], cn: [
41
+ {tag: 'label'},
42
+ {tag: 'progress'}
43
+ ]}
44
+ }
45
+
46
+ /**
47
+ * Triggered after the id config got changed
48
+ * @param {String} value
49
+ * @param {String} oldValue
50
+ * @protected
51
+ */
52
+ afterSetId(value, oldValue) {
53
+ super.afterSetId(value, oldValue);
54
+
55
+ this.vdom.cn[0].for = value;
56
+ this.update()
57
+ }
58
+
59
+ /**
60
+ * Triggered after the labelText config got changed
61
+ * @param {String|null} value
62
+ * @param {String|null} oldValue
63
+ * @protected
64
+ */
65
+ afterSetLabelText(value, oldValue) {
66
+ this.vdom.cn[0].html = value;
67
+ this.update()
68
+ }
69
+
70
+ /**
71
+ * Triggered after the max config got changed
72
+ * @param {Number} value
73
+ * @param {Number} oldValue
74
+ * @protected
75
+ */
76
+ afterSetMax(value, oldValue) {
77
+ this.vdom.cn[1].max = value;
78
+ this.update()
79
+ }
80
+
81
+ /**
82
+ * Triggered after the value config got changed
83
+ * @param {Number|null} value
84
+ * @param {Number|null} oldValue
85
+ * @protected
86
+ */
87
+ afterSetValue(value, oldValue) {
88
+ this.vdom.cn[1].value = value;
89
+ this.update()
90
+ }
91
+
92
+ /**
93
+ * Specify a different vdom root if needed to apply the top level style attributes on a different level.
94
+ * Make sure to use getVnodeRoot() as well, to keep the vdom & vnode trees in sync.
95
+ * @returns {Object} The new vdom root
96
+ */
97
+ getVdomRoot() {
98
+ return this.vdom.cn[1]
99
+ }
100
+
101
+ /**
102
+ * Specify a different vnode root if needed to apply the top level style attributes on a different level.
103
+ * Make sure to use getVdomRoot() as well, to keep the vdom & vnode trees in sync.
104
+ * @returns {Object} The new vnode root
105
+ */
106
+ getVnodeRoot() {
107
+ return this.vnode.childNodes[1]
108
+ }
109
+ }
110
+
111
+ Neo.applyClassConfig(Progress);
112
+
113
+ export default Progress;
@@ -21,9 +21,17 @@ class Dialog extends Base {
21
21
  */
22
22
  ntype: 'container-dialog',
23
23
  /**
24
- * @member {String[]} baseCls=['container-dialog']
25
- * @protected
26
- */
24
+ * @member {Boolean} autoMount=true
25
+ */
26
+ autoMount: true,
27
+ /**
28
+ * @member {Boolean} autoRender=true
29
+ */
30
+ autoRender: true,
31
+ /**
32
+ * @member {String[]} baseCls=['neo-container-dialog', 'neo-panel', 'neo-container']
33
+ * @protected
34
+ */
27
35
  baseCls: ['neo-container-dialog', 'neo-panel', 'neo-container'],
28
36
  /**
29
37
  * @member {Object} headerConfig=null
@@ -34,10 +42,16 @@ class Dialog extends Base {
34
42
  */
35
43
  headerToolbar: null,
36
44
  /**
37
- * The CSS class to use for an icon, e.g. 'fa fa-home'
38
- * @member {String|null} [iconCls_=null]
45
+ * The CSS class to use for an icon, e.g. ['fa', 'fa-home']
46
+ * @member {String[]} [iconCls_=null]
39
47
  */
40
48
  iconCls_: null,
49
+ /**
50
+ * @member {Object} itemDefaults
51
+ */
52
+ itemDefaults: {
53
+ baseCls: ['neo-dialog-content']
54
+ },
41
55
  /**
42
56
  * @member {Object[]} items
43
57
  */
@@ -68,11 +82,9 @@ class Dialog extends Base {
68
82
  * @protected
69
83
  */
70
84
  afterSetIconCls(value, oldValue) {
71
- console.log(value, oldValue)
72
-
73
85
  if (!this.headers) { return }
74
- let iconNode = this.headers.down({flag: 'dialog-header-icon'});
75
- let iconNodeCls = [...iconNode.cls];
86
+ let iconNode = this.headers.down({flag: 'dialog-header-icon'}),
87
+ iconNodeCls = [...iconNode.cls];
76
88
 
77
89
  NeoArray.remove(iconNodeCls, oldValue);
78
90
  NeoArray.add( iconNodeCls, value);
@@ -90,41 +102,11 @@ class Dialog extends Base {
90
102
  * @protected
91
103
  */
92
104
  afterSetTitle(value, oldValue) {
93
- this.headerToolbar?.set({
94
- title: value
105
+ this.headerToolbar?.down({flag: 'panel-header-title'}).set({
106
+ text: value
95
107
  });
96
108
  }
97
109
 
98
- /**
99
- * Converts the iconCls array into a string on beforeGet
100
- * @returns {String}
101
- * @protected
102
- */
103
- beforeGetIconCls() {
104
- let iconCls = this._iconCls;
105
-
106
- if (Array.isArray(iconCls)) {
107
- return iconCls.join(' ');
108
- }
109
-
110
- return iconCls;
111
- }
112
-
113
- /**
114
- * Triggered before the iconCls config gets changed. Converts the string into an array if needed.
115
- * @param {Array|String|null} value
116
- * @param {Array|String|null} oldValue
117
- * @returns {Array}
118
- * @protected
119
- */
120
- beforeSetIconCls(value, oldValue) {
121
- if (value && !Array.isArray(value)) {
122
- value = value.split(' ').filter(Boolean);
123
- }
124
-
125
- return value;
126
- }
127
-
128
110
  /**
129
111
  * close the dialog in main thread
130
112
  */
@@ -141,15 +123,15 @@ class Dialog extends Base {
141
123
  * @protected
142
124
  */
143
125
  createHeader() {
144
- let me = this,
145
- cls = ['neo-header-toolbar', 'neo-toolbar'],
146
- headers = me.headers || [],
126
+ let me = this,
127
+ cls = ['neo-header-toolbar', 'neo-toolbar'],
128
+ headers = me.headers || [],
147
129
  headerConfigCopy = {...me.headerConfig};
148
130
  delete headerConfigCopy.items;
149
131
 
150
132
  me.headerToolbar = Neo.create({
151
133
  module : HeaderToolbar,
152
- actions: [{action: 'close', iconCls: 'fa-solid fa-xmark'}],
134
+ actions : [{action: 'close', iconCls: 'fa-solid fa-xmark'}],
153
135
  appName : me.appName,
154
136
  cls,
155
137
  dock : 'top',
@@ -157,15 +139,16 @@ class Dialog extends Base {
157
139
  id : me.getHeaderToolbarId(),
158
140
  listeners: {headerAction: me.executeHeaderAction, scope: me},
159
141
  items : [{
160
- cls: me.iconCls,
161
- flag : 'dialog-header-icon',
142
+ ntype: '',
143
+ cls : ['neo-dialog-header-icon', ...me.iconCls],
144
+ flag : 'dialog-header-icon',
162
145
  }, {
163
- ntype : 'label',
164
- cls : ['neo-panel-header-text', 'neo-label'],
165
- flag : 'title-label',
166
- removeDom: !me.title,
167
- text : me.title
168
- }, ...me.headerConfig.items],
146
+ ntype : 'label',
147
+ cls : ['neo-panel-header-text', 'neo-label'],
148
+ flag : 'panel-header-title',
149
+ hidden: !me.title,
150
+ text : me.title
151
+ }, ...me.headerConfig.items || []],
169
152
 
170
153
  ...headerConfigCopy
171
154
  });
@@ -182,7 +165,7 @@ class Dialog extends Base {
182
165
  let me = this,
183
166
 
184
167
  map = {
185
- close : me.close
168
+ close: me.close
186
169
  };
187
170
 
188
171
  map[data.action]?.call(me, data);
@@ -1,4 +1,5 @@
1
- import Text from './Text.mjs';
1
+ import StringUtil from '../../util/String.mjs';
2
+ import Text from './Text.mjs';
2
3
 
3
4
  /**
4
5
  *
@@ -121,7 +122,7 @@ class TextArea extends Text {
121
122
  let inputEl = this.getInputEl();
122
123
 
123
124
  if (inputEl) {
124
- inputEl.html = value;
125
+ inputEl.html = StringUtil.escapeHtml(value);
125
126
  }
126
127
 
127
128
  super.afterSetValue(value, oldValue);
@@ -1,5 +1,6 @@
1
1
  import Base from '../core/Base.mjs';
2
2
  import Observable from '../core/Observable.mjs';
3
+ import StringUtil from '../util/String.mjs';
3
4
  import TouchDomEvents from './mixin/TouchDomEvents.mjs';
4
5
 
5
6
  const globalDomEvents = [
@@ -415,7 +416,7 @@ class DomEvents extends Base {
415
416
  data = {
416
417
  ...this.getEventData(event),
417
418
  valid: target.checkValidity(),
418
- value: target.value
419
+ value: (target.tagName === 'INPUT') ? StringUtil.escapeHtml(target.value) : target.value
419
420
  };
420
421
 
421
422
  // input and change events can pass a FileList for input type file
@@ -0,0 +1,56 @@
1
+ import Base from '../core/Base.mjs';
2
+
3
+ /**
4
+ * @class Neo.util.StringUtil
5
+ * @extends Neo.core.Base
6
+ */
7
+ class StringUtil extends Base {
8
+ static config = {
9
+ /**
10
+ * @member {String} className='Neo.util.StringUtil'
11
+ * @protected
12
+ */
13
+ className: 'Neo.util.StringUtil'
14
+ }
15
+
16
+ static escapedChars = {
17
+ '&': '&amp;',
18
+ '<': '&lt;',
19
+ '>': '&gt;',
20
+ '"': '&quot;',
21
+ '\'': '&#039;'
22
+ }
23
+
24
+ /**
25
+ * Escape HTML special characters
26
+ * @param {String} value
27
+ */
28
+ static escapeHtml(value) {
29
+ if (Neo.typeOf(value) !== 'String') {
30
+ return value;
31
+ }
32
+
33
+ return value.replace(/[&<>"']/g, (char) => this.escapedChars[char] || char);
34
+ }
35
+
36
+ /**
37
+ * Unescape HTML special characters
38
+ * @param {String} value
39
+ */
40
+ static unescapeHtml(value) {
41
+ if (Neo.typeOf(value) !== 'String') {
42
+ return value;
43
+ }
44
+
45
+ return value.replace(/(&amp;)|(&lt;)|(&gt;)|(&quot;)|(&#039;)/g, (entity) => this.getKeyByValue(entity) || entity);
46
+ }
47
+
48
+ static getKeyByValue(value) {
49
+ return Object.keys(this.escapedChars).find(key => this.escapedChars[key] === value);
50
+ }
51
+ }
52
+
53
+
54
+ Neo.applyClassConfig(StringUtil);
55
+
56
+ export default StringUtil;