1
- import $ from "jquery" ;
2
1
import parser from "./depends_parse" ;
3
2
4
- function DependsHandler ( $el , expression ) {
5
- var $context = $el . closest ( "form" ) ;
6
- if ( ! $context . length ) $context = $ ( document ) ;
7
- this . $el = $el ;
8
- this . $context = $context ;
9
- this . ast = parser . parse ( expression ) ; // TODO: handle parse exceptions here
10
- }
3
+ class DependsHandler {
4
+ constructor ( el , expression ) {
5
+ this . el = el ;
6
+ this . context = el . closest ( "form" ) || document ;
7
+ this . ast = parser . parse ( expression ) ; // TODO: handle parse exceptions here
8
+ }
11
9
12
- DependsHandler . prototype = {
13
- _findInputs : function ( name ) {
14
- var $input = this . $context . find ( ":input[name='" + name + "']" ) ;
15
- if ( ! $input . length ) $input = $ ( "#" + name ) ;
16
- return $input ;
17
- } ,
10
+ _findInputs ( name ) {
11
+ // In case of radio buttons, there might be multiple inputs.
12
+ // "name" in parentheses, because it can be any value. Common is:
13
+ // `somename:list` for a radio input list.
14
+ let inputs = this . context . querySelectorAll ( `
15
+ input[name="${ name } "],
16
+ select[name="${ name } "],
17
+ textarea[name="${ name } "],
18
+ button[name="${ name } "]
19
+ ` ) ;
20
+ if ( ! inputs . length ) {
21
+ // This should really only find one instance.
22
+ inputs = document . querySelectorAll ( `#${ name } ` ) ;
23
+ }
24
+ return inputs ;
25
+ }
18
26
19
- _getValue : function ( name ) {
20
- var $input = this . _findInputs ( name ) ;
21
- if ( ! $input . length ) return null ;
27
+ _getValue ( name ) {
28
+ let inputs = this . _findInputs ( name ) ;
22
29
23
- if ( $input . attr ( "type" ) === "radio" || $input . attr ( "type" ) === "checkbox" )
24
- return $input . filter ( ":checked" ) . val ( ) || null ;
25
- else return $input . val ( ) ;
26
- } ,
30
+ inputs = [ ...inputs ] . filter ( ( input ) => {
31
+ if ( input . type === "radio" && input . checked === false ) {
32
+ return false ;
33
+ }
34
+ if ( input . type === "checkbox" && input . checked === false ) {
35
+ return false ;
36
+ }
37
+ if ( input . disabled ) {
38
+ return false ;
39
+ }
40
+ return true ;
41
+ } ) ;
27
42
28
- getAllInputs : function ( ) {
29
- var todo = [ this . ast ] ,
30
- $inputs = $ ( ) ,
31
- node ;
43
+ if ( inputs . length === 0 ) {
44
+ return null ;
45
+ }
46
+
47
+ return inputs [ 0 ] . value ;
48
+ }
49
+
50
+ getAllInputs ( ) {
51
+ const todo = [ this . ast ] ;
52
+ const all_inputs = new Set ( ) ;
32
53
33
54
while ( todo . length ) {
34
- node = todo . shift ( ) ;
35
- if ( node . input ) $inputs = $inputs . add ( this . _findInputs ( node . input ) ) ;
36
- if ( node . children && node . children . length )
55
+ const node = todo . shift ( ) ;
56
+ if ( node . input ) {
57
+ const inputs = this . _findInputs ( node . input ) ;
58
+ for ( const input of inputs ) {
59
+ all_inputs . add ( input ) ;
60
+ }
61
+ }
62
+ if ( node . children && node . children . length ) {
37
63
todo . push . apply ( todo , node . children ) ;
64
+ }
38
65
}
39
- return $inputs ;
40
- } ,
66
+ return [ ... all_inputs ] ;
67
+ }
41
68
42
- _evaluate : function ( node ) {
43
- var value = node . input ? this . _getValue ( node . input ) : null ,
44
- i ;
69
+ _evaluate ( node ) {
70
+ const value = node . input ? this . _getValue ( node . input ) : null ;
45
71
46
72
switch ( node . type ) {
47
73
case "NOT" :
48
74
return ! this . _evaluate ( node . children [ 0 ] ) ;
49
- case "AND" :
50
- for ( i = 0 ; i < node . children . length ; i ++ )
51
- if ( ! this . _evaluate ( node . children [ i ] ) ) return false ;
52
- return true ;
53
- case "OR" :
54
- for ( i = 0 ; i < node . children . length ; i ++ )
55
- if ( this . _evaluate ( node . children [ i ] ) ) return true ;
56
- return false ;
75
+ case "AND" : {
76
+ // As soon as one child evaluates to false, the AND expression is false.
77
+ const is_false = node . children . some ( ( child ) => ! this . _evaluate ( child ) ) ;
78
+ return ! is_false ;
79
+ }
80
+ case "OR" : {
81
+ // As soon as one child evaluates to true, the OR expression is true.
82
+ const is_true = node . children . some ( ( child ) => this . _evaluate ( child ) ) ;
83
+ return is_true ;
84
+ }
57
85
case "comparison" :
58
86
switch ( node . operator ) {
59
87
case "=" :
@@ -69,21 +97,25 @@ DependsHandler.prototype = {
69
97
case ">=" :
70
98
return value >= node . value ;
71
99
case "~=" :
72
- if ( value === null ) return false ;
100
+ if ( value === null ) {
101
+ return false ;
102
+ }
73
103
return value . indexOf ( node . value ) != - 1 ;
74
104
case "=~" :
75
- if ( value === null || ! node . value ) return false ;
105
+ if ( value === null || ! node . value ) {
106
+ return false ;
107
+ }
76
108
return node . value . indexOf ( value ) != - 1 ;
77
109
}
78
110
break ;
79
111
case "truthy" :
80
112
return ! ! value ;
81
113
}
82
- } ,
114
+ }
83
115
84
- evaluate : function ( ) {
116
+ evaluate ( ) {
85
117
return this . _evaluate ( this . ast ) ;
86
- } ,
87
- } ;
118
+ }
119
+ }
88
120
89
121
export default DependsHandler ;
0 commit comments