actionview 7.0.7.2 → 7.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +235 -343
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/app/assets/javascripts/rails-ujs.esm.js +668 -0
  6. data/app/assets/javascripts/rails-ujs.js +606 -0
  7. data/lib/action_view/base.rb +28 -7
  8. data/lib/action_view/buffers.rb +106 -8
  9. data/lib/action_view/cache_expiry.rb +40 -43
  10. data/lib/action_view/context.rb +1 -1
  11. data/lib/action_view/deprecator.rb +7 -0
  12. data/lib/action_view/digestor.rb +1 -1
  13. data/lib/action_view/gem_version.rb +4 -4
  14. data/lib/action_view/helpers/active_model_helper.rb +1 -1
  15. data/lib/action_view/helpers/asset_tag_helper.rb +130 -46
  16. data/lib/action_view/helpers/asset_url_helper.rb +6 -5
  17. data/lib/action_view/helpers/atom_feed_helper.rb +5 -5
  18. data/lib/action_view/helpers/cache_helper.rb +3 -9
  19. data/lib/action_view/helpers/capture_helper.rb +24 -10
  20. data/lib/action_view/helpers/content_exfiltration_prevention_helper.rb +70 -0
  21. data/lib/action_view/helpers/controller_helper.rb +6 -0
  22. data/lib/action_view/helpers/csp_helper.rb +2 -2
  23. data/lib/action_view/helpers/csrf_helper.rb +2 -2
  24. data/lib/action_view/helpers/date_helper.rb +17 -19
  25. data/lib/action_view/helpers/debug_helper.rb +3 -3
  26. data/lib/action_view/helpers/form_helper.rb +42 -16
  27. data/lib/action_view/helpers/form_options_helper.rb +2 -1
  28. data/lib/action_view/helpers/form_tag_helper.rb +43 -9
  29. data/lib/action_view/helpers/javascript_helper.rb +1 -0
  30. data/lib/action_view/helpers/number_helper.rb +2 -1
  31. data/lib/action_view/helpers/output_safety_helper.rb +2 -2
  32. data/lib/action_view/helpers/rendering_helper.rb +1 -1
  33. data/lib/action_view/helpers/sanitize_helper.rb +33 -14
  34. data/lib/action_view/helpers/tag_helper.rb +5 -27
  35. data/lib/action_view/helpers/tags/base.rb +11 -52
  36. data/lib/action_view/helpers/tags/collection_check_boxes.rb +1 -0
  37. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +1 -0
  38. data/lib/action_view/helpers/tags/collection_select.rb +3 -0
  39. data/lib/action_view/helpers/tags/date_field.rb +1 -1
  40. data/lib/action_view/helpers/tags/date_select.rb +2 -0
  41. data/lib/action_view/helpers/tags/datetime_field.rb +14 -6
  42. data/lib/action_view/helpers/tags/datetime_local_field.rb +11 -2
  43. data/lib/action_view/helpers/tags/grouped_collection_select.rb +3 -0
  44. data/lib/action_view/helpers/tags/month_field.rb +1 -1
  45. data/lib/action_view/helpers/tags/select.rb +3 -0
  46. data/lib/action_view/helpers/tags/select_renderer.rb +56 -0
  47. data/lib/action_view/helpers/tags/time_field.rb +1 -1
  48. data/lib/action_view/helpers/tags/time_zone_select.rb +3 -0
  49. data/lib/action_view/helpers/tags/week_field.rb +1 -1
  50. data/lib/action_view/helpers/tags/weekday_select.rb +3 -0
  51. data/lib/action_view/helpers/tags.rb +2 -0
  52. data/lib/action_view/helpers/text_helper.rb +32 -16
  53. data/lib/action_view/helpers/translation_helper.rb +3 -3
  54. data/lib/action_view/helpers/url_helper.rb +41 -14
  55. data/lib/action_view/helpers.rb +2 -0
  56. data/lib/action_view/layouts.rb +4 -2
  57. data/lib/action_view/log_subscriber.rb +49 -32
  58. data/lib/action_view/lookup_context.rb +29 -13
  59. data/lib/action_view/path_registry.rb +57 -0
  60. data/lib/action_view/path_set.rb +13 -14
  61. data/lib/action_view/railtie.rb +26 -3
  62. data/lib/action_view/record_identifier.rb +15 -8
  63. data/lib/action_view/renderer/abstract_renderer.rb +1 -1
  64. data/lib/action_view/renderer/collection_renderer.rb +9 -1
  65. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +10 -2
  66. data/lib/action_view/renderer/partial_renderer.rb +2 -1
  67. data/lib/action_view/renderer/renderer.rb +2 -0
  68. data/lib/action_view/renderer/streaming_template_renderer.rb +3 -2
  69. data/lib/action_view/renderer/template_renderer.rb +3 -2
  70. data/lib/action_view/rendering.rb +22 -4
  71. data/lib/action_view/ripper_ast_parser.rb +5 -5
  72. data/lib/action_view/template/error.rb +14 -1
  73. data/lib/action_view/template/handlers/builder.rb +4 -4
  74. data/lib/action_view/template/handlers/erb/erubi.rb +23 -27
  75. data/lib/action_view/template/handlers/erb.rb +73 -1
  76. data/lib/action_view/template/handlers.rb +1 -1
  77. data/lib/action_view/template/html.rb +1 -1
  78. data/lib/action_view/template/raw_file.rb +1 -1
  79. data/lib/action_view/template/renderable.rb +1 -1
  80. data/lib/action_view/template/resolver.rb +10 -2
  81. data/lib/action_view/template/text.rb +1 -1
  82. data/lib/action_view/template/types.rb +25 -34
  83. data/lib/action_view/template.rb +179 -52
  84. data/lib/action_view/template_path.rb +2 -0
  85. data/lib/action_view/test_case.rb +8 -5
  86. data/lib/action_view/unbound_template.rb +15 -5
  87. data/lib/action_view/version.rb +1 -1
  88. data/lib/action_view/view_paths.rb +15 -24
  89. data/lib/action_view.rb +4 -1
  90. metadata +26 -26
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2004-2022 David Heinemeier Hansson
1
+ Copyright (c) David Heinemeier Hansson
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.rdoc CHANGED
@@ -5,7 +5,7 @@ view helpers that assist when building HTML forms, Atom feeds and more.
5
5
  Template formats that Action View handles are ERB (embedded Ruby, typically
6
6
  used to inline short Ruby snippets inside HTML), and XML Builder.
