stimulus_reflex 3.5.0.pre10 → 3.5.0.rc2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of stimulus_reflex might be problematic. Click here for more details.

Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +10 -10
  3. data/README.md +3 -3
  4. data/app/assets/javascripts/stimulus_reflex.js +319 -23
  5. data/app/assets/javascripts/stimulus_reflex.umd.js +316 -25
  6. data/app/channels/stimulus_reflex/channel.rb +1 -18
  7. data/lib/generators/stimulus_reflex/stimulus_reflex_generator.rb +4 -10
  8. data/lib/generators/stimulus_reflex/templates/app/reflexes/%file_name%_reflex.rb.tt +1 -1
  9. data/lib/generators/stimulus_reflex/templates/app/reflexes/application_reflex.rb.tt +1 -1
  10. data/lib/generators/stimulus_reflex/templates/config/initializers/cable_ready.rb +5 -0
  11. data/lib/install/development.rb +2 -2
  12. data/lib/install/importmap.rb +3 -3
  13. data/lib/stimulus_reflex/cable_ready_channels.rb +1 -0
  14. data/lib/stimulus_reflex/engine.rb +0 -4
  15. data/lib/stimulus_reflex/importmap.rb +3 -3
  16. data/lib/stimulus_reflex/installer.rb +2 -2
  17. data/lib/stimulus_reflex/reflex.rb +17 -8
  18. data/lib/stimulus_reflex/reflex_data.rb +6 -2
  19. data/lib/stimulus_reflex/reflex_factory.rb +2 -1
  20. data/lib/stimulus_reflex/version.rb +1 -1
  21. data/lib/stimulus_reflex/version_checker.rb +54 -0
  22. data/lib/tasks/stimulus_reflex/stimulus_reflex.rake +0 -2
  23. data/package.json +10 -8
  24. data/rollup.config.mjs +0 -19
  25. data/stimulus_reflex.gemspec +2 -2
  26. data/yarn.lock +173 -168
  27. metadata +15 -12
  28. data/app/assets/javascripts/stimulus_reflex.min.js +0 -2
  29. data/app/assets/javascripts/stimulus_reflex.min.js.map +0 -1
  30. data/app/assets/javascripts/stimulus_reflex.umd.min.js +0 -1065
  31. data/app/assets/javascripts/stimulus_reflex.umd.min.js.map +0 -1
