stimulus-rails 1.1.0 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/stimulus.js +188 -132
- data/app/assets/javascripts/stimulus.min.js +1 -1
- data/app/assets/javascripts/stimulus.min.js.map +1 -1
- data/lib/stimulus/version.rb +1 -1
- metadata +3 -3
@@ -3,7 +3,7 @@
|
|
3
3
|
//= link ./stimulus-loading.js
|
4
4
|
|
5
5
|
/*
|
6
|
-
Stimulus 3.1.
|
6
|
+
Stimulus 3.1.1
|
7
7
|
Copyright © 2022 Basecamp, LLC
|
8
8
|
*/
|
9
9
|
class EventListener {
|
@@ -36,6 +36,9 @@ class EventListener {
|
|
36
36
|
}
|
37
37
|
}
|
38
38
|
}
|
39
|
+
hasBindings() {
|
40
|
+
return this.unorderedBindings.size > 0;
|
41
|
+
}
|
39
42
|
get bindings() {
|
40
43
|
return Array.from(this.unorderedBindings).sort((left, right) => {
|
41
44
|
const leftIndex = left.index, rightIndex = right.index;
|
@@ -54,7 +57,7 @@ function extendEvent(event) {
|
|
54
57
|
stopImmediatePropagation() {
|
55
58
|
this.immediatePropagationStopped = true;
|
56
59
|
stopImmediatePropagation.call(this);
|
57
|
-
}
|
60
|
+
},
|
58
61
|
});
|
59
62
|
}
|
60
63
|
}
|
@@ -62,34 +65,50 @@ function extendEvent(event) {
|
|
62
65
|
class Dispatcher {
|
63
66
|
constructor(application) {
|
64
67
|
this.application = application;
|
65
|
-
this.eventListenerMaps = new Map;
|
68
|
+
this.eventListenerMaps = new Map();
|
66
69
|
this.started = false;
|
67
70
|
}
|
68
71
|
start() {
|
69
72
|
if (!this.started) {
|
70
73
|
this.started = true;
|
71
|
-
this.eventListeners.forEach(eventListener => eventListener.connect());
|
74
|
+
this.eventListeners.forEach((eventListener) => eventListener.connect());
|
72
75
|
}
|
73
76
|
}
|
74
77
|
stop() {
|
75
78
|
if (this.started) {
|
76
79
|
this.started = false;
|
77
|
-
this.eventListeners.forEach(eventListener => eventListener.disconnect());
|
80
|
+
this.eventListeners.forEach((eventListener) => eventListener.disconnect());
|
78
81
|
}
|
79
82
|
}
|
80
83
|
get eventListeners() {
|
81
|
-
return Array.from(this.eventListenerMaps.values())
|
82
|
-
.reduce((listeners, map) => listeners.concat(Array.from(map.values())), []);
|
84
|
+
return Array.from(this.eventListenerMaps.values()).reduce((listeners, map) => listeners.concat(Array.from(map.values())), []);
|
83
85
|
}
|
84
86
|
bindingConnected(binding) {
|
85
87
|
this.fetchEventListenerForBinding(binding).bindingConnected(binding);
|
86
88
|
}
|
87
|
-
bindingDisconnected(binding) {
|
89
|
+
bindingDisconnected(binding, clearEventListeners = false) {
|
88
90
|
this.fetchEventListenerForBinding(binding).bindingDisconnected(binding);
|
91
|
+
if (clearEventListeners)
|
92
|
+
this.clearEventListenersForBinding(binding);
|
89
93
|
}
|
90
94
|
handleError(error, message, detail = {}) {
|
91
95
|
this.application.handleError(error, `Error ${message}`, detail);
|
92
96
|
}
|
97
|
+
clearEventListenersForBinding(binding) {
|
98
|
+
const eventListener = this.fetchEventListenerForBinding(binding);
|
99
|
+
if (!eventListener.hasBindings()) {
|
100
|
+
eventListener.disconnect();
|
101
|
+
this.removeMappedEventListenerFor(binding);
|
102
|
+
}
|
103
|
+
}
|
104
|
+
removeMappedEventListenerFor(binding) {
|
105
|
+
const { eventTarget, eventName, eventOptions } = binding;
|
106
|
+
const eventListenerMap = this.fetchEventListenerMapForEventTarget(eventTarget);
|
107
|
+
const cacheKey = this.cacheKey(eventName, eventOptions);
|
108
|
+
eventListenerMap.delete(cacheKey);
|
109
|
+
if (eventListenerMap.size == 0)
|
110
|
+
this.eventListenerMaps.delete(eventTarget);
|
111
|
+
}
|
93
112
|
fetchEventListenerForBinding(binding) {
|
94
113
|
const { eventTarget, eventName, eventOptions } = binding;
|
95
114
|
return this.fetchEventListener(eventTarget, eventName, eventOptions);
|
@@ -114,20 +133,42 @@ class Dispatcher {
|
|
114
133
|
fetchEventListenerMapForEventTarget(eventTarget) {
|
115
134
|
let eventListenerMap = this.eventListenerMaps.get(eventTarget);
|
116
135
|
if (!eventListenerMap) {
|
117
|
-
eventListenerMap = new Map;
|
136
|
+
eventListenerMap = new Map();
|
118
137
|
this.eventListenerMaps.set(eventTarget, eventListenerMap);
|
119
138
|
}
|
120
139
|
return eventListenerMap;
|
121
140
|
}
|
122
141
|
cacheKey(eventName, eventOptions) {
|
123
142
|
const parts = [eventName];
|
124
|
-
Object.keys(eventOptions)
|
143
|
+
Object.keys(eventOptions)
|
144
|
+
.sort()
|
145
|
+
.forEach((key) => {
|
125
146
|
parts.push(`${eventOptions[key] ? "" : "!"}${key}`);
|
126
147
|
});
|
127
148
|
return parts.join(":");
|
128
149
|
}
|
129
150
|
}
|
130
151
|
|
152
|
+
const defaultActionDescriptorFilters = {
|
153
|
+
stop({ event, value }) {
|
154
|
+
if (value)
|
155
|
+
event.stopPropagation();
|
156
|
+
return true;
|
157
|
+
},
|
158
|
+
prevent({ event, value }) {
|
159
|
+
if (value)
|
160
|
+
event.preventDefault();
|
161
|
+
return true;
|
162
|
+
},
|
163
|
+
self({ event, value, element }) {
|
164
|
+
if (value) {
|
165
|
+
return element === event.target;
|
166
|
+
}
|
167
|
+
else {
|
168
|
+
return true;
|
169
|
+
}
|
170
|
+
},
|
171
|
+
};
|
131
172
|
const descriptorPattern = /^((.+?)(@(window|document))?->)?(.+?)(#([^:]+?))(:(.+))?$/;
|
132
173
|
function parseActionDescriptorString(descriptorString) {
|
133
174
|
const source = descriptorString.trim();
|
@@ -137,7 +178,7 @@ function parseActionDescriptorString(descriptorString) {
|
|
137
178
|
eventName: matches[2],
|
138
179
|
eventOptions: matches[9] ? parseEventOptions(matches[9]) : {},
|
139
180
|
identifier: matches[5],
|
140
|
-
methodName: matches[7]
|
181
|
+
methodName: matches[7],
|
141
182
|
};
|
142
183
|
}
|
143
184
|
function parseEventTarget(eventTargetName) {
|
@@ -149,7 +190,9 @@ function parseEventTarget(eventTargetName) {
|
|
149
190
|
}
|
150
191
|
}
|
151
192
|
function parseEventOptions(eventOptions) {
|
152
|
-
return eventOptions
|
193
|
+
return eventOptions
|
194
|
+
.split(":")
|
195
|
+
.reduce((options, token) => Object.assign(options, { [token.replace(/^!/, "")]: !/^!/.test(token) }), {});
|
153
196
|
}
|
154
197
|
function stringifyEventTarget(eventTarget) {
|
155
198
|
if (eventTarget == window) {
|
@@ -192,7 +235,7 @@ class Action {
|
|
192
235
|
}
|
193
236
|
get params() {
|
194
237
|
const params = {};
|
195
|
-
const pattern = new RegExp(`^data-${this.identifier}-(.+)-param
|
238
|
+
const pattern = new RegExp(`^data-${this.identifier}-(.+)-param$`, "i");
|
196
239
|
for (const { name, value } of Array.from(this.element.attributes)) {
|
197
240
|
const match = name.match(pattern);
|
198
241
|
const key = match && match[1];
|
@@ -207,13 +250,13 @@ class Action {
|
|
207
250
|
}
|
208
251
|
}
|
209
252
|
const defaultEventNames = {
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
253
|
+
a: () => "click",
|
254
|
+
button: () => "click",
|
255
|
+
form: () => "submit",
|
256
|
+
details: () => "toggle",
|
257
|
+
input: (e) => (e.getAttribute("type") == "submit" ? "click" : "input"),
|
258
|
+
select: () => "change",
|
259
|
+
textarea: () => "input",
|
217
260
|
};
|
218
261
|
function getDefaultEventNameForElement(element) {
|
219
262
|
const tagName = element.tagName.toLowerCase();
|
@@ -251,9 +294,7 @@ class Binding {
|
|
251
294
|
return this.context.identifier;
|
252
295
|
}
|
253
296
|
handleEvent(event) {
|
254
|
-
if (this.willBeInvokedByEvent(event) && this.
|
255
|
-
this.processStopPropagation(event);
|
256
|
-
this.processPreventDefault(event);
|
297
|
+
if (this.willBeInvokedByEvent(event) && this.applyEventModifiers(event)) {
|
257
298
|
this.invokeWithEvent(event);
|
258
299
|
}
|
259
300
|
}
|
@@ -267,15 +308,20 @@ class Binding {
|
|
267
308
|
}
|
268
309
|
throw new Error(`Action "${this.action}" references undefined method "${this.methodName}"`);
|
269
310
|
}
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
311
|
+
applyEventModifiers(event) {
|
312
|
+
const { element } = this.action;
|
313
|
+
const { actionDescriptorFilters } = this.context.application;
|
314
|
+
let passes = true;
|
315
|
+
for (const [name, value] of Object.entries(this.eventOptions)) {
|
316
|
+
if (name in actionDescriptorFilters) {
|
317
|
+
const filter = actionDescriptorFilters[name];
|
318
|
+
passes = passes && filter({ name, value, event, element });
|
319
|
+
}
|
320
|
+
else {
|
321
|
+
continue;
|
322
|
+
}
|
278
323
|
}
|
324
|
+
return passes;
|
279
325
|
}
|
280
326
|
invokeWithEvent(event) {
|
281
327
|
const { target, currentTarget } = event;
|
@@ -291,14 +337,6 @@ class Binding {
|
|
291
337
|
this.context.handleError(error, `invoking action "${this.action}"`, detail);
|
292
338
|
}
|
293
339
|
}
|
294
|
-
shouldBeInvokedPerSelf(event) {
|
295
|
-
if (this.action.eventOptions.self === true) {
|
296
|
-
return this.action.element === event.target;
|
297
|
-
}
|
298
|
-
else {
|
299
|
-
return true;
|
300
|
-
}
|
301
|
-
}
|
302
340
|
willBeInvokedByEvent(event) {
|
303
341
|
const eventTarget = event.target;
|
304
342
|
if (this.element === eventTarget) {
|
@@ -331,7 +369,7 @@ class ElementObserver {
|
|
331
369
|
this.element = element;
|
332
370
|
this.started = false;
|
333
371
|
this.delegate = delegate;
|
334
|
-
this.elements = new Set;
|
372
|
+
this.elements = new Set();
|
335
373
|
this.mutationObserver = new MutationObserver((mutations) => this.processMutations(mutations));
|
336
374
|
}
|
337
375
|
start() {
|
@@ -519,8 +557,8 @@ class StringMapObserver {
|
|
519
557
|
this.element = element;
|
520
558
|
this.delegate = delegate;
|
521
559
|
this.started = false;
|
522
|
-
this.stringMap = new Map;
|
523
|
-
this.mutationObserver = new MutationObserver(mutations => this.processMutations(mutations));
|
560
|
+
this.stringMap = new Map();
|
561
|
+
this.mutationObserver = new MutationObserver((mutations) => this.processMutations(mutations));
|
524
562
|
}
|
525
563
|
start() {
|
526
564
|
if (!this.started) {
|
@@ -596,7 +634,7 @@ class StringMapObserver {
|
|
596
634
|
return Array.from(new Set(this.currentAttributeNames.concat(this.recordedAttributeNames)));
|
597
635
|
}
|
598
636
|
get currentAttributeNames() {
|
599
|
-
return Array.from(this.element.attributes).map(attribute => attribute.name);
|
637
|
+
return Array.from(this.element.attributes).map((attribute) => attribute.name);
|
600
638
|
}
|
601
639
|
get recordedAttributeNames() {
|
602
640
|
return Array.from(this.stringMap.keys());
|
@@ -655,7 +693,7 @@ class Multimap {
|
|
655
693
|
}
|
656
694
|
hasValue(value) {
|
657
695
|
const sets = Array.from(this.valuesByKey.values());
|
658
|
-
return sets.some(set => set.has(value));
|
696
|
+
return sets.some((set) => set.has(value));
|
659
697
|
}
|
660
698
|
getValuesForKey(key) {
|
661
699
|
const values = this.valuesByKey.get(key);
|
@@ -663,15 +701,15 @@ class Multimap {
|
|
663
701
|
}
|
664
702
|
getKeysForValue(value) {
|
665
703
|
return Array.from(this.valuesByKey)
|
666
|
-
.filter(([
|
667
|
-
.map(([key,
|
704
|
+
.filter(([_key, values]) => values.has(value))
|
705
|
+
.map(([key, _values]) => key);
|
668
706
|
}
|
669
707
|
}
|
670
708
|
|
671
709
|
class IndexedMultimap extends Multimap {
|
672
710
|
constructor() {
|
673
711
|
super();
|
674
|
-
this.keysByValue = new Map;
|
712
|
+
this.keysByValue = new Map();
|
675
713
|
}
|
676
714
|
get values() {
|
677
715
|
return Array.from(this.keysByValue.keys());
|
@@ -697,7 +735,7 @@ class TokenListObserver {
|
|
697
735
|
constructor(element, attributeName, delegate) {
|
698
736
|
this.attributeObserver = new AttributeObserver(element, attributeName, this);
|
699
737
|
this.delegate = delegate;
|
700
|
-
this.tokensByElement = new Multimap;
|
738
|
+
this.tokensByElement = new Multimap();
|
701
739
|
}
|
702
740
|
get started() {
|
703
741
|
return this.attributeObserver.started;
|
@@ -732,10 +770,10 @@ class TokenListObserver {
|
|
732
770
|
this.tokensUnmatched(this.tokensByElement.getValuesForKey(element));
|
733
771
|
}
|
734
772
|
tokensMatched(tokens) {
|
735
|
-
tokens.forEach(token => this.tokenMatched(token));
|
773
|
+
tokens.forEach((token) => this.tokenMatched(token));
|
736
774
|
}
|
737
775
|
tokensUnmatched(tokens) {
|
738
|
-
tokens.forEach(token => this.tokenUnmatched(token));
|
776
|
+
tokens.forEach((token) => this.tokenUnmatched(token));
|
739
777
|
}
|
740
778
|
tokenMatched(token) {
|
741
779
|
this.delegate.tokenMatched(token);
|
@@ -748,8 +786,7 @@ class TokenListObserver {
|
|
748
786
|
refreshTokensForElement(element) {
|
749
787
|
const previousTokens = this.tokensByElement.getValuesForKey(element);
|
750
788
|
const currentTokens = this.readTokensForElement(element);
|
751
|
-
const firstDifferingIndex = zip(previousTokens, currentTokens)
|
752
|
-
.findIndex(([previousToken, currentToken]) => !tokensAreEqual(previousToken, currentToken));
|
789
|
+
const firstDifferingIndex = zip(previousTokens, currentTokens).findIndex(([previousToken, currentToken]) => !tokensAreEqual(previousToken, currentToken));
|
753
790
|
if (firstDifferingIndex == -1) {
|
754
791
|
return [[], []];
|
755
792
|
}
|
@@ -764,7 +801,10 @@ class TokenListObserver {
|
|
764
801
|
}
|
765
802
|
}
|
766
803
|
function parseTokenString(tokenString, element, attributeName) {
|
767
|
-
return tokenString
|
804
|
+
return tokenString
|
805
|
+
.trim()
|
806
|
+
.split(/\s+/)
|
807
|
+
.filter((content) => content.length)
|
768
808
|
.map((content, index) => ({ element, attributeName, content, index }));
|
769
809
|
}
|
770
810
|
function zip(left, right) {
|
@@ -779,8 +819,8 @@ class ValueListObserver {
|
|
779
819
|
constructor(element, attributeName, delegate) {
|
780
820
|
this.tokenListObserver = new TokenListObserver(element, attributeName, this);
|
781
821
|
this.delegate = delegate;
|
782
|
-
this.parseResultsByToken = new WeakMap;
|
783
|
-
this.valuesByTokenByElement = new WeakMap;
|
822
|
+
this.parseResultsByToken = new WeakMap();
|
823
|
+
this.valuesByTokenByElement = new WeakMap();
|
784
824
|
}
|
785
825
|
get started() {
|
786
826
|
return this.tokenListObserver.started;
|
@@ -827,7 +867,7 @@ class ValueListObserver {
|
|
827
867
|
fetchValuesByTokenForElement(element) {
|
828
868
|
let valuesByToken = this.valuesByTokenByElement.get(element);
|
829
869
|
if (!valuesByToken) {
|
830
|
-
valuesByToken = new Map;
|
870
|
+
valuesByToken = new Map();
|
831
871
|
this.valuesByTokenByElement.set(element, valuesByToken);
|
832
872
|
}
|
833
873
|
return valuesByToken;
|
@@ -847,7 +887,7 @@ class BindingObserver {
|
|
847
887
|
constructor(context, delegate) {
|
848
888
|
this.context = context;
|
849
889
|
this.delegate = delegate;
|
850
|
-
this.bindingsByAction = new Map;
|
890
|
+
this.bindingsByAction = new Map();
|
851
891
|
}
|
852
892
|
start() {
|
853
893
|
if (!this.valueListObserver) {
|
@@ -890,7 +930,7 @@ class BindingObserver {
|
|
890
930
|
}
|
891
931
|
}
|
892
932
|
disconnectAllActions() {
|
893
|
-
this.bindings.forEach(binding => this.delegate.bindingDisconnected(binding));
|
933
|
+
this.bindings.forEach((binding) => this.delegate.bindingDisconnected(binding, true));
|
894
934
|
this.bindingsByAction.clear();
|
895
935
|
}
|
896
936
|
parseValueForToken(token) {
|
@@ -977,19 +1017,20 @@ class ValueObserver {
|
|
977
1017
|
changedMethod.call(this.receiver, value, oldValue);
|
978
1018
|
}
|
979
1019
|
catch (error) {
|
980
|
-
if (
|
981
|
-
|
982
|
-
|
1020
|
+
if (error instanceof TypeError) {
|
1021
|
+
error.message = `Stimulus Value "${this.context.identifier}.${descriptor.name}" - ${error.message}`;
|
1022
|
+
}
|
1023
|
+
throw error;
|
983
1024
|
}
|
984
1025
|
}
|
985
1026
|
}
|
986
1027
|
get valueDescriptors() {
|
987
1028
|
const { valueDescriptorMap } = this;
|
988
|
-
return Object.keys(valueDescriptorMap).map(key => valueDescriptorMap[key]);
|
1029
|
+
return Object.keys(valueDescriptorMap).map((key) => valueDescriptorMap[key]);
|
989
1030
|
}
|
990
1031
|
get valueDescriptorNameMap() {
|
991
1032
|
const descriptors = {};
|
992
|
-
Object.keys(this.valueDescriptorMap).forEach(key => {
|
1033
|
+
Object.keys(this.valueDescriptorMap).forEach((key) => {
|
993
1034
|
const descriptor = this.valueDescriptorMap[key];
|
994
1035
|
descriptors[descriptor.name] = descriptor;
|
995
1036
|
});
|
@@ -1006,7 +1047,7 @@ class TargetObserver {
|
|
1006
1047
|
constructor(context, delegate) {
|
1007
1048
|
this.context = context;
|
1008
1049
|
this.delegate = delegate;
|
1009
|
-
this.targetsByName = new Multimap;
|
1050
|
+
this.targetsByName = new Multimap();
|
1010
1051
|
}
|
1011
1052
|
start() {
|
1012
1053
|
if (!this.tokenListObserver) {
|
@@ -1146,9 +1187,9 @@ class Context {
|
|
1146
1187
|
function readInheritableStaticArrayValues(constructor, propertyName) {
|
1147
1188
|
const ancestors = getAncestorsForConstructor(constructor);
|
1148
1189
|
return Array.from(ancestors.reduce((values, constructor) => {
|
1149
|
-
getOwnStaticArrayValues(constructor, propertyName).forEach(name => values.add(name));
|
1190
|
+
getOwnStaticArrayValues(constructor, propertyName).forEach((name) => values.add(name));
|
1150
1191
|
return values;
|
1151
|
-
}, new Set));
|
1192
|
+
}, new Set()));
|
1152
1193
|
}
|
1153
1194
|
function readInheritableStaticObjectPairs(constructor, propertyName) {
|
1154
1195
|
const ancestors = getAncestorsForConstructor(constructor);
|
@@ -1171,7 +1212,7 @@ function getOwnStaticArrayValues(constructor, propertyName) {
|
|
1171
1212
|
}
|
1172
1213
|
function getOwnStaticObjectPairs(constructor, propertyName) {
|
1173
1214
|
const definition = constructor[propertyName];
|
1174
|
-
return definition ? Object.keys(definition).map(key => [key, definition[key]]) : [];
|
1215
|
+
return definition ? Object.keys(definition).map((key) => [key, definition[key]]) : [];
|
1175
1216
|
}
|
1176
1217
|
|
1177
1218
|
function bless(constructor) {
|
@@ -1217,10 +1258,7 @@ function getShadowedDescriptor(prototype, properties, key) {
|
|
1217
1258
|
}
|
1218
1259
|
const getOwnKeys = (() => {
|
1219
1260
|
if (typeof Object.getOwnPropertySymbols == "function") {
|
1220
|
-
return (object) => [
|
1221
|
-
...Object.getOwnPropertyNames(object),
|
1222
|
-
...Object.getOwnPropertySymbols(object)
|
1223
|
-
];
|
1261
|
+
return (object) => [...Object.getOwnPropertyNames(object), ...Object.getOwnPropertySymbols(object)];
|
1224
1262
|
}
|
1225
1263
|
else {
|
1226
1264
|
return Object.getOwnPropertyNames;
|
@@ -1232,16 +1270,18 @@ const extend = (() => {
|
|
1232
1270
|
return Reflect.construct(constructor, arguments, new.target);
|
1233
1271
|
}
|
1234
1272
|
extended.prototype = Object.create(constructor.prototype, {
|
1235
|
-
constructor: { value: extended }
|
1273
|
+
constructor: { value: extended },
|
1236
1274
|
});
|
1237
1275
|
Reflect.setPrototypeOf(extended, constructor);
|
1238
1276
|
return extended;
|
1239
1277
|
}
|
1240
1278
|
function testReflectExtension() {
|
1241
|
-
const a = function () {
|
1279
|
+
const a = function () {
|
1280
|
+
this.a.call(this);
|
1281
|
+
};
|
1242
1282
|
const b = extendWithReflect(a);
|
1243
1283
|
b.prototype.a = function () { };
|
1244
|
-
return new b;
|
1284
|
+
return new b();
|
1245
1285
|
}
|
1246
1286
|
try {
|
1247
1287
|
testReflectExtension();
|
@@ -1256,7 +1296,7 @@ const extend = (() => {
|
|
1256
1296
|
function blessDefinition(definition) {
|
1257
1297
|
return {
|
1258
1298
|
identifier: definition.identifier,
|
1259
|
-
controllerConstructor: bless(definition.controllerConstructor)
|
1299
|
+
controllerConstructor: bless(definition.controllerConstructor),
|
1260
1300
|
};
|
1261
1301
|
}
|
1262
1302
|
|
@@ -1264,8 +1304,8 @@ class Module {
|
|
1264
1304
|
constructor(application, definition) {
|
1265
1305
|
this.application = application;
|
1266
1306
|
this.definition = blessDefinition(definition);
|
1267
|
-
this.contextsByScope = new WeakMap;
|
1268
|
-
this.connectedContexts = new Set;
|
1307
|
+
this.contextsByScope = new WeakMap();
|
1308
|
+
this.connectedContexts = new Set();
|
1269
1309
|
}
|
1270
1310
|
get identifier() {
|
1271
1311
|
return this.definition.identifier;
|
@@ -1363,13 +1403,13 @@ class DataMap {
|
|
1363
1403
|
|
1364
1404
|
class Guide {
|
1365
1405
|
constructor(logger) {
|
1366
|
-
this.warnedKeysByObject = new WeakMap;
|
1406
|
+
this.warnedKeysByObject = new WeakMap();
|
1367
1407
|
this.logger = logger;
|
1368
1408
|
}
|
1369
1409
|
warn(object, key, message) {
|
1370
1410
|
let warnedKeys = this.warnedKeysByObject.get(object);
|
1371
1411
|
if (!warnedKeys) {
|
1372
|
-
warnedKeys = new Set;
|
1412
|
+
warnedKeys = new Set();
|
1373
1413
|
this.warnedKeysByObject.set(object, warnedKeys);
|
1374
1414
|
}
|
1375
1415
|
if (!warnedKeys.has(key)) {
|
@@ -1400,15 +1440,13 @@ class TargetSet {
|
|
1400
1440
|
return this.find(targetName) != null;
|
1401
1441
|
}
|
1402
1442
|
find(...targetNames) {
|
1403
|
-
return targetNames.reduce((target, targetName) => target
|
1404
|
-
|| this.findTarget(targetName)
|
1405
|
-
|| this.findLegacyTarget(targetName), undefined);
|
1443
|
+
return targetNames.reduce((target, targetName) => target || this.findTarget(targetName) || this.findLegacyTarget(targetName), undefined);
|
1406
1444
|
}
|
1407
1445
|
findAll(...targetNames) {
|
1408
1446
|
return targetNames.reduce((targets, targetName) => [
|
1409
1447
|
...targets,
|
1410
1448
|
...this.findAllTargets(targetName),
|
1411
|
-
...this.findAllLegacyTargets(targetName)
|
1449
|
+
...this.findAllLegacyTargets(targetName),
|
1412
1450
|
], []);
|
1413
1451
|
}
|
1414
1452
|
findTarget(targetName) {
|
@@ -1429,7 +1467,7 @@ class TargetSet {
|
|
1429
1467
|
}
|
1430
1468
|
findAllLegacyTargets(targetName) {
|
1431
1469
|
const selector = this.getLegacySelectorForTargetName(targetName);
|
1432
|
-
return this.scope.findAllElements(selector).map(element => this.deprecate(element, targetName));
|
1470
|
+
return this.scope.findAllElements(selector).map((element) => this.deprecate(element, targetName));
|
1433
1471
|
}
|
1434
1472
|
getLegacySelectorForTargetName(targetName) {
|
1435
1473
|
const targetDescriptor = `${this.identifier}.${targetName}`;
|
@@ -1464,14 +1502,12 @@ class Scope {
|
|
1464
1502
|
this.guide = new Guide(logger);
|
1465
1503
|
}
|
1466
1504
|
findElement(selector) {
|
1467
|
-
return this.element.matches(selector)
|
1468
|
-
? this.element
|
1469
|
-
: this.queryElements(selector).find(this.containsElement);
|
1505
|
+
return this.element.matches(selector) ? this.element : this.queryElements(selector).find(this.containsElement);
|
1470
1506
|
}
|
1471
1507
|
findAllElements(selector) {
|
1472
1508
|
return [
|
1473
|
-
...this.element.matches(selector) ? [this.element] : [],
|
1474
|
-
...this.queryElements(selector).filter(this.containsElement)
|
1509
|
+
...(this.element.matches(selector) ? [this.element] : []),
|
1510
|
+
...this.queryElements(selector).filter(this.containsElement),
|
1475
1511
|
];
|
1476
1512
|
}
|
1477
1513
|
queryElements(selector) {
|
@@ -1488,8 +1524,8 @@ class ScopeObserver {
|
|
1488
1524
|
this.schema = schema;
|
1489
1525
|
this.delegate = delegate;
|
1490
1526
|
this.valueListObserver = new ValueListObserver(this.element, this.controllerAttribute, this);
|
1491
|
-
this.scopesByIdentifierByElement = new WeakMap;
|
1492
|
-
this.scopeReferenceCounts = new WeakMap;
|
1527
|
+
this.scopesByIdentifierByElement = new WeakMap();
|
1528
|
+
this.scopeReferenceCounts = new WeakMap();
|
1493
1529
|
}
|
1494
1530
|
start() {
|
1495
1531
|
this.valueListObserver.start();
|
@@ -1529,7 +1565,7 @@ class ScopeObserver {
|
|
1529
1565
|
fetchScopesByIdentifierForElement(element) {
|
1530
1566
|
let scopesByIdentifier = this.scopesByIdentifierByElement.get(element);
|
1531
1567
|
if (!scopesByIdentifier) {
|
1532
|
-
scopesByIdentifier = new Map;
|
1568
|
+
scopesByIdentifier = new Map();
|
1533
1569
|
this.scopesByIdentifierByElement.set(element, scopesByIdentifier);
|
1534
1570
|
}
|
1535
1571
|
return scopesByIdentifier;
|
@@ -1540,8 +1576,8 @@ class Router {
|
|
1540
1576
|
constructor(application) {
|
1541
1577
|
this.application = application;
|
1542
1578
|
this.scopeObserver = new ScopeObserver(this.element, this.schema, this);
|
1543
|
-
this.scopesByIdentifier = new Multimap;
|
1544
|
-
this.modulesByIdentifier = new Map;
|
1579
|
+
this.scopesByIdentifier = new Multimap();
|
1580
|
+
this.modulesByIdentifier = new Map();
|
1545
1581
|
}
|
1546
1582
|
get element() {
|
1547
1583
|
return this.application.element;
|
@@ -1581,7 +1617,7 @@ class Router {
|
|
1581
1617
|
getContextForElementAndIdentifier(element, identifier) {
|
1582
1618
|
const module = this.modulesByIdentifier.get(identifier);
|
1583
1619
|
if (module) {
|
1584
|
-
return module.contexts.find(context => context.element == element);
|
1620
|
+
return module.contexts.find((context) => context.element == element);
|
1585
1621
|
}
|
1586
1622
|
}
|
1587
1623
|
handleError(error, message, detail) {
|
@@ -1607,12 +1643,12 @@ class Router {
|
|
1607
1643
|
connectModule(module) {
|
1608
1644
|
this.modulesByIdentifier.set(module.identifier, module);
|
1609
1645
|
const scopes = this.scopesByIdentifier.getValuesForKey(module.identifier);
|
1610
|
-
scopes.forEach(scope => module.connectContextForScope(scope));
|
1646
|
+
scopes.forEach((scope) => module.connectContextForScope(scope));
|
1611
1647
|
}
|
1612
1648
|
disconnectModule(module) {
|
1613
1649
|
this.modulesByIdentifier.delete(module.identifier);
|
1614
1650
|
const scopes = this.scopesByIdentifier.getValuesForKey(module.identifier);
|
1615
|
-
scopes.forEach(scope => module.disconnectContextForScope(scope));
|
1651
|
+
scopes.forEach((scope) => module.disconnectContextForScope(scope));
|
1616
1652
|
}
|
1617
1653
|
}
|
1618
1654
|
|
@@ -1620,7 +1656,7 @@ const defaultSchema = {
|
|
1620
1656
|
controllerAttribute: "data-controller",
|
1621
1657
|
actionAttribute: "data-action",
|
1622
1658
|
targetAttribute: "data-target",
|
1623
|
-
targetAttributeForScope: identifier => `data-${identifier}-target
|
1659
|
+
targetAttributeForScope: (identifier) => `data-${identifier}-target`,
|
1624
1660
|
};
|
1625
1661
|
|
1626
1662
|
class Application {
|
@@ -1636,6 +1672,7 @@ class Application {
|
|
1636
1672
|
this.schema = schema;
|
1637
1673
|
this.dispatcher = new Dispatcher(this);
|
1638
1674
|
this.router = new Router(this);
|
1675
|
+
this.actionDescriptorFilters = Object.assign({}, defaultActionDescriptorFilters);
|
1639
1676
|
}
|
1640
1677
|
static start(element, schema) {
|
1641
1678
|
const application = new Application(element, schema);
|
@@ -1658,9 +1695,12 @@ class Application {
|
|
1658
1695
|
register(identifier, controllerConstructor) {
|
1659
1696
|
this.load({ identifier, controllerConstructor });
|
1660
1697
|
}
|
1698
|
+
registerActionOption(name, filter) {
|
1699
|
+
this.actionDescriptorFilters[name] = filter;
|
1700
|
+
}
|
1661
1701
|
load(head, ...rest) {
|
1662
1702
|
const definitions = Array.isArray(head) ? head : [head, ...rest];
|
1663
|
-
definitions.forEach(definition => {
|
1703
|
+
definitions.forEach((definition) => {
|
1664
1704
|
if (definition.controllerConstructor.shouldLoad) {
|
1665
1705
|
this.router.loadDefinition(definition);
|
1666
1706
|
}
|
@@ -1668,10 +1708,10 @@ class Application {
|
|
1668
1708
|
}
|
1669
1709
|
unload(head, ...rest) {
|
1670
1710
|
const identifiers = Array.isArray(head) ? head : [head, ...rest];
|
1671
|
-
identifiers.forEach(identifier => this.router.unloadIdentifier(identifier));
|
1711
|
+
identifiers.forEach((identifier) => this.router.unloadIdentifier(identifier));
|
1672
1712
|
}
|
1673
1713
|
get controllers() {
|
1674
|
-
return this.router.contexts.map(context => context.controller);
|
1714
|
+
return this.router.contexts.map((context) => context.controller);
|
1675
1715
|
}
|
1676
1716
|
getControllerForElementAndIdentifier(element, identifier) {
|
1677
1717
|
const context = this.router.getContextForElementAndIdentifier(element, identifier);
|
@@ -1690,7 +1730,7 @@ class Application {
|
|
1690
1730
|
}
|
1691
1731
|
}
|
1692
1732
|
function domReady() {
|
1693
|
-
return new Promise(resolve => {
|
1733
|
+
return new Promise((resolve) => {
|
1694
1734
|
if (document.readyState == "loading") {
|
1695
1735
|
document.addEventListener("DOMContentLoaded", () => resolve());
|
1696
1736
|
}
|
@@ -1718,18 +1758,18 @@ function propertiesForClassDefinition(key) {
|
|
1718
1758
|
const attribute = classes.getAttributeName(key);
|
1719
1759
|
throw new Error(`Missing attribute "${attribute}"`);
|
1720
1760
|
}
|
1721
|
-
}
|
1761
|
+
},
|
1722
1762
|
},
|
1723
1763
|
[`${key}Classes`]: {
|
1724
1764
|
get() {
|
1725
1765
|
return this.classes.getAll(key);
|
1726
|
-
}
|
1766
|
+
},
|
1727
1767
|
},
|
1728
1768
|
[`has${capitalize(key)}Class`]: {
|
1729
1769
|
get() {
|
1730
1770
|
return this.classes.has(key);
|
1731
|
-
}
|
1732
|
-
}
|
1771
|
+
},
|
1772
|
+
},
|
1733
1773
|
};
|
1734
1774
|
}
|
1735
1775
|
|
@@ -1750,18 +1790,18 @@ function propertiesForTargetDefinition(name) {
|
|
1750
1790
|
else {
|
1751
1791
|
throw new Error(`Missing target element "${name}" for "${this.identifier}" controller`);
|
1752
1792
|
}
|
1753
|
-
}
|
1793
|
+
},
|
1754
1794
|
},
|
1755
1795
|
[`${name}Targets`]: {
|
1756
1796
|
get() {
|
1757
1797
|
return this.targets.findAll(name);
|
1758
|
-
}
|
1798
|
+
},
|
1759
1799
|
},
|
1760
1800
|
[`has${capitalize(name)}Target`]: {
|
1761
1801
|
get() {
|
1762
1802
|
return this.targets.has(name);
|
1763
|
-
}
|
1764
|
-
}
|
1803
|
+
},
|
1804
|
+
},
|
1765
1805
|
};
|
1766
1806
|
}
|
1767
1807
|
|
@@ -1775,8 +1815,8 @@ function ValuePropertiesBlessing(constructor) {
|
|
1775
1815
|
const attributeName = this.data.getAttributeNameForKey(valueDescriptor.key);
|
1776
1816
|
return Object.assign(result, { [attributeName]: valueDescriptor });
|
1777
1817
|
}, {});
|
1778
|
-
}
|
1779
|
-
}
|
1818
|
+
},
|
1819
|
+
},
|
1780
1820
|
};
|
1781
1821
|
return valueDefinitionPairs.reduce((properties, valueDefinitionPair) => {
|
1782
1822
|
return Object.assign(properties, propertiesForValueDefinitionPair(valueDefinitionPair));
|
@@ -1803,13 +1843,13 @@ function propertiesForValueDefinitionPair(valueDefinitionPair, controller) {
|
|
1803
1843
|
else {
|
1804
1844
|
this.data.set(key, write(value));
|
1805
1845
|
}
|
1806
|
-
}
|
1846
|
+
},
|
1807
1847
|
},
|
1808
1848
|
[`has${capitalize(name)}`]: {
|
1809
1849
|
get() {
|
1810
1850
|
return this.data.has(key) || definition.hasCustomDefaultValue;
|
1811
|
-
}
|
1812
|
-
}
|
1851
|
+
},
|
1852
|
+
},
|
1813
1853
|
};
|
1814
1854
|
}
|
1815
1855
|
function parseValueDefinitionPair([token, typeDefinition], controller) {
|
@@ -1821,18 +1861,26 @@ function parseValueDefinitionPair([token, typeDefinition], controller) {
|
|
1821
1861
|
}
|
1822
1862
|
function parseValueTypeConstant(constant) {
|
1823
1863
|
switch (constant) {
|
1824
|
-
case Array:
|
1825
|
-
|
1826
|
-
case
|
1827
|
-
|
1828
|
-
case
|
1864
|
+
case Array:
|
1865
|
+
return "array";
|
1866
|
+
case Boolean:
|
1867
|
+
return "boolean";
|
1868
|
+
case Number:
|
1869
|
+
return "number";
|
1870
|
+
case Object:
|
1871
|
+
return "object";
|
1872
|
+
case String:
|
1873
|
+
return "string";
|
1829
1874
|
}
|
1830
1875
|
}
|
1831
1876
|
function parseValueTypeDefault(defaultValue) {
|
1832
1877
|
switch (typeof defaultValue) {
|
1833
|
-
case "boolean":
|
1834
|
-
|
1835
|
-
case "
|
1878
|
+
case "boolean":
|
1879
|
+
return "boolean";
|
1880
|
+
case "number":
|
1881
|
+
return "number";
|
1882
|
+
case "string":
|
1883
|
+
return "string";
|
1836
1884
|
}
|
1837
1885
|
if (Array.isArray(defaultValue))
|
1838
1886
|
return "array";
|
@@ -1854,7 +1902,7 @@ function parseValueTypeDefinition(payload) {
|
|
1854
1902
|
const typeFromObject = parseValueTypeObject({
|
1855
1903
|
controller: payload.controller,
|
1856
1904
|
token: payload.token,
|
1857
|
-
typeObject: payload.typeDefinition
|
1905
|
+
typeObject: payload.typeDefinition,
|
1858
1906
|
});
|
1859
1907
|
const typeFromDefaultValue = parseValueTypeDefault(payload.typeDefinition);
|
1860
1908
|
const typeFromConstant = parseValueTypeConstant(payload.typeDefinition);
|
@@ -1880,18 +1928,26 @@ function valueDescriptorForTokenAndTypeDefinition(payload) {
|
|
1880
1928
|
type,
|
1881
1929
|
key,
|
1882
1930
|
name: camelize(key),
|
1883
|
-
get defaultValue() {
|
1884
|
-
|
1931
|
+
get defaultValue() {
|
1932
|
+
return defaultValueForDefinition(payload.typeDefinition);
|
1933
|
+
},
|
1934
|
+
get hasCustomDefaultValue() {
|
1935
|
+
return parseValueTypeDefault(payload.typeDefinition) !== undefined;
|
1936
|
+
},
|
1885
1937
|
reader: readers[type],
|
1886
|
-
writer: writers[type] || writers.default
|
1938
|
+
writer: writers[type] || writers.default,
|
1887
1939
|
};
|
1888
1940
|
}
|
1889
1941
|
const defaultValuesByType = {
|
1890
|
-
get array() {
|
1942
|
+
get array() {
|
1943
|
+
return [];
|
1944
|
+
},
|
1891
1945
|
boolean: false,
|
1892
1946
|
number: 0,
|
1893
|
-
get object() {
|
1894
|
-
|
1947
|
+
get object() {
|
1948
|
+
return {};
|
1949
|
+
},
|
1950
|
+
string: "",
|
1895
1951
|
};
|
1896
1952
|
const readers = {
|
1897
1953
|
array(value) {
|
@@ -1916,12 +1972,12 @@ const readers = {
|
|
1916
1972
|
},
|
1917
1973
|
string(value) {
|
1918
1974
|
return value;
|
1919
|
-
}
|
1975
|
+
},
|
1920
1976
|
};
|
1921
1977
|
const writers = {
|
1922
1978
|
default: writeString,
|
1923
1979
|
array: writeJSON,
|
1924
|
-
object: writeJSON
|
1980
|
+
object: writeJSON,
|
1925
1981
|
};
|
1926
1982
|
function writeJSON(value) {
|
1927
1983
|
return JSON.stringify(value);
|