7
7
 
8
- You can read more about Action View in the {Action View Overview}[https://edgeguides.rubyonrails.org/action_view_overview.html] guide.
8
+ You can read more about Action View in the {Action View Overview}[https://guides.rubyonrails.org/action_view_overview.html] guide.
9
9
 
10
10
  == Download and installation
11
11
 
@@ -0,0 +1,668 @@
1
+ /*
2
+ Unobtrusive JavaScript
3
+ https://github.com/rails/rails/blob/main/actionview/app/javascript
4
+ Released under the MIT license
5
+ */
6
+ const linkClickSelector = "a[data-confirm], a[data-method], a[data-remote]:not([disabled]), a[data-disable-with], a[data-disable]";
7
+
8
+ const buttonClickSelector = {
9
+ selector: "button[data-remote]:not([form]), button[data-confirm]:not([form])",
10
+ exclude: "form button"
11
+ };
12
+
13
+ const inputChangeSelector = "select[data-remote], input[data-remote], textarea[data-remote]";
14
+
15
+ const formSubmitSelector = "form:not([data-turbo=true])";
16
+
17
+ const formInputClickSelector = "form:not([data-turbo=true]) input[type=submit], form:not([data-turbo=true]) input[type=image], form:not([data-turbo=true]) button[type=submit], form:not([data-turbo=true]) button:not([type]), input[type=submit][form], input[type=image][form], button[type=submit][form], button[form]:not([type])";
18
+
19
+ const formDisableSelector = "input[data-disable-with]:enabled, button[data-disable-with]:enabled, textarea[data-disable-with]:enabled, input[data-disable]:enabled, button[data-disable]:enabled, textarea[data-disable]:enabled";
20
+
21
+ const formEnableSelector = "input[data-disable-with]:disabled, button[data-disable-with]:disabled, textarea[data-disable-with]:disabled, input[data-disable]:disabled, button[data-disable]:disabled, textarea[data-disable]:disabled";
22
+
23
+ const fileInputSelector = "input[name][type=file]:not([disabled])";
24
+
25
+ const linkDisableSelector = "a[data-disable-with], a[data-disable]";
26
+
27
+ const buttonDisableSelector = "button[data-remote][data-disable-with], button[data-remote][data-disable]";
28
+
29
+ let nonce = null;
30
+
31
+ const loadCSPNonce = () => {
32
+ const metaTag = document.querySelector("meta[name=csp-nonce]");
33
+ return nonce = metaTag && metaTag.content;
34
+ };
35
+
36
+ const cspNonce = () => nonce || loadCSPNonce();
37
+
38
+ const m = Element.prototype.matches || Element.prototype.matchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector || Element.prototype.webkitMatchesSelector;
39
+
40
+ const matches = function(element, selector) {
41
+ if (selector.exclude) {
42
+ return m.call(element, selector.selector) && !m.call(element, selector.exclude);
43
+ } else {
44
+ return m.call(element, selector);
45
+ }
46
+ };
47
+
48
+ const EXPANDO = "_ujsData";
49
+
50
+ const getData = (element, key) => element[EXPANDO] ? element[EXPANDO][key] : undefined;
51
+
52
+ const setData = function(element, key, value) {
53
+ if (!element[EXPANDO]) {
54
+ element[EXPANDO] = {};
55
+ }
56
+ return element[EXPANDO][key] = value;
57
+ };
58
+
59
+ const $ = selector => Array.prototype.slice.call(document.querySelectorAll(selector));
60
+
61
+ const csrfToken = () => {
62
+ const meta = document.querySelector("meta[name=csrf-token]");
63
+ return meta && meta.content;
64
+ };
65
+
66
+ const csrfParam = () => {
67
+ const meta = document.querySelector("meta[name=csrf-param]");
68
+ return meta && meta.content;
69
+ };
70
+
71
+ const CSRFProtection = xhr => {
72
+ const token = csrfToken();
73
+ if (token) {
74
+ return xhr.setRequestHeader("X-CSRF-Token", token);
75
+ }
76
+ };
77
+
78
+ const refreshCSRFTokens = () => {
79
+ const token = csrfToken();
80
+ const param = csrfParam();
81
+ if (token && param) {
82
+ return $('form input[name="' + param + '"]').forEach((input => input.value = token));
83
+ }
84
+ };
85
+
86
+ const AcceptHeaders = {
87
+ "*": "*/*",
88
+ text: "text/plain",
89
+ html: "text/html",
90
+ xml: "application/xml, text/xml",
91
+ json: "application/json, text/javascript",
92
+ script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
93
+ };
94
+
95
+ const ajax = options => {
96
+ options = prepareOptions(options);
97
+ var xhr = createXHR(options, (function() {
98
+ const response = processResponse(xhr.response != null ? xhr.response : xhr.responseText, xhr.getResponseHeader("Content-Type"));
99
+ if (Math.floor(xhr.status / 100) === 2) {
100
+ if (typeof options.success === "function") {
101
+ options.success(response, xhr.statusText, xhr);
102
+ }
103
+ } else {
104
+ if (typeof options.error === "function") {
105
+ options.error(response, xhr.statusText, xhr);
106
+ }
107
+ }
108
+ return typeof options.complete === "function" ? options.complete(xhr, xhr.statusText) : undefined;
109
+ }));
110
+ if (options.beforeSend && !options.beforeSend(xhr, options)) {
111
+ return false;
112
+ }
113
+ if (xhr.readyState === XMLHttpRequest.OPENED) {
114
+ return xhr.send(options.data);
115
+ }
116
+ };
117
+
118
+ var prepareOptions = function(options) {
119
+ options.url = options.url || location.href;
120
+ options.type = options.type.toUpperCase();
121
+ if (options.type === "GET" && options.data) {
122
+ if (options.url.indexOf("?") < 0) {
123
+ options.url += "?" + options.data;
124
+ } else {
125
+ options.url += "&" + options.data;
126
+ }
127
+ }
128
+ if (!(options.dataType in AcceptHeaders)) {
129
+ options.dataType = "*";
130
+ }
131
+ options.accept = AcceptHeaders[options.dataType];
132
+ if (options.dataType !== "*") {
133
+ options.accept += ", */*; q=0.01";
134
+ }
135
+ return options;
136
+ };
137
+
138
+ var createXHR = function(options, done) {
139
+ const xhr = new XMLHttpRequest;
140
+ xhr.open(options.type, options.url, true);
141
+ xhr.setRequestHeader("Accept", options.accept);
142
+ if (typeof options.data === "string") {
143
+ xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
144
+ }
145
+ if (!options.crossDomain) {
146
+ xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
147
+ CSRFProtection(xhr);
148
+ }
149
+ xhr.withCredentials = !!options.withCredentials;
150
+ xhr.onreadystatechange = function() {
151
+ if (xhr.readyState === XMLHttpRequest.DONE) {
152
+ return done(xhr);
153
+ }
154
+ };
155
+ return xhr;
156
+ };
157
+
158
+ var processResponse = function(response, type) {
159
+ if (typeof response === "string" && typeof type === "string") {
160
+ if (type.match(/\bjson\b/)) {
161
+ try {
162
+ response = JSON.parse(response);
163
+ } catch (error) {}
164
+ } else if (type.match(/\b(?:java|ecma)script\b/)) {
165
+ const script = document.createElement("script");
166
+ script.setAttribute("nonce", cspNonce());
167
+ script.text = response;
168
+ document.head.appendChild(script).parentNode.removeChild(script);
169
+ } else if (type.match(/\b(xml|html|svg)\b/)) {
170
+ const parser = new DOMParser;
171
+ type = type.replace(/;.+/, "");
172
+ try {
173
+ response = parser.parseFromString(response, type);
174
+ } catch (error1) {}
175
+ }
176
+ }
177
+ return response;
178
+ };
179
+
180
+ const href = element => element.href;
181
+
182
+ const isCrossDomain = function(url) {
183
+ const originAnchor = document.createElement("a");
184
+ originAnchor.href = location.href;
185
+ const urlAnchor = document.createElement("a");
186
+ try {
187
+ urlAnchor.href = url;
188
+ return !((!urlAnchor.protocol || urlAnchor.protocol === ":") && !urlAnchor.host || originAnchor.protocol + "//" + originAnchor.host === urlAnchor.protocol + "//" + urlAnchor.host);
189
+ } catch (e) {
190
+ return true;
191
+ }
192
+ };
193
+
194
+ let preventDefault;
195
+
196
+ let {CustomEvent: CustomEvent} = window;
197
+
198
+ if (typeof CustomEvent !== "function") {
199
+ CustomEvent = function(event, params) {
200
+ const evt = document.createEvent("CustomEvent");
201
+ evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
202
+ return evt;
203
+ };
204
+ CustomEvent.prototype = window.Event.prototype;
205
+ ({preventDefault: preventDefault} = CustomEvent.prototype);
206
+ CustomEvent.prototype.preventDefault = function() {
207
+ const result = preventDefault.call(this);
208
+ if (this.cancelable && !this.defaultPrevented) {
209
+ Object.defineProperty(this, "defaultPrevented", {
210
+ get() {
211
+ return true;
212
+ }
213
+ });
214
+ }
215
+ return result;
216
+ };
217
+ }
218
+
219
+ const fire = (obj, name, data) => {
220
+ const event = new CustomEvent(name, {
221
+ bubbles: true,
222
+ cancelable: true,
223
+ detail: data
224
+ });
225
+ obj.dispatchEvent(event);
226
+ return !event.defaultPrevented;
227
+ };
228
+
229
+ const stopEverything = e => {
230
+ fire(e.target, "ujs:everythingStopped");
231
+ e.preventDefault();
232
+ e.stopPropagation();
233
+ e.stopImmediatePropagation();
234
+ };
235
+
236
+ const delegate = (element, selector, eventType, handler) => element.addEventListener(eventType, (function(e) {
237
+ let {target: target} = e;
238
+ while (!!(target instanceof Element) && !matches(target, selector)) {
239
+ target = target.parentNode;
240
+ }
241
+ if (target instanceof Element && handler.call(target, e) === false) {
242
+ e.preventDefault();
243
+ e.stopPropagation();
244
+ }
245
+ }));
246
+
247
+ const toArray = e => Array.prototype.slice.call(e);
248
+
249
+ const serializeElement = (element, additionalParam) => {
250
+ let inputs = [ element ];
251
+ if (matches(element, "form")) {
252
+ inputs = toArray(element.elements);
253
+ }
254
+ const params = [];
255
+ inputs.forEach((function(input) {
256
+ if (!input.name || input.disabled) {
257
+ return;
258
+ }
259
+ if (matches(input, "fieldset[disabled] *")) {
260
+ return;
261
+ }
262
+ if (matches(input, "select")) {
263
+ toArray(input.options).forEach((function(option) {
264
+ if (option.selected) {
265
+ params.push({
266
+ name: input.name,
267
+ value: option.value
268
+ });
269
+ }
270
+ }));
271
+ } else if (input.checked || [ "radio", "checkbox", "submit" ].indexOf(input.type) === -1) {
272
+ params.push({
273
+ name: input.name,
274
+ value: input.value
275
+ });
276
+ }
277
+ }));
278
+ if (additionalParam) {
279
+ params.push(additionalParam);
280
+ }
281
+ return params.map((function(param) {
282
+ if (param.name) {
283
+ return `${encodeURIComponent(param.name)}=${encodeURIComponent(param.value)}`;
284
+ } else {
285
+ return param;
286
+ }
287
+ })).join("&");
288
+ };
289
+
290
+ const formElements = (form, selector) => {
291
+ if (matches(form, "form")) {
292
+ return toArray(form.elements).filter((el => matches(el, selector)));
293
+ } else {
294
+ return toArray(form.querySelectorAll(selector));
295
+ }
296
+ };
297
+
298
+ const handleConfirmWithRails = rails => function(e) {
299
+ if (!allowAction(this, rails)) {
300
+ stopEverything(e);
301
+ }
302
+ };
303
+
304
+ const confirm = (message, element) => window.confirm(message);
305
+
306
+ var allowAction = function(element, rails) {
307
+ let callback;
308
+ const message = element.getAttribute("data-confirm");
309
+ if (!message) {
310
+ return true;
311
+ }
312
+ let answer = false;
313
+ if (fire(element, "confirm")) {
314
+ try {
315
+ answer = rails.confirm(message, element);
316
+ } catch (error) {}
317
+ callback = fire(element, "confirm:complete", [ answer ]);
318
+ }
319
+ return answer && callback;
320
+ };
321
+
322
+ const handleDisabledElement = function(e) {
323
+ const element = this;
324
+ if (element.disabled) {
325
+ stopEverything(e);
326
+ }
327
+ };
328
+
329
+ const enableElement = e => {
330
+ let element;
331
+ if (e instanceof Event) {
332
+ if (isXhrRedirect(e)) {
333
+ return;
334
+ }
335
+ element = e.target;
336
+ } else {
337
+ element = e;
338
+ }
339
+ if (matches(element, linkDisableSelector)) {
340
+ return enableLinkElement(element);
341
+ } else if (matches(element, buttonDisableSelector) || matches(element, formEnableSelector)) {
342
+ return enableFormElement(element);
343
+ } else if (matches(element, formSubmitSelector)) {
344
+ return enableFormElements(element);
345
+ }
346
+ };
347
+
348
+ const disableElement = e => {
349
+ const element = e instanceof Event ? e.target : e;
350
+ if (matches(element, linkDisableSelector)) {
351
+ return disableLinkElement(element);
352
+ } else if (matches(element, buttonDisableSelector) || matches(element, formDisableSelector)) {
353
+ return disableFormElement(element);
354
+ } else if (matches(element, formSubmitSelector)) {
355
+ return disableFormElements(element);
356
+ }
357
+ };
358
+
359
+ var disableLinkElement = function(element) {
360
+ if (getData(element, "ujs:disabled")) {
361
+ return;
362
+ }
363
+ const replacement = element.getAttribute("data-disable-with");
364
+ if (replacement != null) {
365
+ setData(element, "ujs:enable-with", element.innerHTML);
366
+ element.innerHTML = replacement;
367
+ }
368
+ element.addEventListener("click", stopEverything);
369
+ return setData(element, "ujs:disabled", true);
370
+ };
371
+
372
+ var enableLinkElement = function(element) {
373
+ const originalText = getData(element, "ujs:enable-with");
374
+ if (originalText != null) {
375
+ element.innerHTML = originalText;
376
+ setData(element, "ujs:enable-with", null);
377
+ }
378
+ element.removeEventListener("click", stopEverything);
379
+ return setData(element, "ujs:disabled", null);
380
+ };
381
+
382
+ var disableFormElements = form => formElements(form, formDisableSelector).forEach(disableFormElement);
383
+
384
+ var disableFormElement = function(element) {
385
+ if (getData(element, "ujs:disabled")) {
386
+ return;
387
+ }
388
+ const replacement = element.getAttribute("data-disable-with");
389
+ if (replacement != null) {
390
+ if (matches(element, "button")) {
391
+ setData(element, "ujs:enable-with", element.innerHTML);
392
+ element.innerHTML = replacement;
393
+ } else {
394
+ setData(element, "ujs:enable-with", element.value);
395
+ element.value = replacement;
396
+ }
397
+ }
398
+ element.disabled = true;
399
+ return setData(element, "ujs:disabled", true);
400
+ };
401
+
402
+ var enableFormElements = form => formElements(form, formEnableSelector).forEach((element => enableFormElement(element)));
403
+
404
+ var enableFormElement = function(element) {
405
+ const originalText = getData(element, "ujs:enable-with");
406
+ if (originalText != null) {
407
+ if (matches(element, "button")) {
408
+ element.innerHTML = originalText;
409
+ } else {
410
+ element.value = originalText;
411
+ }
412
+ setData(element, "ujs:enable-with", null);
413
+ }
414
+ element.disabled = false;
415
+ return setData(element, "ujs:disabled", null);
416
+ };
417
+
418
+ var isXhrRedirect = function(event) {
419
+ const xhr = event.detail ? event.detail[0] : undefined;
420
+ return xhr && xhr.getResponseHeader("X-Xhr-Redirect");
421
+ };
422
+
423
+ const handleMethodWithRails = rails => function(e) {
424
+ const link = this;
425
+ const method = link.getAttribute("data-method");
426
+ if (!method) {
427
+ return;
428
+ }
429
+ const href = rails.href(link);
430
+ const csrfToken$1 = csrfToken();
431
+ const csrfParam$1 = csrfParam();
432
+ const form = document.createElement("form");
433
+ let formContent = `<input name='_method' value='${method}' type='hidden' />`;
434
+ if (csrfParam$1 && csrfToken$1 && !isCrossDomain(href)) {
435
+ formContent += `<input name='${csrfParam$1}' value='${csrfToken$1}' type='hidden' />`;
436
+ }
437
+ formContent += '<input type="submit" />';
438
+ form.method = "post";
439
+ form.action = href;
440
+ form.target = link.target;
441
+ form.innerHTML = formContent;
442
+ form.style.display = "none";
443
+ document.body.appendChild(form);
444
+ form.querySelector('[type="submit"]').click();
445
+ stopEverything(e);
446
+ };
447
+
448
+ const isRemote = function(element) {
449
+ const value = element.getAttribute("data-remote");
450
+ return value != null && value !== "false";
451
+ };
452
+
453
+ const handleRemoteWithRails = rails => function(e) {
454
+ let data, method, url;
455
+ const element = this;
456
+ if (!isRemote(element)) {
457
+ return true;
458
+ }
459
+ if (!fire(element, "ajax:before")) {
460
+ fire(element, "ajax:stopped");
461
+ return false;
462
+ }
463
+ const withCredentials = element.getAttribute("data-with-credentials");
464
+ const dataType = element.getAttribute("data-type") || "script";
465
+ if (matches(element, formSubmitSelector)) {
466
+ const button = getData(element, "ujs:submit-button");
467
+ method = getData(element, "ujs:submit-button-formmethod") || element.getAttribute("method") || "get";
468
+ url = getData(element, "ujs:submit-button-formaction") || element.getAttribute("action") || location.href;
469
+ if (method.toUpperCase() === "GET") {
470
+ url = url.replace(/\?.*$/, "");
471
+ }
472
+ if (element.enctype === "multipart/form-data") {
473
+ data = new FormData(element);
474
+ if (button != null) {
475
+ data.append(button.name, button.value);
476
+ }
477
+ } else {
478
+ data = serializeElement(element, button);
479
+ }
480
+ setData(element, "ujs:submit-button", null);
481
+ setData(element, "ujs:submit-button-formmethod", null);
482
+ setData(element, "ujs:submit-button-formaction", null);
483
+ } else if (matches(element, buttonClickSelector) || matches(element, inputChangeSelector)) {
484
+ method = element.getAttribute("data-method");
485
+ url = element.getAttribute("data-url");
486
+ data = serializeElement(element, element.getAttribute("data-params"));
487
+ } else {
488
+ method = element.getAttribute("data-method");
489
+ url = rails.href(element);
490
+ data = element.getAttribute("data-params");
491
+ }
492
+ ajax({
493
+ type: method || "GET",
494
+ url: url,
495
+ data: data,
496
+ dataType: dataType,
497
+ beforeSend(xhr, options) {
498
+ if (fire(element, "ajax:beforeSend", [ xhr, options ])) {
499
+ return fire(element, "ajax:send", [ xhr ]);
500
+ } else {
501
+ fire(element, "ajax:stopped");
502
+ return false;
503
+ }
504
+ },
505
+ success(...args) {
506
+ return fire(element, "ajax:success", args);
507
+ },
508
+ error(...args) {
509
+ return fire(element, "ajax:error", args);
510
+ },
511
+ complete(...args) {
512
+ return fire(element, "ajax:complete", args);
513
+ },
514
+ crossDomain: isCrossDomain(url),
515
+ withCredentials: withCredentials != null && withCredentials !== "false"
516
+ });
517
+ stopEverything(e);
518
+ };
519
+
520
+ const formSubmitButtonClick = function(e) {
521
+ const button = this;
522
+ const {form: form} = button;
523
+ if (!form) {
524
+ return;
525
+ }
526
+ if (button.name) {
527
+ setData(form, "ujs:submit-button", {
528
+ name: button.name,
529
+ value: button.value
530
+ });
531
+ }
532
+ setData(form, "ujs:formnovalidate-button", button.formNoValidate);
533
+ setData(form, "ujs:submit-button-formaction", button.getAttribute("formaction"));
534
+ return setData(form, "ujs:submit-button-formmethod", button.getAttribute("formmethod"));
535
+ };
536
+
537
+ const preventInsignificantClick = function(e) {
538
+ const link = this;
539
+ const method = (link.getAttribute("data-method") || "GET").toUpperCase();
540
+ const data = link.getAttribute("data-params");
541
+ const metaClick = e.metaKey || e.ctrlKey;
542
+ const insignificantMetaClick = metaClick && method === "GET" && !data;
543
+ const nonPrimaryMouseClick = e.button != null && e.button !== 0;
544
+ if (nonPrimaryMouseClick || insignificantMetaClick) {
545
+ e.stopImmediatePropagation();
546
+ }
547
+ };
548
+
549
+ const Rails = {
550
+ $: $,
551
+ ajax: ajax,
552
+ buttonClickSelector: buttonClickSelector,
553
+ buttonDisableSelector: buttonDisableSelector,
554
+ confirm: confirm,
555
+ cspNonce: cspNonce,
556
+ csrfToken: csrfToken,
557
+ csrfParam: csrfParam,
558
+ CSRFProtection: CSRFProtection,
559
+ delegate: delegate,
560
+ disableElement: disableElement,
561
+ enableElement: enableElement,
562
+ fileInputSelector: fileInputSelector,
563
+ fire: fire,
564
+ formElements: formElements,
565
+ formEnableSelector: formEnableSelector,
566
+ formDisableSelector: formDisableSelector,
567
+ formInputClickSelector: formInputClickSelector,
568
+ formSubmitButtonClick: formSubmitButtonClick,
569
+ formSubmitSelector: formSubmitSelector,
570
+ getData: getData,
571
+ handleDisabledElement: handleDisabledElement,
572
+ href: href,
573
+ inputChangeSelector: inputChangeSelector,
574
+ isCrossDomain: isCrossDomain,
575
+ linkClickSelector: linkClickSelector,
576
+ linkDisableSelector: linkDisableSelector,
577
+ loadCSPNonce: loadCSPNonce,
578
+ matches: matches,
579
+ preventInsignificantClick: preventInsignificantClick,
580
+ refreshCSRFTokens: refreshCSRFTokens,
581
+ serializeElement: serializeElement,
582
+ setData: setData,
583
+ stopEverything: stopEverything
584
+ };
585
+
586
+ const handleConfirm = handleConfirmWithRails(Rails);
587
+
588
+ Rails.handleConfirm = handleConfirm;
589
+
590
+ const handleMethod = handleMethodWithRails(Rails);
591
+
592
+ Rails.handleMethod = handleMethod;
593
+
594
+ const handleRemote = handleRemoteWithRails(Rails);
595
+
596
+ Rails.handleRemote = handleRemote;
597
+
598
+ const start = function() {
599
+ if (window._rails_loaded) {
600
+ throw new Error("rails-ujs has already been loaded!");
601
+ }
602
+ window.addEventListener("pageshow", (function() {
603
+ $(formEnableSelector).forEach((function(el) {
604
+ if (getData(el, "ujs:disabled")) {
605
+ enableElement(el);
606
+ }
607
+ }));
608
+ $(linkDisableSelector).forEach((function(el) {
609
+ if (getData(el, "ujs:disabled")) {
610
+ enableElement(el);
611
+ }
612
+ }));
613
+ }));
614
+ delegate(document, linkDisableSelector, "ajax:complete", enableElement);
615
+ delegate(document, linkDisableSelector, "ajax:stopped", enableElement);
616
+ delegate(document, buttonDisableSelector, "ajax:complete", enableElement);
617
+ delegate(document, buttonDisableSelector, "ajax:stopped", enableElement);
618
+ delegate(document, linkClickSelector, "click", preventInsignificantClick);
619
+ delegate(document, linkClickSelector, "click", handleDisabledElement);
620
+ delegate(document, linkClickSelector, "click", handleConfirm);
621
+ delegate(document, linkClickSelector, "click", disableElement);
622
+ delegate(document, linkClickSelector, "click", handleRemote);
623
+ delegate(document, linkClickSelector, "click", handleMethod);
624
+ delegate(document, buttonClickSelector, "click", preventInsignificantClick);
625
+ delegate(document, buttonClickSelector, "click", handleDisabledElement);
626
+ delegate(document, buttonClickSelector, "click", handleConfirm);
627
+ delegate(document, buttonClickSelector, "click", disableElement);
628
+ delegate(document, buttonClickSelector, "click", handleRemote);
629
+ delegate(document, inputChangeSelector, "change", handleDisabledElement);
630
+ delegate(document, inputChangeSelector, "change", handleConfirm);
631
+ delegate(document, inputChangeSelector, "change", handleRemote);
632
+ delegate(document, formSubmitSelector, "submit", handleDisabledElement);
633
+ delegate(document, formSubmitSelector, "submit", handleConfirm);
634
+ delegate(document, formSubmitSelector, "submit", handleRemote);
635
+ delegate(document, formSubmitSelector, "submit", (e => setTimeout((() => disableElement(e)), 13)));
636
+ delegate(document, formSubmitSelector, "ajax:send", disableElement);
637
+ delegate(document, formSubmitSelector, "ajax:complete", enableElement);
638
+ delegate(document, formInputClickSelector, "click", preventInsignificantClick);
639
+ delegate(document, formInputClickSelector, "click", handleDisabledElement);
640
+ delegate(document, formInputClickSelector, "click", handleConfirm);
641
+ delegate(document, formInputClickSelector, "click", formSubmitButtonClick);
642
+ document.addEventListener("DOMContentLoaded", refreshCSRFTokens);
643
+ document.addEventListener("DOMContentLoaded", loadCSPNonce);
644
+ return window._rails_loaded = true;
645
+ };
646
+
647
+ Rails.start = start;
648
+
649
+ if (typeof jQuery !== "undefined" && jQuery && jQuery.ajax) {
650
+ if (jQuery.rails) {
651
+ throw new Error("If you load both jquery_ujs and rails-ujs, use rails-ujs only.");
652
+ }
653
+ jQuery.rails = Rails;
654
+ jQuery.ajaxPrefilter((function(options, originalOptions, xhr) {
655
+ if (!options.crossDomain) {
656
+ return CSRFProtection(xhr);
657
+ }
658
+ }));
659
+ }
660
+
661
+ if (typeof exports !== "object" && typeof module === "undefined") {
662
+ window.Rails = Rails;
663
+ if (fire(document, "rails:attachBindings")) {
664
+ start();
665
+ }
666
+ }
667
+
668
+ export default Rails;