@@ -1,1065 +0,0 @@
1
- (function(global, factory) {
2
- typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@hotwired/stimulus"), require("@rails/actioncable"), require("cable_ready")) : typeof define === "function" && define.amd ? define([ "exports", "@hotwired/stimulus", "@rails/actioncable", "cable_ready" ], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self,
3
- factory(global.StimulusReflex = {}, global.Stimulus, global.ActionCable, global.CableReady));
4
- })(this, (function(exports, stimulus, actioncable, CableReady) {
5
- "use strict";
6
- let deprecationWarnings = true;
7
- var Deprecate = {
8
- get enabled() {
9
- return deprecationWarnings;
10
- },
11
- get disabled() {
12
- return !deprecationWarnings;
13
- },
14
- get value() {
15
- return deprecationWarnings;
16
- },
17
- set(value) {
18
- deprecationWarnings = !!value;
19
- },
20
- set deprecate(value) {
21
- deprecationWarnings = !!value;
22
- }
23
- };
24
- let debugging = false;
25
- var Debug$1 = {
26
- get enabled() {
27
- return debugging;
28
- },
29
- get disabled() {
30
- return !debugging;
31
- },
32
- get value() {
33
- return debugging;
34
- },
35
- set(value) {
36
- debugging = !!value;
37
- },
38
- set debug(value) {
39
- debugging = !!value;
40
- }
41
- };
42
- const defaultSchema = {
43
- reflexAttribute: "data-reflex",
44
- reflexPermanentAttribute: "data-reflex-permanent",
45
- reflexRootAttribute: "data-reflex-root",
46
- reflexSuppressLoggingAttribute: "data-reflex-suppress-logging",
47
- reflexDatasetAttribute: "data-reflex-dataset",
48
- reflexDatasetAllAttribute: "data-reflex-dataset-all",
49
- reflexSerializeFormAttribute: "data-reflex-serialize-form",
50
- reflexFormSelectorAttribute: "data-reflex-form-selector",
51
- reflexIncludeInnerHtmlAttribute: "data-reflex-include-inner-html",
52
- reflexIncludeTextContentAttribute: "data-reflex-include-text-content"
53
- };
54
- let schema = {};
55
- var Schema = {
56
- set(application) {
57
- schema = {
58
- ...defaultSchema,
59
- ...application.schema
60
- };
61
- for (const attribute in schema) {
62
- const attributeName = attribute.slice(0, -9);
63
- Object.defineProperty(this, attributeName, {
64
- get: () => schema[attribute],
65
- configurable: true
66
- });
67
- }
68
- }
69
- };
70
- const {debounce: debounce, dispatch: dispatch, xpathToElement: xpathToElement, xpathToElementArray: xpathToElementArray} = CableReady.Utils;
71
- const uuidv4 = () => {
72
- const crypto = window.crypto || window.msCrypto;
73
- return ([ 1e7 ] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)));
74
- };
75
- const serializeForm = (form, options = {}) => {
76
- if (!form) return "";
77
- const w = options.w || window;
78
- const {element: element} = options;
79
- const formData = new w.FormData(form);
80
- const data = Array.from(formData, (e => e.map(encodeURIComponent).join("=")));
81
- const submitButton = form.querySelector("input[type=submit]");
82
- if (element && element.name && element.nodeName === "INPUT" && element.type === "submit") {
83
- data.push(`${encodeURIComponent(element.name)}=${encodeURIComponent(element.value)}`);
84
- } else if (submitButton && submitButton.name) {
85
- data.push(`${encodeURIComponent(submitButton.name)}=${encodeURIComponent(submitButton.value)}`);
86
- }
87
- return Array.from(data).join("&");
88
- };
89
- const camelize = (value, uppercaseFirstLetter = true) => {
90
- if (typeof value !== "string") return "";
91
- value = value.replace(/[\s_](.)/g, ($1 => $1.toUpperCase())).replace(/[\s_]/g, "").replace(/^(.)/, ($1 => $1.toLowerCase()));
92
- if (uppercaseFirstLetter) value = value.substr(0, 1).toUpperCase() + value.substr(1);
93
- return value;
94
- };
95
- const XPathToElement = xpathToElement;
96
- const XPathToArray = xpathToElementArray;
97
- const emitEvent = (name, detail = {}) => dispatch(document, name, detail);
98
- const extractReflexName = reflexString => {
99
- const match = reflexString.match(/(?:.*->)?(.*?)(?:Reflex)?#/);
100
- return match ? match[1] : "";
101
- };
102
- const elementToXPath = element => {
103
- if (element.id !== "") return "//*[@id='" + element.id + "']";
104
- if (element === document.body) return "/html/body";
105
- if (element.nodeName === "HTML") return "/html";
106
- let ix = 0;
107
- const siblings = element && element.parentNode ? element.parentNode.childNodes : [];
108
- for (var i = 0; i < siblings.length; i++) {
109
- const sibling = siblings[i];
110
- if (sibling === element) {
111
- const computedPath = elementToXPath(element.parentNode);
112
- const tagName = element.tagName.toLowerCase();
113
- const ixInc = ix + 1;
114
- return `${computedPath}/${tagName}[${ixInc}]`;
115
- }
116
- if (sibling.nodeType === 1 && sibling.tagName === element.tagName) {
117
- ix++;
118
- }
119
- }
120
- };
121
- const elementInvalid = element => element.type === "number" && element.validity && element.validity.badInput;
122
- const getReflexElement = (args, element) => args[0] && args[0].nodeType === Node.ELEMENT_NODE ? args.shift() : element;
123
- const getReflexOptions = args => {
124
- const options = {};
125
- if (args[0] && typeof args[0] === "object" && Object.keys(args[0]).filter((key => [ "id", "attrs", "selectors", "reflexId", "resolveLate", "serializeForm", "suppressLogging", "includeInnerHTML", "includeTextContent" ].includes(key))).length) {
126
- const opts = args.shift();
127
- Object.keys(opts).forEach((o => {
128
- if (o === "reflexId") {
129
- if (Deprecate.enabled) console.warn("reflexId option will be removed in v4. Use id instead.");
130
- options["id"] = opts["reflexId"];
131
- } else options[o] = opts[o];
132
- }));
133
- }
134
- return options;
135
- };
136
- const getReflexRoots = element => {
137
- let list = [];
138
- while (list.length === 0 && element) {
139
- let reflexRoot = element.getAttribute(Schema.reflexRoot);
140
- if (reflexRoot) {
141
- if (reflexRoot.length === 0 && element.id) reflexRoot = `#${element.id}`;
142
- const selectors = reflexRoot.split(",").filter((s => s.trim().length));
143
- if (Debug$1.enabled && selectors.length === 0) {
144
- console.error(`No value found for ${Schema.reflexRoot}. Add an #id to the element or provide a value for ${Schema.reflexRoot}.`, element);
145
- }
146
- list = list.concat(selectors.filter((s => document.querySelector(s))));
147
- }
148
- element = element.parentElement ? element.parentElement.closest(`[${Schema.reflexRoot}]`) : null;
149
- }
150
- return list;
151
- };
152
- const stages = [ "created", "before", "delivered", "queued", "after", "finalized", "success", "error", "halted", "forbidden" ];
153
- let lastReflex;
154
- const reflexes = new Proxy({}, {
155
- get: function(target, prop) {
156
- if (stages.includes(prop)) return Object.fromEntries(Object.entries(target).filter((([_, reflex]) => reflex.stage === prop))); else if (prop === "last") return lastReflex; else if (prop === "all") return target;
157
- return Reflect.get(...arguments);
158
- },
159
- set: function(target, prop, value) {
160
- target[prop] = value;
161
- lastReflex = value;
162
- return true;
163
- }
164
- });
165
- const invokeLifecycleMethod = (reflex, stage) => {
166
- const specificLifecycleMethod = reflex.controller[[ "before", "after", "finalize" ].includes(stage) ? `${stage}${camelize(reflex.action)}` : `${camelize(reflex.action, false)}${camelize(stage)}`];
167
- const genericLifecycleMethod = reflex.controller[[ "before", "after", "finalize" ].includes(stage) ? `${stage}Reflex` : `reflex${camelize(stage)}`];
168
- if (typeof specificLifecycleMethod === "function") {
169
- specificLifecycleMethod.call(reflex.controller, reflex.element, reflex.target, reflex.error, reflex.id, reflex.payload);
170
- }
171
- if (typeof genericLifecycleMethod === "function") {
172
- genericLifecycleMethod.call(reflex.controller, reflex.element, reflex.target, reflex.error, reflex.id, reflex.payload);
173
- }
174
- };
175
- const dispatchLifecycleEvent = (reflex, stage) => {
176
- if (!reflex.controller.element.parentElement) {
177
- if (Debug$1.enabled && !reflex.warned) {
178
- console.warn(`StimulusReflex was not able execute callbacks or emit events for "${stage}" or later life-cycle stages for this Reflex. The StimulusReflex Controller Element is no longer present in the DOM. Could you move the StimulusReflex Controller to an element higher in your DOM?`);
179
- reflex.warned = true;
180
- }
181
- return;
182
- }
183
- reflex.stage = stage;
184
- reflex.lifecycle.push(stage);
185
- const event = `stimulus-reflex:${stage}`;
186
- const action = `${event}:${reflex.action}`;
187
- const detail = {
188
- reflex: reflex.target,
189
- controller: reflex.controller,
190
- id: reflex.id,
191
- element: reflex.element,
192
- payload: reflex.payload
193
- };
194
- const options = {
195
- bubbles: true,
196
- cancelable: false,
197
- detail: detail
198
- };
199
- reflex.controller.element.dispatchEvent(new CustomEvent(event, options));
200
- reflex.controller.element.dispatchEvent(new CustomEvent(action, options));
201
- if (window.jQuery) {
202
- window.jQuery(reflex.controller.element).trigger(event, detail);
203
- window.jQuery(reflex.controller.element).trigger(action, detail);
204
- }
205
- };
206
- document.addEventListener("stimulus-reflex:before", (event => invokeLifecycleMethod(reflexes[event.detail.id], "before")), true);
207
- document.addEventListener("stimulus-reflex:queued", (event => invokeLifecycleMethod(reflexes[event.detail.id], "queued")), true);
208
- document.addEventListener("stimulus-reflex:delivered", (event => invokeLifecycleMethod(reflexes[event.detail.id], "delivered")), true);
209
- document.addEventListener("stimulus-reflex:success", (event => {
210
- const reflex = reflexes[event.detail.id];
211
- invokeLifecycleMethod(reflex, "success");
212
- dispatchLifecycleEvent(reflex, "after");
213
- }), true);
214
- document.addEventListener("stimulus-reflex:nothing", (event => dispatchLifecycleEvent(reflexes[event.detail.id], "success")), true);
215
- document.addEventListener("stimulus-reflex:error", (event => {
216
- const reflex = reflexes[event.detail.id];
217
- invokeLifecycleMethod(reflex, "error");
218
- dispatchLifecycleEvent(reflex, "after");
219
- }), true);
220
- document.addEventListener("stimulus-reflex:halted", (event => invokeLifecycleMethod(reflexes[event.detail.id], "halted")), true);
221
- document.addEventListener("stimulus-reflex:forbidden", (event => invokeLifecycleMethod(reflexes[event.detail.id], "forbidden")), true);
222
- document.addEventListener("stimulus-reflex:after", (event => invokeLifecycleMethod(reflexes[event.detail.id], "after")), true);
223
- document.addEventListener("stimulus-reflex:finalize", (event => invokeLifecycleMethod(reflexes[event.detail.id], "finalize")), true);
224
- let app = {};
225
- var App = {
226
- get app() {
227
- return app;
228
- },
229
- set(application) {
230
- app = application;
231
- }
232
- };
233
- let isolationMode = false;
234
- var IsolationMode = {
235
- get disabled() {
236
- return !isolationMode;
237
- },
238
- set(value) {
239
- isolationMode = value;
240
- if (Deprecate.enabled && !isolationMode) {
241
- document.addEventListener("DOMContentLoaded", (() => console.warn("Deprecation warning: the next version of StimulusReflex will standardize isolation mode, and the isolate option will be removed.\nPlease update your applications to assume that every tab will be isolated. Use CableReady operations to broadcast updates to other tabs and users.")), {
242
- once: true
243
- });
244
- }
245
- }
246
- };
247
- class Reflex {
248
- constructor(data, controller) {
249
- this.data = data.valueOf();
250
- this.controller = controller;
251
- this.element = data.reflexElement;
252
- this.id = data.id;
253
- this.error = null;
254
- this.payload = null;
255
- this.stage = "created";
256
- this.lifecycle = [ "created" ];
257
- this.warned = false;
258
- this.target = data.target;
259
- this.action = data.target.split("#")[1];
260
- this.selector = null;
261
- this.morph = null;
262
- this.operation = null;
263
- this.timestamp = new Date;
264
- this.cloned = false;
265
- }
266
- get getPromise() {
267
- const promise = new Promise(((resolve, reject) => {
268
- this.promise = {
269
- resolve: resolve,
270
- reject: reject,
271
- data: this.data
272
- };
273
- }));
274
- promise.id = this.id;
275
- Object.defineProperty(promise, "reflexId", {
276
- get() {
277
- if (Deprecate.enabled) console.warn("reflexId is deprecated and will be removed from v4. Use id instead.");
278
- return this.id;
279
- }
280
- });
281
- promise.reflex = this;
282
- if (Debug$1.enabled) promise.catch((() => {}));
283
- return promise;
284
- }
285
- }
286
- const received = data => {
287
- if (!data.cableReady) return;
288
- if (data.version.replace(".pre", "-pre") !== CableReady.version) {
289
- if (Debug$1.enabled) console.error(`Reflex failed due to cable_ready gem/NPM package version mismatch. Package versions must match exactly.\nNote that if you are using pre-release builds, gems use the "x.y.z.preN" version format, while NPM packages use "x.y.z-preN".\n\ncable_ready gem: ${data.version}\ncable_ready NPM: ${CableReady.version}`);
290
- return;
291
- }
292
- let reflexOperations = [];
293
- for (let i = data.operations.length - 1; i >= 0; i--) {
294
- if (data.operations[i].stimulusReflex) {
295
- reflexOperations.push(data.operations[i]);
296
- data.operations.splice(i, 1);
297
- }
298
- }
299
- if (reflexOperations.some((operation => operation.stimulusReflex.url !== location.href))) {
300
- if (Debug$1.enabled) {
301
- console.error("Reflex failed due to mismatched URL.");
302
- return;
303
- }
304
- }
305
- let reflexData;
306
- if (reflexOperations.length) {
307
- reflexData = reflexOperations[0].stimulusReflex;
308
- reflexData.payload = reflexOperations[0].payload;
309
- }
310
- if (reflexData) {
311
- const {id: id, payload: payload} = reflexData;
312
- let reflex;
313
- if (!reflexes[id] && IsolationMode.disabled) {
314
- const controllerElement = XPathToElement(reflexData.xpathController);
315
- const reflexElement = XPathToElement(reflexData.xpathElement);
316
- controllerElement.reflexController = controllerElement.reflexController || {};
317
- controllerElement.reflexData = controllerElement.reflexData || {};
318
- controllerElement.reflexError = controllerElement.reflexError || {};
319
- const controller = App.app.getControllerForElementAndIdentifier(controllerElement, reflexData.reflexController);
320
- controllerElement.reflexController[id] = controller;
321
- controllerElement.reflexData[id] = reflexData;
322
- reflex = new Reflex(reflexData, controller);
323
- reflexes[id] = reflex;
324
- reflex.cloned = true;
325
- reflex.element = reflexElement;
326
- controller.lastReflex = reflex;
327
- dispatchLifecycleEvent(reflex, "before");
328
- reflex.getPromise;
329
- } else {
330
- reflex = reflexes[id];
331
- }
332
- if (reflex) {
333
- reflex.payload = payload;
334
- reflex.totalOperations = reflexOperations.length;
335
- reflex.pendingOperations = reflexOperations.length;
336
- reflex.completedOperations = 0;
337
- reflex.piggybackOperations = data.operations;
338
- CableReady.perform(reflexOperations);
339
- }
340
- } else {
341
- if (data.operations.length && reflexes[data.operations[0].reflexId]) {
342
- CableReady.perform(data.operations);
343
- }
344
- }
345
- };
346
- let consumer;
347
- let params;
348
- let subscription;
349
- let active;
350
- const initialize$1 = (consumerValue, paramsValue) => {
351
- consumer = consumerValue;
352
- params = paramsValue;
353
- document.addEventListener("DOMContentLoaded", (() => {
354
- active = false;
355
- connectionStatusClass();
356
- if (Deprecate.enabled && consumerValue) console.warn("Deprecation warning: the next version of StimulusReflex will obtain a reference to consumer via the Stimulus application object.\nPlease add 'application.consumer = consumer' to your index.js after your Stimulus application has been established, and remove the consumer key from your StimulusReflex initialize() options object.");
357
- }));
358
- document.addEventListener("turbolinks:load", connectionStatusClass);
359
- document.addEventListener("turbo:load", connectionStatusClass);
360
- };
361
- const subscribe = controller => {
362
- if (subscription) return;
363
- consumer = consumer || controller.application.consumer || actioncable.createConsumer();
364
- const {channel: channel} = controller.StimulusReflex;
365
- const request = {
366
- channel: channel,
367
- ...params
368
- };
369
- const identifier = JSON.stringify(request);
370
- subscription = consumer.subscriptions.findAll(identifier)[0] || consumer.subscriptions.create(request, {
371
- received: received,
372
- connected: connected,
373
- rejected: rejected,
374
- disconnected: disconnected
375
- });
376
- };
377
- const connected = () => {
378
- active = true;
379
- connectionStatusClass();
380
- emitEvent("stimulus-reflex:connected");
381
- Object.values(reflexes.queued).forEach((reflex => {
382
- subscription.send(reflex.data);
383
- dispatchLifecycleEvent(reflex, "delivered");
384
- }));
385
- };
386
- const rejected = () => {
387
- active = false;
388
- connectionStatusClass();
389
- emitEvent("stimulus-reflex:rejected");
390
- if (Debug.enabled) console.warn("Channel subscription was rejected.");
391
- };
392
- const disconnected = willAttemptReconnect => {
393
- active = false;
394
- connectionStatusClass();
395
- emitEvent("stimulus-reflex:disconnected", willAttemptReconnect);
396
- };
397
- const deliver = reflex => {
398
- if (active) {
399
- subscription.send(reflex.data);
400
- dispatchLifecycleEvent(reflex, "delivered");
401
- } else dispatchLifecycleEvent(reflex, "queued");
402
- };
403
- const connectionStatusClass = () => {
404
- const list = document.body.classList;
405
- if (!(list.contains("stimulus-reflex-connected") || list.contains("stimulus-reflex-disconnected"))) {
406
- list.add(active ? "stimulus-reflex-connected" : "stimulus-reflex-disconnected");
407
- return;
408
- }
409
- if (active) {
410
- list.replace("stimulus-reflex-disconnected", "stimulus-reflex-connected");
411
- } else {
412
- list.replace("stimulus-reflex-connected", "stimulus-reflex-disconnected");
413
- }
414
- };
415
- var ActionCableTransport = {
416
- subscribe: subscribe,
417
- deliver: deliver,
418
- initialize: initialize$1
419
- };
420
- const request = reflex => {
421
- if (Debug$1.disabled || reflex.data.suppressLogging) return;
422
- console.log(`↑ stimulus ↑ ${reflex.target}`, {
423
- id: reflex.id,
424
- args: reflex.data.args,
425
- controller: reflex.controller.identifier,
426
- element: reflex.element,
427
- controllerElement: reflex.controller.element
428
- });
429
- };
430
- const success = reflex => {
431
- if (Debug$1.disabled || reflex.data.suppressLogging) return;
432
- const output = {
433
- id: reflex.id,
434
- morph: reflex.morph,
435
- payload: reflex.payload
436
- };
437
- if (reflex.operation !== "dispatch_event") output.operation = reflex.operation;
438
- console.log(`↓ reflex ↓ ${reflex.target} → ${reflex.selector || "∞"}${progress(reflex)} ${duration(reflex)}`, output);
439
- };
440
- const halted$1 = reflex => {
441
- if (Debug$1.disabled || reflex.data.suppressLogging) return;
442
- console.log(`↓ reflex ↓ ${reflex.target} ${duration(reflex)} %cHALTED`, "color: #ffa500;", {
443
- id: reflex.id,
444
- payload: reflex.payload
445
- });
446
- };
447
- const forbidden$1 = reflex => {
448
- if (Debug$1.disabled || reflex.data.suppressLogging) return;
449
- console.log(`↓ reflex ↓ ${reflex.target} ${duration(reflex)} %cFORBIDDEN`, "color: #BF40BF;", {
450
- id: reflex.id,
451
- payload: reflex.payload
452
- });
453
- };
454
- const error$1 = reflex => {
455
- if (Debug$1.disabled || reflex.data.suppressLogging) return;
456
- console.log(`↓ reflex ↓ ${reflex.target} ${duration(reflex)} %cERROR: ${reflex.error}`, "color: #f00;", {
457
- id: reflex.id,
458
- payload: reflex.payload
459
- });
460
- };
461
- const duration = reflex => !reflex.cloned ? `in ${new Date - reflex.timestamp}ms` : "CLONED";
462
- const progress = reflex => reflex.totalOperations > 1 ? ` ${reflex.completedOperations}/${reflex.totalOperations}` : "";
463
- var Log = {
464
- request: request,
465
- success: success,
466
- halted: halted$1,
467
- forbidden: forbidden$1,
468
- error: error$1
469
- };
470
- const multipleInstances = element => {
471
- if ([ "checkbox", "radio" ].includes(element.type)) {
472
- return document.querySelectorAll(`input[type="${element.type}"][name="${element.name}"]`).length > 1;
473
- }
474
- return false;
475
- };
476
- const collectCheckedOptions = element => Array.from(element.querySelectorAll("option:checked")).concat(Array.from(document.querySelectorAll(`input[type="${element.type}"][name="${element.name}"]`)).filter((elem => elem.checked))).map((o => o.value));
477
- const attributeValue = (values = []) => {
478
- const value = Array.from(new Set(values.filter((v => v && String(v).length)).map((v => v.trim())))).join(" ").trim();
479
- return value.length > 0 ? value : null;
480
- };
481
- const attributeValues = value => {
482
- if (!value) return [];
483
- if (!value.length) return [];
484
- return value.split(" ").filter((v => v.trim().length));
485
- };
486
- const extractElementAttributes = element => {
487
- let attrs = Array.from(element.attributes).reduce(((memo, attr) => {
488
- memo[attr.name] = attr.value;
489
- return memo;
490
- }), {});
491
- attrs.checked = !!element.checked;
492
- attrs.selected = !!element.selected;
493
- attrs.tag_name = element.tagName;
494
- if (element.tagName.match(/select/i) || multipleInstances(element)) {
495
- const collectedOptions = collectCheckedOptions(element);
496
- attrs.values = collectedOptions;
497
- attrs.value = collectedOptions.join(",");
498
- } else {
499
- attrs.value = element.value;
500
- }
501
- return attrs;
502
- };
503
- const getElementsFromTokens = (element, tokens) => {
504
- if (!tokens || tokens.length === 0) return [];
505
- let elements = [ element ];
506
- const xPath = elementToXPath(element);
507
- tokens.forEach((token => {
508
- try {
509
- switch (token) {
510
- case "combined":
511
- if (Deprecate.enabled) console.warn("In the next version of StimulusReflex, the 'combined' option to data-reflex-dataset will become 'ancestors'.");
512
- elements = [ ...elements, ...XPathToArray(`${xPath}/ancestor::*`, true) ];
513
- break;
514
-
515
- case "ancestors":
516
- elements = [ ...elements, ...XPathToArray(`${xPath}/ancestor::*`, true) ];
517
- break;
518
-
519
- case "parent":
520
- elements = [ ...elements, ...XPathToArray(`${xPath}/parent::*`) ];
521
- break;
522
-
523
- case "siblings":
524
- elements = [ ...elements, ...XPathToArray(`${xPath}/preceding-sibling::*|${xPath}/following-sibling::*`) ];
525
- break;
526
-
527
- case "children":
528
- elements = [ ...elements, ...XPathToArray(`${xPath}/child::*`) ];
529
- break;
530
-
531
- case "descendants":
532
- elements = [ ...elements, ...XPathToArray(`${xPath}/descendant::*`) ];
533
- break;
534
-
535
- default:
536
- elements = [ ...elements, ...document.querySelectorAll(token) ];
537
- }
538
- } catch (error) {
539
- if (Debug$1.enabled) console.error(error);
540
- }
541
- }));
542
- return elements;
543
- };
544
- const extractElementDataset = element => {
545
- const dataset = element.attributes[Schema.reflexDataset];
546
- const allDataset = element.attributes[Schema.reflexDatasetAll];
547
- const tokens = dataset && dataset.value.split(" ") || [];
548
- const allTokens = allDataset && allDataset.value.split(" ") || [];
549
- const datasetElements = getElementsFromTokens(element, tokens);
550
- const datasetAllElements = getElementsFromTokens(element, allTokens);
551
- const datasetAttributes = datasetElements.reduce(((acc, ele) => ({
552
- ...extractDataAttributes(ele),
553
- ...acc
554
- })), {});
555
- const reflexElementAttributes = extractDataAttributes(element);
556
- const elementDataset = {
557
- dataset: {
558
- ...reflexElementAttributes,
559
- ...datasetAttributes
560
- },
561
- datasetAll: {}
562
- };
563
- datasetAllElements.forEach((element => {
564
- const elementAttributes = extractDataAttributes(element);
565
- Object.keys(elementAttributes).forEach((key => {
566
- const value = elementAttributes[key];
567
- if (elementDataset.datasetAll[key] && Array.isArray(elementDataset.datasetAll[key])) {
568
- elementDataset.datasetAll[key].push(value);
569
- } else {
570
- elementDataset.datasetAll[key] = [ value ];
571
- }
572
- }));
573
- }));
574
- return elementDataset;
575
- };
576
- const extractDataAttributes = element => {
577
- let attrs = {};
578
- if (element && element.attributes) {
579
- Array.from(element.attributes).forEach((attr => {
580
- if (attr.name.startsWith("data-")) {
581
- attrs[attr.name] = attr.value;
582
- }
583
- }));
584
- }
585
- return attrs;
586
- };
587
- var name = "stimulus_reflex";
588
- var version = "3.5.0-pre10";
589
- var description = "Build reactive applications with the Rails tooling you already know and love.";
590
- var keywords = [ "ruby", "rails", "websockets", "actioncable", "turbolinks", "reactive", "cable", "ujs", "ssr", "stimulus", "reflex", "stimulus_reflex", "dom", "morphdom" ];
591
- var homepage = "https://docs.stimulusreflex.com";
592
- var bugs = "https://github.com/stimulusreflex/stimulus_reflex/issues";
593
- var repository = "https://github.com/stimulusreflex/stimulus_reflex";
594
- var license = "MIT";
595
- var author = "Nathan Hopkins <natehop@gmail.com>";
596
- var contributors = [ "Andrew Mason <andrewmcodes@protonmail.com>", "Julian Rubisch <julian@julianrubisch.at>", "Marco Roth <marco.roth@intergga.ch>", "Nathan Hopkins <natehop@gmail.com>" ];
597
- var main = "./dist/stimulus_reflex.js";
598
- var module = "./dist/stimulus_reflex.js";
599
- var browser = "./dist/stimulus_reflex.js";
600
- var unpkg = "./dist/stimulus_reflex.umd.js";
601
- var umd = "./dist/stimulus_reflex.umd.js";
602
- var files = [ "dist/*", "javascript/*" ];
603
- var scripts = {
604
- lint: "yarn run format --check",
605
- format: "yarn run prettier-standard ./javascript/**/*.js rollup.config.mjs",
606
- build: "yarn rollup -c",
607
- "build:watch": "yarn rollup -wc",
608
- watch: "yarn build:watch",
609
- test: "web-test-runner javascript/test/**/*.test.js",
610
- "docs:dev": "vitepress dev docs",
611
- "docs:build": "vitepress build docs",
612
- "docs:preview": "vitepress preview docs"
613
- };
614
- var peerDependencies = {
615
- "@hotwired/stimulus": ">= 3.0"
616
- };
617
- var dependencies = {
618
- "@hotwired/stimulus": ">= 3.0, < 4",
619
- "@rails/actioncable": ">= 6.0, < 8",
620
- cable_ready: "5.0.0-pre10"
621
- };
622
- var devDependencies = {
623
- "@open-wc/testing": "^3.1.7",
624
- "@rollup/plugin-json": "^6.0.0",
625
- "@rollup/plugin-node-resolve": "^15.0.1",
626
- "@rollup/plugin-terser": "^0.4.0",
627
- "@web/dev-server-esbuild": "^0.3.3",
628
- "@web/dev-server-rollup": "^0.3.21",
629
- "@web/test-runner": "^0.15.0",
630
- "prettier-standard": "^16.4.1",
631
- rollup: "^3.17.1",
632
- vitepress: "^1.0.0-alpha.47"
633
- };
634
- var packageInfo = {
635
- name: name,
636
- version: version,
637
- description: description,
638
- keywords: keywords,
639
- homepage: homepage,
640
- bugs: bugs,
641
- repository: repository,
642
- license: license,
643
- author: author,
644
- contributors: contributors,
645
- main: main,
646
- module: module,
647
- browser: browser,
648
- import: "./dist/stimulus_reflex.js",
649
- unpkg: unpkg,
650
- umd: umd,
651
- files: files,
652
- scripts: scripts,
653
- peerDependencies: peerDependencies,
654
- dependencies: dependencies,
655
- devDependencies: devDependencies
656
- };
657
- class ReflexData {
658
- constructor(options, reflexElement, controllerElement, reflexController, permanentAttributeName, target, args, url, tabId) {
659
- this.options = options;
660
- this.reflexElement = reflexElement;
661
- this.controllerElement = controllerElement;
662
- this.reflexController = reflexController;
663
- this.permanentAttributeName = permanentAttributeName;
664
- this.target = target;
665
- this.args = args;
666
- this.url = url;
667
- this.tabId = tabId;
668
- }
669
- get attrs() {
670
- this._attrs = this._attrs || this.options["attrs"] || extractElementAttributes(this.reflexElement);
671
- return this._attrs;
672
- }
673
- get id() {
674
- this._id = this._id || this.options["id"] || uuidv4();
675
- return this._id;
676
- }
677
- get selectors() {
678
- this._selectors = this._selectors || this.options["selectors"] || getReflexRoots(this.reflexElement);
679
- return typeof this._selectors === "string" ? [ this._selectors ] : this._selectors;
680
- }
681
- get resolveLate() {
682
- return this.options["resolveLate"] || false;
683
- }
684
- get dataset() {
685
- this._dataset = this._dataset || extractElementDataset(this.reflexElement);
686
- return this._dataset;
687
- }
688
- get innerHTML() {
689
- return this.includeInnerHtml ? this.reflexElement.innerHTML : "";
690
- }
691
- get textContent() {
692
- return this.includeTextContent ? this.reflexElement.textContent : "";
693
- }
694
- get xpathController() {
695
- return elementToXPath(this.controllerElement);
696
- }
697
- get xpathElement() {
698
- return elementToXPath(this.reflexElement);
699
- }
700
- get formSelector() {
701
- const attr = this.reflexElement.attributes[Schema.reflexFormSelector] ? this.reflexElement.attributes[Schema.reflexFormSelector].value : undefined;
702
- return this.options["formSelector"] || attr;
703
- }
704
- get includeInnerHtml() {
705
- const attr = this.reflexElement.attributes[Schema.reflexIncludeInnerHtml] || false;
706
- return this.options["includeInnerHTML"] || attr ? attr.value !== "false" : false;
707
- }
708
- get includeTextContent() {
709
- const attr = this.reflexElement.attributes[Schema.reflexIncludeTextContent] || false;
710
- return this.options["includeTextContent"] || attr ? attr.value !== "false" : false;
711
- }
712
- get suppressLogging() {
713
- return this.options["suppressLogging"] || this.reflexElement.attributes[Schema.reflexSuppressLogging] || false;
714
- }
715
- valueOf() {
716
- return {
717
- attrs: this.attrs,
718
- dataset: this.dataset,
719
- selectors: this.selectors,
720
- id: this.id,
721
- resolveLate: this.resolveLate,
722
- suppressLogging: this.suppressLogging,
723
- xpathController: this.xpathController,
724
- xpathElement: this.xpathElement,
725
- inner_html: this.innerHTML,
726
- text_content: this.textContent,
727
- formSelector: this.formSelector,
728
- reflexController: this.reflexController,
729
- permanentAttributeName: this.permanentAttributeName,
730
- target: this.target,
731
- args: this.args,
732
- url: this.url,
733
- tabId: this.tabId,
734
- version: packageInfo.version
735
- };
736
- }
737
- }
738
- let transport = {};
739
- var Transport = {
740
- get plugin() {
741
- return transport;
742
- },
743
- set(newTransport) {
744
- transport = newTransport;
745
- }
746
- };
747
- const beforeDOMUpdate = event => {
748
- const {stimulusReflex: stimulusReflex} = event.detail || {};
749
- if (!stimulusReflex) return;
750
- const reflex = reflexes[stimulusReflex.id];
751
- reflex.pendingOperations--;
752
- if (reflex.pendingOperations > 0) return;
753
- if (!stimulusReflex.resolveLate) setTimeout((() => reflex.promise.resolve({
754
- element: reflex.element,
755
- event: event,
756
- data: reflex.data,
757
- payload: reflex.payload,
758
- id: reflex.id,
759
- toString: () => ""
760
- })));
761
- setTimeout((() => dispatchLifecycleEvent(reflex, "success")));
762
- };
763
- const afterDOMUpdate = event => {
764
- const {stimulusReflex: stimulusReflex} = event.detail || {};
765
- if (!stimulusReflex) return;
766
- const reflex = reflexes[stimulusReflex.id];
767
- reflex.completedOperations++;
768
- reflex.selector = event.detail.selector;
769
- reflex.morph = event.detail.stimulusReflex.morph;
770
- reflex.operation = event.type.split(":")[1].split("-").slice(1).join("_");
771
- Log.success(reflex);
772
- if (reflex.completedOperations < reflex.totalOperations) return;
773
- if (stimulusReflex.resolveLate) setTimeout((() => reflex.promise.resolve({
774
- element: reflex.element,
775
- event: event,
776
- data: reflex.data,
777
- payload: reflex.payload,
778
- id: reflex.id,
779
- toString: () => ""
780
- })));
781
- setTimeout((() => dispatchLifecycleEvent(reflex, "finalize")));
782
- if (reflex.piggybackOperations.length) CableReady.perform(reflex.piggybackOperations);
783
- };
784
- const routeReflexEvent = event => {
785
- const {stimulusReflex: stimulusReflex, name: name} = event.detail || {};
786
- const eventType = name.split("-")[2];
787
- const eventTypes = {
788
- nothing: nothing,
789
- halted: halted,
790
- forbidden: forbidden,
791
- error: error
792
- };
793
- if (!stimulusReflex || !Object.keys(eventTypes).includes(eventType)) return;
794
- const reflex = reflexes[stimulusReflex.id];
795
- reflex.completedOperations++;
796
- reflex.pendingOperations--;
797
- reflex.selector = event.detail.selector;
798
- reflex.morph = event.detail.stimulusReflex.morph;
799
- reflex.operation = event.type.split(":")[1].split("-").slice(1).join("_");
800
- if (eventType === "error") reflex.error = event.detail.error;
801
- eventTypes[eventType](reflex, event);
802
- setTimeout((() => dispatchLifecycleEvent(reflex, eventType)));
803
- if (reflex.piggybackOperations.length) CableReady.perform(reflex.piggybackOperations);
804
- };
805
- const nothing = (reflex, event) => {
806
- Log.success(reflex);
807
- setTimeout((() => reflex.promise.resolve({
808
- data: reflex.data,
809
- element: reflex.element,
810
- event: event,
811
- payload: reflex.payload,
812
- id: reflex.id,
813
- toString: () => ""
814
- })));
815
- };
816
- const halted = (reflex, event) => {
817
- Log.halted(reflex, event);
818
- setTimeout((() => reflex.promise.resolve({
819
- data: reflex.data,
820
- element: reflex.element,
821
- event: event,
822
- payload: reflex.payload,
823
- id: reflex.id,
824
- toString: () => ""
825
- })));
826
- };
827
- const forbidden = (reflex, event) => {
828
- Log.forbidden(reflex, event);
829
- setTimeout((() => reflex.promise.resolve({
830
- data: reflex.data,
831
- element: reflex.element,
832
- event: event,
833
- payload: reflex.payload,
834
- id: reflex.id,
835
- toString: () => ""
836
- })));
837
- };
838
- const error = (reflex, event) => {
839
- Log.error(reflex, event);
840
- setTimeout((() => reflex.promise.reject({
841
- data: reflex.data,
842
- element: reflex.element,
843
- event: event,
844
- payload: reflex.payload,
845
- id: reflex.id,
846
- error: reflex.error,
847
- toString: () => reflex.error
848
- })));
849
- };
850
- const localReflexControllers = element => attributeValues(element.getAttribute(Schema.controller)).reduce(((memo, name) => {
851
- const controller = App.app.getControllerForElementAndIdentifier(element, name);
852
- if (controller && controller.StimulusReflex) memo.push(controller);
853
- return memo;
854
- }), []);
855
- const allReflexControllers = element => {
856
- let controllers = [];
857
- while (element) {
858
- controllers = controllers.concat(localReflexControllers(element));
859
- element = element.parentElement;
860
- }
861
- return controllers;
862
- };
863
- const findControllerByReflexName = (reflexName, controllers) => {
864
- const controller = controllers.find((controller => {
865
- if (!controller.identifier) return;
866
- return extractReflexName(reflexName).replace(/([a-z0–9])([A-Z])/g, "$1-$2").replace(/(::)/g, "--").toLowerCase() === controller.identifier;
867
- }));
868
- return controller || controllers[0];
869
- };
870
- const scanForReflexes = debounce((() => {
871
- const reflexElements = document.querySelectorAll(`[${Schema.reflex}]`);
872
- reflexElements.forEach((element => scanForReflexesOnElement(element)));
873
- }), 20);
874
- const scanForReflexesOnElement = element => {
875
- const controllerAttribute = element.getAttribute(Schema.controller);
876
- const controllers = attributeValues(controllerAttribute);
877
- const reflexAttribute = element.getAttribute(Schema.reflex);
878
- const reflexAttributeNames = attributeValues(reflexAttribute);
879
- const actionAttribute = element.getAttribute(Schema.action);
880
- const actions = attributeValues(actionAttribute).filter((action => !action.includes("#__perform")));
881
- reflexAttributeNames.forEach((reflexName => {
882
- const controller = findControllerByReflexName(reflexName, allReflexControllers(element));
883
- const controllerName = controller ? controller.identifier : "stimulus-reflex";
884
- actions.push(`${reflexName.split("->")[0]}->${controllerName}#__perform`);
885
- controllers.push(controllerName);
886
- }));
887
- const controllerValue = attributeValue(controllers);
888
- const actionValue = attributeValue(actions);
889
- let emitReadyEvent = false;
890
- if (controllerValue && element.getAttribute(Schema.controller) != controllerValue) {
891
- element.setAttribute(Schema.controller, controllerValue);
892
- emitReadyEvent = true;
893
- }
894
- if (actionValue && element.getAttribute(Schema.action) != actionValue) {
895
- element.setAttribute(Schema.action, actionValue);
896
- emitReadyEvent = true;
897
- }
898
- if (emitReadyEvent) {
899
- dispatch(element, "stimulus-reflex:ready", {
900
- reflex: reflexAttribute,
901
- controller: controllerValue,
902
- action: actionValue,
903
- element: element
904
- });
905
- }
906
- };
907
- class StimulusReflexController extends stimulus.Controller {
908
- constructor(...args) {
909
- super(...args);
910
- register(this);
911
- }
912
- }
913
- const tabId = uuidv4();
914
- const initialize = (application, {controller: controller, consumer: consumer, debug: debug, params: params, isolate: isolate, deprecate: deprecate, transport: transport} = {}) => {
915
- Transport.set(transport || ActionCableTransport);
916
- Transport.plugin.initialize(consumer, params);
917
- IsolationMode.set(!!isolate);
918
- App.set(application);
919
- Schema.set(application);
920
- App.app.register("stimulus-reflex", controller || StimulusReflexController);
921
- Debug$1.set(!!debug);
922
- if (typeof deprecate !== "undefined") Deprecate.set(deprecate);
923
- const observer = new MutationObserver(scanForReflexes);
924
- observer.observe(document.documentElement, {
925
- attributeFilter: [ Schema.reflex, Schema.action ],
926
- childList: true,
927
- subtree: true
928
- });
929
- emitEvent("stimulus-reflex:initialized");
930
- };
931
- const register = (controller, options = {}) => {
932
- const channel = "StimulusReflex::Channel";
933
- controller.StimulusReflex = {
934
- ...options,
935
- channel: channel
936
- };
937
- Transport.plugin.subscribe(controller);
938
- Object.assign(controller, {
939
- stimulate() {
940
- const url = location.href;
941
- const controllerElement = this.element;
942
- const args = Array.from(arguments);
943
- const target = args.shift() || "StimulusReflex::Reflex#default_reflex";
944
- const reflexElement = getReflexElement(args, controllerElement);
945
- if (elementInvalid(reflexElement)) {
946
- if (Debug$1.enabled) console.warn("Reflex aborted: invalid numeric input");
947
- return;
948
- }
949
- const options = getReflexOptions(args);
950
- const reflexData = new ReflexData(options, reflexElement, controllerElement, this.identifier, Schema.reflexPermanent, target, args, url, tabId);
951
- const id = reflexData.id;
952
- controllerElement.reflexController = controllerElement.reflexController || {};
953
- controllerElement.reflexData = controllerElement.reflexData || {};
954
- controllerElement.reflexError = controllerElement.reflexError || {};
955
- controllerElement.reflexController[id] = this;
956
- controllerElement.reflexData[id] = reflexData.valueOf();
957
- const reflex = new Reflex(reflexData, this);
958
- reflexes[id] = reflex;
959
- this.lastReflex = reflex;
960
- dispatchLifecycleEvent(reflex, "before");
961
- setTimeout((() => {
962
- const {params: params} = controllerElement.reflexData[id] || {};
963
- const check = reflexElement.attributes[Schema.reflexSerializeForm];
964
- if (check) {
965
- options["serializeForm"] = check.value !== "false";
966
- }
967
- const form = reflexElement.closest(reflexData.formSelector) || document.querySelector(reflexData.formSelector) || reflexElement.closest("form");
968
- if (Deprecate.enabled && options["serializeForm"] === undefined && form) console.warn(`Deprecation warning: the next version of StimulusReflex will not serialize forms by default.\nPlease set ${Schema.reflexSerializeForm}="true" on your Reflex Controller Element or pass { serializeForm: true } as an option to stimulate.`);
969
- const formData = options["serializeForm"] === false ? "" : serializeForm(form, {
970
- element: reflexElement
971
- });
972
- reflex.data = {
973
- ...reflexData.valueOf(),
974
- params: params,
975
- formData: formData
976
- };
977
- controllerElement.reflexData[id] = reflex.data;
978
- Transport.plugin.deliver(reflex);
979
- }));
980
- Log.request(reflex);
981
- return reflex.getPromise;
982
- },
983
- __perform(event) {
984
- let element = event.target;
985
- let reflex;
986
- while (element && !reflex) {
987
- reflex = element.getAttribute(Schema.reflex);
988
- if (!reflex || !reflex.trim().length) element = element.parentElement;
989
- }
990
- const match = attributeValues(reflex).find((reflex => reflex.split("->")[0] === event.type));
991
- if (match) {
992
- event.preventDefault();
993
- event.stopPropagation();
994
- this.stimulate(match.split("->")[1], element);
995
- }
996
- }
997
- });
998
- if (!controller.reflexes) Object.defineProperty(controller, "reflexes", {
999
- get() {
1000
- return new Proxy(reflexes, {
1001
- get: function(target, prop) {
1002
- if (prop === "last") return this.lastReflex;
1003
- return Object.fromEntries(Object.entries(target[prop]).filter((([_, reflex]) => reflex.controller === this)));
1004
- }.bind(this)
1005
- });
1006
- }
1007
- });
1008
- scanForReflexesOnElement(controller.element);
1009
- emitEvent("stimulus-reflex:controller-registered", {
1010
- detail: {
1011
- controller: controller
1012
- }
1013
- });
1014
- };
1015
- const useReflex = (controller, options = {}) => {
1016
- register(controller, options);
1017
- };
1018
- document.addEventListener("cable-ready:after-dispatch-event", routeReflexEvent);
1019
- document.addEventListener("cable-ready:before-inner-html", beforeDOMUpdate);
1020
- document.addEventListener("cable-ready:before-morph", beforeDOMUpdate);
1021
- document.addEventListener("cable-ready:after-inner-html", afterDOMUpdate);
1022
- document.addEventListener("cable-ready:after-morph", afterDOMUpdate);
1023
- document.addEventListener("readystatechange", (() => {
1024
- if (document.readyState === "complete") {
1025
- scanForReflexes();
1026
- }
1027
- }));
1028
- var StimulusReflex = Object.freeze({
1029
- __proto__: null,
1030
- initialize: initialize,
1031
- reflexes: reflexes,
1032
- register: register,
1033
- scanForReflexes: scanForReflexes,
1034
- scanForReflexesOnElement: scanForReflexesOnElement,
1035
- useReflex: useReflex
1036
- });
1037
- const global = {
1038
- version: packageInfo.version,
1039
- ...StimulusReflex,
1040
- get debug() {
1041
- return Debug$1.value;
1042
- },
1043
- set debug(value) {
1044
- Debug$1.set(!!value);
1045
- },
1046
- get deprecate() {
1047
- return Deprecate.value;
1048
- },
1049
- set deprecate(value) {
1050
- Deprecate.set(!!value);
1051
- }
1052
- };
1053
- window.StimulusReflex = global;
1054
- exports.default = global;
1055
- exports.initialize = initialize;
1056
- exports.reflexes = reflexes;
1057
- exports.register = register;
1058
- exports.scanForReflexes = scanForReflexes;
1059
- exports.scanForReflexesOnElement = scanForReflexesOnElement;
1060
- exports.useReflex = useReflex;
1061
- Object.defineProperty(exports, "__esModule", {
1062
- value: true
1063
- });
1064
- }));
1065
- //# sourceMappingURL=stimulus_reflex.umd.min.js.map