1
- import { Controller } from '@hotwired/stimulus' ;
2
- import Backend , { type BackendInterface } from './Backend/Backend' ;
3
- import Component , { proxifyComponent } from './Component' ;
4
- import { StimulusElementDriver } from './Component/ElementDriver' ;
1
+ import { Controller } from '@hotwired/stimulus' ;
2
+ import Backend , { type BackendInterface } from './Backend/Backend' ;
3
+ import Component , { proxifyComponent } from './Component' ;
4
+ import { StimulusElementDriver } from './Component/ElementDriver' ;
5
5
import ChildComponentPlugin from './Component/plugins/ChildComponentPlugin' ;
6
6
import LazyPlugin from './Component/plugins/LazyPlugin' ;
7
7
import LoadingPlugin from './Component/plugins/LoadingPlugin' ;
8
8
import PageUnloadingPlugin from './Component/plugins/PageUnloadingPlugin' ;
9
- import type { PluginInterface } from './Component/plugins/PluginInterface' ;
9
+ import type { PluginInterface } from './Component/plugins/PluginInterface' ;
10
10
import PollingPlugin from './Component/plugins/PollingPlugin' ;
11
11
import QueryStringPlugin from './Component/plugins/QueryStringPlugin' ;
12
12
import SetValueOntoModelFieldsPlugin from './Component/plugins/SetValueOntoModelFieldsPlugin' ;
13
13
import ValidatedFieldsPlugin from './Component/plugins/ValidatedFieldsPlugin' ;
14
- import { type DirectiveModifier , parseDirectives } from './Directive/directives_parser' ;
14
+ import { type DirectiveModifier , parseDirectives } from './Directive/directives_parser' ;
15
15
import getModelBinding from './Directive/get_model_binding' ;
16
- import { elementBelongsToThisComponent , getModelDirectiveFromElement , getValueFromElement } from './dom_utils' ;
16
+ import { elementBelongsToThisComponent , getModelDirectiveFromElement , getValueFromElement } from './dom_utils' ;
17
17
import getElementAsTagText from './Util/getElementAsTagText' ;
18
18
19
- export { Component } ;
20
- export { getComponent } from './ComponentRegistry' ;
19
+ export { Component } ;
20
+ export { getComponent } from './ComponentRegistry' ;
21
21
22
22
export interface LiveEvent extends CustomEvent {
23
23
detail : {
@@ -30,19 +30,20 @@ export interface LiveController {
30
30
element : HTMLElement ;
31
31
component : Component ;
32
32
}
33
+
33
34
export default class LiveControllerDefault extends Controller < HTMLElement > implements LiveController {
34
35
static values = {
35
36
name : String ,
36
37
url : String ,
37
- props : { type : Object , default : { } } ,
38
- propsUpdatedFromParent : { type : Object , default : { } } ,
39
- listeners : { type : Array , default : [ ] } ,
40
- eventsToEmit : { type : Array , default : [ ] } ,
41
- eventsToDispatch : { type : Array , default : [ ] } ,
42
- debounce : { type : Number , default : 150 } ,
43
- fingerprint : { type : String , default : '' } ,
44
- requestMethod : { type : String , default : 'post' } ,
45
- queryMapping : { type : Object , default : { } } ,
38
+ props : { type : Object , default : { } } ,
39
+ propsUpdatedFromParent : { type : Object , default : { } } ,
40
+ listeners : { type : Array , default : [ ] } ,
41
+ eventsToEmit : { type : Array , default : [ ] } ,
42
+ eventsToDispatch : { type : Array , default : [ ] } ,
43
+ debounce : { type : Number , default : 150 } ,
44
+ fingerprint : { type : String , default : '' } ,
45
+ requestMethod : { type : String , default : 'post' } ,
46
+ queryMapping : { type : Object , default : { } } ,
46
47
} ;
47
48
48
49
declare readonly nameValue : string ;
@@ -71,8 +72,8 @@ export default class LiveControllerDefault extends Controller<HTMLElement> imple
71
72
pendingActionTriggerModelElement : HTMLElement | null = null ;
72
73
73
74
private elementEventListeners : Array < { event : string ; callback : ( event : any ) => void } > = [
74
- { event : 'input' , callback : ( event ) => this . handleInputEvent ( event ) } ,
75
- { event : 'change' , callback : ( event ) => this . handleChangeEvent ( event ) } ,
75
+ { event : 'input' , callback : ( event ) => this . handleInputEvent ( event ) } ,
76
+ { event : 'change' , callback : ( event ) => this . handleChangeEvent ( event ) } ,
76
77
] ;
77
78
private pendingFiles : { [ key : string ] : HTMLInputElement } = { } ;
78
79
@@ -127,7 +128,7 @@ export default class LiveControllerDefault extends Controller<HTMLElement> imple
127
128
}
128
129
const rawAction = params . action ;
129
130
// all other params are considered action arguments
130
- const actionArgs = { ...params } ;
131
+ const actionArgs = { ...params } ;
131
132
delete actionArgs . action ;
132
133
133
134
// data-live-action-param="debounce(1000)|save"
@@ -159,7 +160,8 @@ export default class LiveControllerDefault extends Controller<HTMLElement> imple
159
160
directive . modifiers . forEach ( ( modifier ) => {
160
161
if ( validModifiers . has ( modifier . name ) ) {
161
162
// variable is entirely to make ts happy
162
- const callable = validModifiers . get ( modifier . name ) ?? ( ( ) => { } ) ;
163
+ const callable = validModifiers . get ( modifier . name ) ?? ( ( ) => {
164
+ } ) ;
163
165
callable ( modifier ) ;
164
166
165
167
return ;
@@ -195,19 +197,19 @@ export default class LiveControllerDefault extends Controller<HTMLElement> imple
195
197
}
196
198
197
199
emit ( event : any ) {
198
- this . getEmitDirectives ( event ) . forEach ( ( { name, data, nameMatch } ) => {
200
+ this . getEmitDirectives ( event ) . forEach ( ( { name, data, nameMatch} ) => {
199
201
this . component . emit ( name , data , nameMatch ) ;
200
202
} ) ;
201
203
}
202
204
203
205
emitUp ( event : any ) {
204
- this . getEmitDirectives ( event ) . forEach ( ( { name, data, nameMatch } ) => {
206
+ this . getEmitDirectives ( event ) . forEach ( ( { name, data, nameMatch} ) => {
205
207
this . component . emitUp ( name , data , nameMatch ) ;
206
208
} ) ;
207
209
}
208
210
209
211
emitSelf ( event : any ) {
210
- this . getEmitDirectives ( event ) . forEach ( ( { name, data } ) => {
212
+ this . getEmitDirectives ( event ) . forEach ( ( { name, data} ) => {
211
213
this . component . emitSelf ( name , data ) ;
212
214
} ) ;
213
215
}
@@ -243,7 +245,7 @@ export default class LiveControllerDefault extends Controller<HTMLElement> imple
243
245
}
244
246
const eventInfo = params . event ;
245
247
// all other params are considered event arguments
246
- const eventArgs = { ...params } ;
248
+ const eventArgs = { ...params } ;
247
249
delete eventArgs . event ;
248
250
249
251
// data-event="name(product_list)|some_event"
@@ -315,7 +317,7 @@ export default class LiveControllerDefault extends Controller<HTMLElement> imple
315
317
attributes : true ,
316
318
} ) ;
317
319
318
- this . elementEventListeners . forEach ( ( { event, callback } ) => {
320
+ this . elementEventListeners . forEach ( ( { event, callback} ) => {
319
321
this . component . element . addEventListener ( event , callback ) ;
320
322
} ) ;
321
323
@@ -324,7 +326,7 @@ export default class LiveControllerDefault extends Controller<HTMLElement> imple
324
326
325
327
private disconnectComponent ( ) {
326
328
this . component . disconnect ( ) ;
327
- this . elementEventListeners . forEach ( ( { event, callback } ) => {
329
+ this . elementEventListeners . forEach ( ( { event, callback} ) => {
328
330
this . component . element . removeEventListener ( event , callback ) ;
329
331
} ) ;
330
332
this . dispatchEvent ( 'disconnect' ) ;
@@ -429,14 +431,35 @@ export default class LiveControllerDefault extends Controller<HTMLElement> imple
429
431
430
432
const finalValue = getValueFromElement ( element , this . component . valueStore ) ;
431
433
434
+ if (
435
+ ( element instanceof HTMLInputElement && [ 'text' , 'email' , 'password' , 'search' , 'tel' , 'url' ] . includes ( element . type ) ) ||
436
+ element instanceof HTMLTextAreaElement
437
+ ) {
438
+ if ( modelBinding . minLength !== null && typeof finalValue === "string" && finalValue . length < modelBinding . minLength ) {
439
+ return ;
440
+ }
441
+ if ( modelBinding . maxLength !== null && typeof finalValue === "string" && finalValue . length > modelBinding . maxLength ) {
442
+ return ;
443
+ }
444
+ }
445
+
446
+ if ( element instanceof HTMLInputElement && element . type === 'number' ) {
447
+ if ( modelBinding . minValue !== null && Number ( finalValue ) < modelBinding . minValue ) {
448
+ return ;
449
+ }
450
+ if ( modelBinding . maxValue !== null && Number ( finalValue ) > modelBinding . maxValue ) {
451
+ return ;
452
+ }
453
+ }
454
+
432
455
this . component . set ( modelBinding . modelName , finalValue , modelBinding . shouldRender , modelBinding . debounce ) ;
433
456
}
434
457
435
458
private dispatchEvent ( name : string , detail : any = { } , canBubble = true , cancelable = false ) {
436
459
detail . controller = this ;
437
460
detail . component = this . proxiedComponent ;
438
461
439
- this . dispatch ( name , { detail, prefix : 'live' , cancelable, bubbles : canBubble } ) ;
462
+ this . dispatch ( name , { detail, prefix : 'live' , cancelable, bubbles : canBubble } ) ;
440
463
}
441
464
442
465
private onMutations ( mutations : MutationRecord [ ] ) : void {
0 commit comments