neo.mjs 5.10.12 → 5.11.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/examples/ServiceWorker.mjs +2 -2
- package/examples/component/dateSelector/MainContainer.mjs +16 -3
- package/examples/component/timer/MainContainer.mjs +71 -0
- package/examples/component/timer/MainContainerController.mjs +95 -0
- package/examples/component/timer/app.mjs +7 -0
- package/examples/component/timer/index.html +12 -0
- package/examples/component/timer/neo-config.json +7 -0
- package/examples/layout/form/MainContainer.mjs +131 -0
- package/examples/layout/form/app.mjs +6 -0
- package/examples/layout/form/index.html +11 -0
- package/examples/layout/form/neo-config.json +6 -0
- package/examples/table/container/MainContainer.mjs +6 -0
- package/package.json +3 -3
- package/resources/scss/src/component/Timer.scss +115 -0
- package/resources/scss/src/layout/Form.scss +27 -0
- package/resources/scss/theme-dark/component/Timer.scss +14 -0
- package/resources/scss/theme-light/component/Timer.scss +15 -0
- package/src/DefaultConfig.mjs +2 -2
- package/src/component/DateSelector.mjs +44 -10
- package/src/component/Timer.mjs +328 -0
- package/src/form/field/Date.mjs +42 -0
- package/src/form/field/Text.mjs +2 -2
- package/src/layout/Flexbox.mjs +21 -0
- package/src/layout/Form.mjs +140 -0
- package/src/table/Container.mjs +17 -0
- package/src/table/header/Button.mjs +36 -9
- package/src/table/header/Toolbar.mjs +26 -1
@@ -75,6 +75,14 @@ class DateSelector extends Component {
|
|
75
75
|
* @member {String} locale_=Neo.config.locale
|
76
76
|
*/
|
77
77
|
locale_: Neo.config.locale,
|
78
|
+
/**
|
79
|
+
* @member {String|null} maxValue_=null
|
80
|
+
*/
|
81
|
+
maxValue_: null,
|
82
|
+
/**
|
83
|
+
* @member {String|null} minValue_=null
|
84
|
+
*/
|
85
|
+
minValue_: null,
|
78
86
|
/**
|
79
87
|
* Used for wheel events. min value = 1.
|
80
88
|
* A higher value means lesser sensitivity for wheel events
|
@@ -241,6 +249,26 @@ class DateSelector extends Component {
|
|
241
249
|
}
|
242
250
|
}
|
243
251
|
|
252
|
+
/**
|
253
|
+
* Triggered after the maxValue config got changed
|
254
|
+
* @param {Text} value
|
255
|
+
* @param {Text} oldValue
|
256
|
+
* @protected
|
257
|
+
*/
|
258
|
+
afterSetMaxValue(value, oldValue) {
|
259
|
+
oldValue !== undefined && this.recreateDayViewContent()
|
260
|
+
}
|
261
|
+
|
262
|
+
/**
|
263
|
+
* Triggered after the minValue config got changed
|
264
|
+
* @param {Text} value
|
265
|
+
* @param {Text} oldValue
|
266
|
+
* @protected
|
267
|
+
*/
|
268
|
+
afterSetMinValue(value, oldValue) {
|
269
|
+
oldValue !== undefined && this.recreateDayViewContent()
|
270
|
+
}
|
271
|
+
|
244
272
|
/**
|
245
273
|
* Triggered after the showCellBorders config got changed
|
246
274
|
* @param {Boolean} value
|
@@ -262,7 +290,7 @@ class DateSelector extends Component {
|
|
262
290
|
* @protected
|
263
291
|
*/
|
264
292
|
afterSetShowDisabledDays(value, oldValue) {
|
265
|
-
oldValue !== undefined && this.recreateDayViewContent()
|
293
|
+
oldValue !== undefined && this.recreateDayViewContent()
|
266
294
|
}
|
267
295
|
|
268
296
|
/**
|
@@ -566,6 +594,8 @@ class DateSelector extends Component {
|
|
566
594
|
currentMonth = currentDate.getMonth(),
|
567
595
|
currentYear = currentDate.getFullYear(),
|
568
596
|
date = me.currentDate, // cloned
|
597
|
+
maxDate = me.maxValue && new Date(`${me.maxValue}T00:00:00.000Z`),
|
598
|
+
minDate = me.minValue && new Date(`${me.minValue}T00:00:00.000Z`),
|
569
599
|
valueDate = new Date(`${me.value}T00:00:00.000Z`),
|
570
600
|
valueMonth = valueDate.getMonth(),
|
571
601
|
valueYear = valueDate.getFullYear(),
|
@@ -612,23 +642,27 @@ class DateSelector extends Component {
|
|
612
642
|
config.cls.push('neo-weekend');
|
613
643
|
}
|
614
644
|
|
645
|
+
if (maxDate && date > maxDate || minDate && date < minDate) {
|
646
|
+
NeoArray.add(config.cls, 'neo-disabled')
|
647
|
+
}
|
648
|
+
|
615
649
|
if (today.year === currentYear && today.month === currentMonth && today.day === day) {
|
616
|
-
config.cn[0].cls.push('neo-today')
|
650
|
+
config.cn[0].cls.push('neo-today')
|
617
651
|
}
|
618
652
|
|
619
653
|
if (valueYear === currentYear && valueMonth === currentMonth && day === currentDay) {
|
620
654
|
config.cls.push('neo-selected');
|
621
|
-
me.selectionModel.items = [cellId]
|
655
|
+
me.selectionModel.items = [cellId] // silent update
|
622
656
|
}
|
623
657
|
|
624
658
|
row.cn.push(config);
|
625
659
|
|
626
660
|
date.setDate(date.getDate() + 1);
|
627
661
|
|
628
|
-
day
|
662
|
+
day++
|
629
663
|
}
|
630
664
|
|
631
|
-
centerEl.cn.push(row)
|
665
|
+
centerEl.cn.push(row)
|
632
666
|
}
|
633
667
|
|
634
668
|
!silent && me.update()
|
@@ -638,7 +672,7 @@ class DateSelector extends Component {
|
|
638
672
|
*
|
639
673
|
*/
|
640
674
|
focusCurrentItem() {
|
641
|
-
this.focus(this.selectionModel.items[0])
|
675
|
+
this.focus(this.selectionModel.items[0])
|
642
676
|
}
|
643
677
|
|
644
678
|
/**
|
@@ -752,7 +786,7 @@ class DateSelector extends Component {
|
|
752
786
|
*/
|
753
787
|
onConstructed() {
|
754
788
|
super.onConstructed();
|
755
|
-
this.selectionModel?.register(this)
|
789
|
+
this.selectionModel?.register(this)
|
756
790
|
}
|
757
791
|
|
758
792
|
/**
|
@@ -777,7 +811,7 @@ class DateSelector extends Component {
|
|
777
811
|
monthIncrement !== 0 && me.updateHeaderMonth(monthIncrement, yearIncrement, true);
|
778
812
|
yearIncrement !== 0 && me.updateHeaderYear(yearIncrement, true);
|
779
813
|
|
780
|
-
me.triggerVdomUpdate(silent)
|
814
|
+
me.triggerVdomUpdate(silent)
|
781
815
|
}
|
782
816
|
|
783
817
|
/**
|
@@ -793,10 +827,10 @@ class DateSelector extends Component {
|
|
793
827
|
me.createDayViewContent(true);
|
794
828
|
|
795
829
|
if (syncIds) {
|
796
|
-
me.syncVdomIds()
|
830
|
+
me.syncVdomIds()
|
797
831
|
}
|
798
832
|
|
799
|
-
me.triggerVdomUpdate(silent)
|
833
|
+
me.triggerVdomUpdate(silent)
|
800
834
|
}
|
801
835
|
|
802
836
|
/**
|
@@ -0,0 +1,328 @@
|
|
1
|
+
import Component from './Base.mjs';
|
2
|
+
import NeoArray from '../util/Array.mjs';
|
3
|
+
|
4
|
+
/**
|
5
|
+
* @class Neo.component.Timer
|
6
|
+
* @extends Neo.component.Base
|
7
|
+
*/
|
8
|
+
class Timer extends Component {
|
9
|
+
static config = {
|
10
|
+
/**
|
11
|
+
* @member {String} className='Neo.component.Timer'
|
12
|
+
* @protected
|
13
|
+
*/
|
14
|
+
className: 'Neo.component.Timer',
|
15
|
+
/**
|
16
|
+
* @member {String} ntype='timer'
|
17
|
+
* @protected
|
18
|
+
*/
|
19
|
+
ntype: 'timer',
|
20
|
+
/**
|
21
|
+
* CSS selectors to apply to the root level node of this component
|
22
|
+
* @member {String[]} baseCls=['timer']
|
23
|
+
*/
|
24
|
+
baseCls: ['neo-timer'],
|
25
|
+
/**
|
26
|
+
* End color of the circle. If not set, it uses the css default
|
27
|
+
* @member {Number|String} colorEnd_=null
|
28
|
+
*/
|
29
|
+
colorEnd_: null,
|
30
|
+
/**
|
31
|
+
* Start color of the circle. If not set, it uses the css default
|
32
|
+
* @member {Number|String} colorStart_=null
|
33
|
+
*/
|
34
|
+
colorStart_: null,
|
35
|
+
/**
|
36
|
+
* Start time. This might be '5m', '30s' or milliseconds as number
|
37
|
+
* @member {Number|String} duration_='5m'
|
38
|
+
*/
|
39
|
+
duration_: '10m',
|
40
|
+
/**
|
41
|
+
* Defines height and min-width. This can be a number in px or a string.
|
42
|
+
* @member {Number|String} dimensions_='6rem'
|
43
|
+
*/
|
44
|
+
dimensions_: '8em',
|
45
|
+
/**
|
46
|
+
* Helper to keep running smooth at minimum cost
|
47
|
+
* @member {Object} timer={}
|
48
|
+
* @member {Number|null} timer.currentSecond =null // run only once per second
|
49
|
+
* @member {Number|null} timer.intervalId =null // setInterval id
|
50
|
+
* @member {Boolean} timer.running =false// keeps track if timer/entry is up
|
51
|
+
* @member {Number|null} timer.startTime =null // calc the current progress
|
52
|
+
*/
|
53
|
+
timer: {
|
54
|
+
currentSecond: null,
|
55
|
+
intervalId : null,
|
56
|
+
running : false,
|
57
|
+
startTime : null
|
58
|
+
},
|
59
|
+
/**
|
60
|
+
* The vdom markup for this component.
|
61
|
+
* @member {Object} vdom={}
|
62
|
+
*/
|
63
|
+
vdom: {
|
64
|
+
cn: [
|
65
|
+
{cls: 'countdown', cn : [
|
66
|
+
{tag: 'svg', cls: 'clock', viewBox: "-50 -50 100 100", strokeWidth: "10", cn: [
|
67
|
+
{tag: 'circle', r: 45},
|
68
|
+
{tag: 'circle', r: 45,pathLength: 1}
|
69
|
+
]},
|
70
|
+
{cls: ['flip-card'], cn : [
|
71
|
+
{cls: 'flip-card-inner enter-mask', cn : [
|
72
|
+
{cls: 'flip-card-front', cn : [
|
73
|
+
{tag: 'input', cls: 'enter-time'},
|
74
|
+
{tag: 'button',cls: 'fa fa-play'}
|
75
|
+
]},
|
76
|
+
{cls: 'flip-card-back', cn : [
|
77
|
+
{cls : 'runner', html: '00:00'}
|
78
|
+
]}
|
79
|
+
]}
|
80
|
+
]}
|
81
|
+
]}
|
82
|
+
]
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
/**
|
87
|
+
* @param {Object} config
|
88
|
+
*/
|
89
|
+
construct(config) {
|
90
|
+
super.construct(config);
|
91
|
+
|
92
|
+
let me = this;
|
93
|
+
|
94
|
+
me.addDomListeners([
|
95
|
+
{click: me.onTimerClick, delegate: 'flip-card-back'},
|
96
|
+
{click: me.onTimerClick, delegate: 'fa fa-play'},
|
97
|
+
{input: me.onTimerInput, delegate: 'enter-time'},
|
98
|
+
{focusout: me.onTimerInput, delegate: 'enter-time'},
|
99
|
+
{keydown: me.onFieldKeyDown, delegate: 'enter-time'}
|
100
|
+
]);
|
101
|
+
}
|
102
|
+
|
103
|
+
/**
|
104
|
+
* Triggered after the dimensions config got changed
|
105
|
+
* @param {Number|String} value
|
106
|
+
* @param {Number|String} oldValue
|
107
|
+
* @protected
|
108
|
+
*/
|
109
|
+
afterSetDimensions(value, oldValue) {
|
110
|
+
if (typeof value === 'number') {
|
111
|
+
value = value + 'px';
|
112
|
+
}
|
113
|
+
this.updateProperties({dimensions: value});
|
114
|
+
}
|
115
|
+
|
116
|
+
/**
|
117
|
+
* Triggered after the colorStart config got changed
|
118
|
+
* @param {String|null} value
|
119
|
+
* @param {String|null} oldValue
|
120
|
+
* @protected
|
121
|
+
*/
|
122
|
+
afterSetColorStart(value, oldValue) {
|
123
|
+
if (!value) return;
|
124
|
+
this.updateProperties({colorStart: value});
|
125
|
+
}
|
126
|
+
|
127
|
+
/**
|
128
|
+
* Triggered after the colorEnd config got changed
|
129
|
+
* @param {String|null} value
|
130
|
+
* @param {String|null} oldValue
|
131
|
+
* @protected
|
132
|
+
*/
|
133
|
+
afterSetColorEnd(value, oldValue) {
|
134
|
+
if (!value) return;
|
135
|
+
this.updateProperties({colorEnd: value});
|
136
|
+
}
|
137
|
+
|
138
|
+
/**
|
139
|
+
* Triggered before the duration config got changed
|
140
|
+
* @param {Number|String} value
|
141
|
+
* @param {Number|String} oldValue
|
142
|
+
* @protected
|
143
|
+
*/
|
144
|
+
beforeSetDuration(value, oldValue) {
|
145
|
+
const me = this;
|
146
|
+
|
147
|
+
me.updateInputField(value)
|
148
|
+
|
149
|
+
if (typeof value === 'string') {
|
150
|
+
const durationType = value.at(-1);
|
151
|
+
|
152
|
+
if (durationType === 'm') {
|
153
|
+
value = value.split('m')[0] * 60 * 1000;
|
154
|
+
} else if (durationType === 's') {
|
155
|
+
value = value.split('s')[0] * 1000;
|
156
|
+
}
|
157
|
+
}
|
158
|
+
|
159
|
+
me.updateProperties({full: value});
|
160
|
+
|
161
|
+
return value;
|
162
|
+
}
|
163
|
+
|
164
|
+
/**
|
165
|
+
* Check if Enter was pressed
|
166
|
+
* @param {Object} data
|
167
|
+
*/
|
168
|
+
onFieldKeyDown(data) {
|
169
|
+
const me = this;
|
170
|
+
|
171
|
+
if (data.key === 'Enter') {
|
172
|
+
me.duration = me.timer.entry;
|
173
|
+
me.onTimerClick();
|
174
|
+
}
|
175
|
+
}
|
176
|
+
|
177
|
+
/**
|
178
|
+
* Click on Play or Timer
|
179
|
+
*/
|
180
|
+
onTimerClick() {
|
181
|
+
const me = this;
|
182
|
+
|
183
|
+
// If the timer is running, stop and clear it
|
184
|
+
if (me.timer.intervalId) {
|
185
|
+
me.toggleTimer(false);
|
186
|
+
me.resetTimer();
|
187
|
+
} else {
|
188
|
+
// prepare
|
189
|
+
me.timer.startTime = new Date().getTime();
|
190
|
+
|
191
|
+
me.timer.intervalId = setInterval(function () {
|
192
|
+
const startTime = me.timer.startTime,
|
193
|
+
curTime = new Date().getTime(),
|
194
|
+
totalTime = me.duration,
|
195
|
+
endTime = startTime + totalTime;
|
196
|
+
|
197
|
+
if (curTime > endTime) {
|
198
|
+
me.toggleTimer(false);
|
199
|
+
me.resetTimer();
|
200
|
+
} else {
|
201
|
+
const milliseconds = endTime - curTime,
|
202
|
+
secondsLeft = Math.floor(milliseconds / 1000);
|
203
|
+
let secondsNow = secondsLeft % 60,
|
204
|
+
minutesNow = Math.floor(secondsLeft / 60)
|
205
|
+
|
206
|
+
// Ensure this does not run 10 times a second
|
207
|
+
if (secondsNow !== me.timer.currentSecond) {
|
208
|
+
me.timer.currentSecond = secondsNow;
|
209
|
+
|
210
|
+
secondsNow = secondsNow.toString().padStart(2, '0');
|
211
|
+
minutesNow = minutesNow.toString().padStart(2, '0');
|
212
|
+
|
213
|
+
me.updateTimer(`${minutesNow}:${secondsNow}`);
|
214
|
+
me.updateProperties({current: milliseconds});
|
215
|
+
me.toggleTimer(true);
|
216
|
+
}
|
217
|
+
}
|
218
|
+
}, 100);
|
219
|
+
}
|
220
|
+
}
|
221
|
+
|
222
|
+
/**
|
223
|
+
* On change event of the textfield
|
224
|
+
* @param {Object} data
|
225
|
+
*/
|
226
|
+
onTimerInput(data) {
|
227
|
+
const me = this;
|
228
|
+
|
229
|
+
if (data.value) {
|
230
|
+
me.timer.entry = data.value
|
231
|
+
} else {
|
232
|
+
me.duration = me.timer.entry;
|
233
|
+
}
|
234
|
+
}
|
235
|
+
|
236
|
+
/**
|
237
|
+
* Reset the properties, timer and remove Interval
|
238
|
+
*/
|
239
|
+
resetTimer() {
|
240
|
+
const me = this;
|
241
|
+
|
242
|
+
me.updateProperties({current: ''});
|
243
|
+
me.updateTimer('00:00');
|
244
|
+
|
245
|
+
clearInterval(me.timer.intervalId);
|
246
|
+
delete me.timer.intervalId;
|
247
|
+
}
|
248
|
+
|
249
|
+
/**
|
250
|
+
* Flip over the timer face
|
251
|
+
* @param {Boolean} doShow
|
252
|
+
*/
|
253
|
+
toggleTimer(doShow) {
|
254
|
+
if(this.running === doShow) return;
|
255
|
+
|
256
|
+
let me = this,
|
257
|
+
turnFn = doShow ? 'add' : 'remove',
|
258
|
+
vdom = me.vdom,
|
259
|
+
flipCard = vdom.cn[0].cn[1];
|
260
|
+
|
261
|
+
me.running = doShow;
|
262
|
+
|
263
|
+
flipCard.cls = flipCard.cls || [];
|
264
|
+
|
265
|
+
NeoArray[turnFn](flipCard.cls, 'turn');
|
266
|
+
me.vdom = vdom;
|
267
|
+
}
|
268
|
+
|
269
|
+
/**
|
270
|
+
* Write to the input field
|
271
|
+
* @param {String} value
|
272
|
+
*/
|
273
|
+
updateInputField(value) {
|
274
|
+
let me = this,
|
275
|
+
vdom = me.vdom,
|
276
|
+
inputField = vdom.cn[0].cn[1].cn[0].cn[0].cn[0];
|
277
|
+
|
278
|
+
inputField.value = value;
|
279
|
+
}
|
280
|
+
|
281
|
+
/**
|
282
|
+
* Update the timer, typically once per second
|
283
|
+
* @param {String} value
|
284
|
+
*/
|
285
|
+
updateTimer(value) {
|
286
|
+
let me = this,
|
287
|
+
vdom = me.vdom,
|
288
|
+
timer = vdom.cn[0].cn[1].cn[0].cn[1].cn[0];
|
289
|
+
|
290
|
+
timer.innerHTML = value;
|
291
|
+
me.vdom = vdom;
|
292
|
+
}
|
293
|
+
|
294
|
+
/**
|
295
|
+
* Update the css properties
|
296
|
+
* - current amount of seconds left
|
297
|
+
* - full amount of time
|
298
|
+
* - size of the timer
|
299
|
+
* @param {Object} properties
|
300
|
+
*/
|
301
|
+
updateProperties(properties) {
|
302
|
+
// Neo.setCssVariable({key: '--neo-timer-full', value: '\'200\''});
|
303
|
+
let me = this,
|
304
|
+
style = me.style;
|
305
|
+
|
306
|
+
if (properties.current !== undefined) {
|
307
|
+
style['--neo-timer-current'] = `${properties.current}!important`;
|
308
|
+
}
|
309
|
+
if (properties.full !== undefined) {
|
310
|
+
style['--neo-timer-full'] = `${properties.full}!important`;
|
311
|
+
}
|
312
|
+
if (properties.colorEnd !== undefined) {
|
313
|
+
style['--timer-color-end'] = `${properties.colorEnd}!important`;
|
314
|
+
}
|
315
|
+
if (properties.colorStart !== undefined) {
|
316
|
+
style['--timer-color-start'] = `${properties.colorStart}!important`;
|
317
|
+
}
|
318
|
+
if (properties.dimensions !== undefined) {
|
319
|
+
style['--timer-dimension'] = `${properties.dimensions}!important`;
|
320
|
+
}
|
321
|
+
|
322
|
+
me.style = style;
|
323
|
+
}
|
324
|
+
}
|
325
|
+
|
326
|
+
Neo.applyClassConfig(Timer);
|
327
|
+
|
328
|
+
export default Timer;
|
package/src/form/field/Date.mjs
CHANGED
@@ -42,6 +42,14 @@ class DateField extends Picker {
|
|
42
42
|
* @member {String} inputType='date'
|
43
43
|
*/
|
44
44
|
inputType: 'date',
|
45
|
+
/**
|
46
|
+
* @member {String|null} maxValue_=null
|
47
|
+
*/
|
48
|
+
maxValue_: null,
|
49
|
+
/**
|
50
|
+
* @member {String|null} minValue_=null
|
51
|
+
*/
|
52
|
+
minValue_: null,
|
45
53
|
/**
|
46
54
|
* @member {Number} pickerHeight=225
|
47
55
|
*/
|
@@ -79,6 +87,8 @@ class DateField extends Picker {
|
|
79
87
|
|
80
88
|
me.dateSelector = Neo.create(DateSelector, {
|
81
89
|
dayNameFormat: 'short',
|
90
|
+
maxValue : me.maxValue,
|
91
|
+
minValue : me.minValue,
|
82
92
|
value : me.value || DateUtil.convertToyyyymmdd(new Date()),
|
83
93
|
...me.dateSelectorConfig
|
84
94
|
});
|
@@ -93,6 +103,38 @@ class DateField extends Picker {
|
|
93
103
|
});
|
94
104
|
}
|
95
105
|
|
106
|
+
/**
|
107
|
+
* Triggered after the maxValue config got changed
|
108
|
+
* @param {Text} value
|
109
|
+
* @param {Text} oldValue
|
110
|
+
* @protected
|
111
|
+
*/
|
112
|
+
afterSetMaxValue(value, oldValue) {
|
113
|
+
let me = this;
|
114
|
+
|
115
|
+
me.changeInputElKey('max', value);
|
116
|
+
|
117
|
+
if (me.dateSelector) {
|
118
|
+
me.dateSelector.maxValue = value
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
/**
|
123
|
+
* Triggered after the minValue config got changed
|
124
|
+
* @param {Text} value
|
125
|
+
* @param {Text} oldValue
|
126
|
+
* @protected
|
127
|
+
*/
|
128
|
+
afterSetMinValue(value, oldValue) {
|
129
|
+
let me = this;
|
130
|
+
|
131
|
+
me.changeInputElKey('max', value);
|
132
|
+
|
133
|
+
if (me.dateSelector) {
|
134
|
+
me.dateSelector.minValue = value
|
135
|
+
}
|
136
|
+
}
|
137
|
+
|
96
138
|
/**
|
97
139
|
* Triggered after the value config got changed
|
98
140
|
* @param {String} value
|
package/src/form/field/Text.mjs
CHANGED
@@ -115,9 +115,9 @@ class Text extends Base {
|
|
115
115
|
* If false, the inputPattern will only get validated via JavaScript, but not getting applied on DOM level.
|
116
116
|
* The regex support for input based patterns is not fully there yet, so feel free to disable this feature
|
117
117
|
* if needed (E.g. form.field.Phone).
|
118
|
-
* @member {Boolean}
|
118
|
+
* @member {Boolean} inputPatternDOM_=true
|
119
119
|
*/
|
120
|
-
|
120
|
+
inputPatternDOM_: true,
|
121
121
|
/**
|
122
122
|
* @member {String} inputType_='text'
|
123
123
|
*/
|
package/src/layout/Flexbox.mjs
CHANGED
@@ -56,6 +56,11 @@ class Flexbox extends Base {
|
|
56
56
|
* @member {String|null} direction_=null
|
57
57
|
*/
|
58
58
|
direction_: null,
|
59
|
+
/**
|
60
|
+
* flex css allows gap. This adds it to the component style
|
61
|
+
* @member {String} gap_=null
|
62
|
+
*/
|
63
|
+
gap_: null,
|
59
64
|
/**
|
60
65
|
* Valid values: 'center', 'end', 'start', null
|
61
66
|
* @member {String|null} pack_=null
|
@@ -93,6 +98,22 @@ class Flexbox extends Base {
|
|
93
98
|
oldValue && this.updateInputValue(value, oldValue, 'direction');
|
94
99
|
}
|
95
100
|
|
101
|
+
/**
|
102
|
+
* Updates the Container style to add a gap to display:flex
|
103
|
+
* @param {String|null} value
|
104
|
+
* @param {String|null} oldValue
|
105
|
+
* @protected
|
106
|
+
*/
|
107
|
+
afterSetGap(value, oldValue) {
|
108
|
+
if (!value && !oldValue) return;
|
109
|
+
|
110
|
+
let item = Neo.getComponent(this.containerId),
|
111
|
+
style = item.wrapperStyle;
|
112
|
+
|
113
|
+
style.gap = value;
|
114
|
+
item.wrapperStyle = style;
|
115
|
+
}
|
116
|
+
|
96
117
|
/**
|
97
118
|
* Updates the Container CSS cls after "pack" gets changed
|
98
119
|
* @param {String|null} value
|
@@ -0,0 +1,140 @@
|
|
1
|
+
import Base from './Base.mjs';
|
2
|
+
import NeoArray from '../util/Array.mjs';
|
3
|
+
|
4
|
+
/**
|
5
|
+
* @class Neo.layout.Form
|
6
|
+
* @extends Neo.layout.Base
|
7
|
+
*/
|
8
|
+
class Form extends Base {
|
9
|
+
static config = {
|
10
|
+
/**
|
11
|
+
* @member {String} className='Neo.layout.Form'
|
12
|
+
* @protected
|
13
|
+
*/
|
14
|
+
className: 'Neo.layout.Form',
|
15
|
+
/**
|
16
|
+
* @member {String} ntype='layout-form'
|
17
|
+
* @protected
|
18
|
+
*/
|
19
|
+
ntype: 'layout-form',
|
20
|
+
/**
|
21
|
+
* flex css allows gap. This adds it to the component style
|
22
|
+
* @member {String} gap_=null
|
23
|
+
*/
|
24
|
+
gap_: null,
|
25
|
+
/**
|
26
|
+
* CSS className prefix
|
27
|
+
* @member {String} prefix='neo-form-'
|
28
|
+
*/
|
29
|
+
prefix: 'neo-layout-form-'
|
30
|
+
}
|
31
|
+
|
32
|
+
/**
|
33
|
+
* Updates the Container style to add a gap to display:flex
|
34
|
+
* @param {String|null} value
|
35
|
+
* @param {String|null} oldValue
|
36
|
+
* @protected
|
37
|
+
*/
|
38
|
+
afterSetGap(value, oldValue) {
|
39
|
+
if (!value && !oldValue) return;
|
40
|
+
|
41
|
+
let item = Neo.getComponent(this.containerId),
|
42
|
+
style = item.wrapperStyle;
|
43
|
+
|
44
|
+
style.gap = value;
|
45
|
+
item.wrapperStyle = style;
|
46
|
+
}
|
47
|
+
|
48
|
+
/**
|
49
|
+
* Applies the flex value to an item of the container this layout is bound to
|
50
|
+
* @param {Neo.component.Base} item
|
51
|
+
* @param {Number} index
|
52
|
+
*/
|
53
|
+
applyChildAttributes(child, index) {
|
54
|
+
if (!child.ignoreLayout) {
|
55
|
+
if (child.ntype === 'fieldset') {
|
56
|
+
child.wrapperCls = NeoArray.union(child.wrapperCls, 'neo-layout-form-subfieldset');
|
57
|
+
} else if (child.ntype === 'legend') {
|
58
|
+
child.wrapperCls = NeoArray.union(child.wrapperCls, 'neo-layout-form-legend');
|
59
|
+
} else {
|
60
|
+
child.wrapperCls = NeoArray.union(child.wrapperCls, 'neo-layout-form-item');
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
/**
|
66
|
+
* Applies CSS classes to the container this layout is bound to
|
67
|
+
*/
|
68
|
+
applyRenderAttributes() {
|
69
|
+
let me = this,
|
70
|
+
container = Neo.getComponent(me.containerId),
|
71
|
+
wrapperCls = container?.wrapperCls || [];
|
72
|
+
|
73
|
+
if (!container) {
|
74
|
+
Neo.logError('layout.Form: applyRenderAttributes -> container not yet created', me.containerId);
|
75
|
+
}
|
76
|
+
|
77
|
+
NeoArray.add(wrapperCls, 'neo-layout-form');
|
78
|
+
|
79
|
+
container.wrapperCls = wrapperCls;
|
80
|
+
}
|
81
|
+
|
82
|
+
/**
|
83
|
+
* Removes all CSS rules from an container item this layout is bound to.
|
84
|
+
* Gets called when switching to a different layout.
|
85
|
+
* @param {Neo.component.Base} item
|
86
|
+
* @protected
|
87
|
+
*/
|
88
|
+
removeChildAttributes(item) {
|
89
|
+
let style = item.wrapperStyle || {};
|
90
|
+
|
91
|
+
style.flex = item.flex || null;
|
92
|
+
item.wrapperStyle = style;
|
93
|
+
}
|
94
|
+
|
95
|
+
/**
|
96
|
+
* Removes all CSS rules from the container this layout is bound to.
|
97
|
+
* Gets called when switching to a different layout.
|
98
|
+
*/
|
99
|
+
removeRenderAttributes() {
|
100
|
+
let me = this,
|
101
|
+
container = Neo.getComponent(me.containerId),
|
102
|
+
wrapperCls = container?.wrapperCls || [];
|
103
|
+
|
104
|
+
if (!container) {
|
105
|
+
Neo.logError('layout.Form: removeRenderAttributes -> container not yet created', me.containerId);
|
106
|
+
}
|
107
|
+
|
108
|
+
NeoArray.remove(wrapperCls, 'neo-layout-form');
|
109
|
+
|
110
|
+
container.wrapperCls = wrapperCls;
|
111
|
+
}
|
112
|
+
|
113
|
+
/**
|
114
|
+
* Updates the Container CSS wrapperCls
|
115
|
+
* @param {String|null} value
|
116
|
+
* @param {String|null} oldValue
|
117
|
+
* @param {String} propertyName
|
118
|
+
* @protected
|
119
|
+
*/
|
120
|
+
updateInputValue(value, oldValue, propertyName) {
|
121
|
+
let me = this,
|
122
|
+
container = Neo.getComponent(me.containerId),
|
123
|
+
prefix = me.prefix,
|
124
|
+
wrapperCls = container?.wrapperCls;
|
125
|
+
|
126
|
+
if (container?.rendered) {
|
127
|
+
NeoArray.remove(wrapperCls, prefix + propertyName + '-' + oldValue);
|
128
|
+
|
129
|
+
if (value !== null) {
|
130
|
+
NeoArray.add(wrapperCls, prefix + propertyName + '-' + value);
|
131
|
+
}
|
132
|
+
|
133
|
+
container.wrapperCls = wrapperCls;
|
134
|
+
}
|
135
|
+
}
|
136
|
+
}
|
137
|
+
|
138
|
+
Neo.applyClassConfig(Form);
|
139
|
+
|
140
|
+
export default Form;
|