shoelace-rails 0.4.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +11 -61
  3. data/.gitignore +1 -6
  4. data/Appraisals +6 -0
  5. data/CHANGELOG.md +22 -5
  6. data/Gemfile +0 -3
  7. data/Rakefile +2 -17
  8. data/app/helpers/shoelace/form_helper.rb +63 -14
  9. data/gemfiles/rails_60.gemfile +0 -1
  10. data/gemfiles/rails_61.gemfile +0 -1
  11. data/gemfiles/rails_70.gemfile +0 -1
  12. data/gemfiles/rails_71.gemfile +10 -0
  13. data/gemfiles/rails_edge.gemfile +0 -1
  14. data/lib/shoelace/rails/version.rb +1 -1
  15. data/shoelace-rails.gemspec +1 -1
  16. data/test/helpers/form_helper_test.rb +40 -11
  17. data/test/helpers/translation_test.rb +160 -0
  18. metadata +7 -58
  19. data/dist/.keep +0 -0
  20. data/dist/types/.keep +0 -0
  21. data/package.json +0 -50
  22. data/rollup.config.js +0 -49
  23. data/src/index.ts +0 -2
  24. data/src/turbo/index.ts +0 -6
  25. data/src/turbo/polyfills/formdata-event.js +0 -27
  26. data/src/turbo/sl-turbo-form.ts +0 -110
  27. data/src/turbolinks/features/confirm.ts +0 -42
  28. data/src/turbolinks/features/disable.ts +0 -94
  29. data/src/turbolinks/features/remote.ts +0 -107
  30. data/src/turbolinks/index.ts +0 -6
  31. data/src/turbolinks/selectors.ts +0 -38
  32. data/src/turbolinks/start.ts +0 -38
  33. data/src/turbolinks/turbolinks.ts +0 -78
  34. data/src/turbolinks/utils/ajax.ts +0 -146
  35. data/src/turbolinks/utils/csp.ts +0 -20
  36. data/src/turbolinks/utils/csrf.ts +0 -33
  37. data/src/turbolinks/utils/dom.ts +0 -40
  38. data/src/turbolinks/utils/event.ts +0 -57
  39. data/src/turbolinks/utils/form.ts +0 -58
  40. data/test/dummy_app/Gemfile +0 -19
  41. data/test/dummy_app/Rakefile +0 -6
  42. data/test/dummy_app/app/controllers/hotwire_forms_controller.rb +0 -46
  43. data/test/dummy_app/app/controllers/turbolinks_forms_controller.rb +0 -37
  44. data/test/dummy_app/app/models/user.rb +0 -16
  45. data/test/dummy_app/app/packs/entrypoints/hotwire.js +0 -1
  46. data/test/dummy_app/app/packs/entrypoints/turbolinks.js +0 -5
  47. data/test/dummy_app/app/views/hotwire_forms/form.html.erb +0 -45
  48. data/test/dummy_app/app/views/hotwire_forms/show.html.erb +0 -5
  49. data/test/dummy_app/app/views/layouts/application.html.erb +0 -39
  50. data/test/dummy_app/app/views/turbolinks_forms/form.html.erb +0 -44
  51. data/test/dummy_app/app/views/turbolinks_forms/show.html.erb +0 -5
  52. data/test/dummy_app/bin/rails +0 -5
  53. data/test/dummy_app/bin/webpack +0 -18
  54. data/test/dummy_app/bin/yarn +0 -18
  55. data/test/dummy_app/config/application.rb +0 -16
  56. data/test/dummy_app/config/boot.rb +0 -4
  57. data/test/dummy_app/config/environment.rb +0 -2
  58. data/test/dummy_app/config/environments/development.rb +0 -10
  59. data/test/dummy_app/config/environments/test.rb +0 -18
  60. data/test/dummy_app/config/routes.rb +0 -4
  61. data/test/dummy_app/config/webpack/development.js +0 -5
  62. data/test/dummy_app/config/webpack/production.js +0 -1
  63. data/test/dummy_app/config/webpack/test.js +0 -5
  64. data/test/dummy_app/config/webpacker.yml +0 -33
  65. data/test/dummy_app/config.ru +0 -6
  66. data/test/dummy_app/package.json +0 -24
  67. data/test/dummy_app/test/system/hotwire_form_test.rb +0 -63
  68. data/test/dummy_app/test/system/turbolinks_form_test.rb +0 -38
  69. data/test/dummy_app/test/test_helper.rb +0 -68
  70. data/tsconfig.json +0 -19
  71. data/yarn.lock +0 -249
@@ -1,94 +0,0 @@
1
- // This code was heavily inspired by the rails-ujs project.
2
- // Copyright (c) 2007-2021 Rails Core team.
3
- import { buttonDisableSelector, formDisableSelector, formEnableSelector, formSubmitSelector } from "../selectors"
4
- import { getData, matches, setData } from "../utils/dom"
5
- import { stopEverything } from "../utils/event"
6
- import { formElements } from "../utils/form"
7
-
8
- export const handleDisabledElement = (event) => {
9
- const element: HTMLInputElement | HTMLFormElement = event.target
10
-
11
- if (element.disabled) {
12
- return stopEverything(event)
13
- }
14
- }
15
-
16
- // Unified function to enable an element (link, button and form)
17
- export const enableElement = function (e) {
18
- let element
19
-
20
- if (e instanceof Event) {
21
- if (isXhrRedirect(e)) {
22
- return
23
- }
24
- element = e.target
25
- } else {
26
- element = e
27
- }
28
-
29
- if (matches(element, buttonDisableSelector) || matches(element, formEnableSelector)) {
30
- return enableFormElement(element)
31
- } else if (matches(element, formSubmitSelector)) {
32
- return enableFormElements(element)
33
- }
34
- }
35
-
36
- // Unified function to disable an element (link, button and form)
37
- export const disableElement = function (e) {
38
- const element = e instanceof Event ? e.target : e
39
-
40
- if (matches(element, buttonDisableSelector) || matches(element, formDisableSelector)) {
41
- return disableFormElement(element)
42
- } else if (matches(element, formSubmitSelector)) {
43
- return disableFormElements(element)
44
- }
45
- }
46
-
47
- // Disables form elements:
48
- // - Caches element value in 'ujs:enable-with' data store
49
- // - Replaces element text with value of 'data-disable-with' attribute
50
- // - Sets disabled property to true
51
- const disableFormElements = (form) => formElements(form, formDisableSelector).forEach(disableFormElement)
52
-
53
- const disableFormElement = function (element) {
54
- if (getData(element, "ujs:disabled")) {
55
- return
56
- }
57
-
58
- const replacement = element.getAttribute("data-disable-with")
59
- if (replacement != null) {
60
- if (matches(element, "button")) {
61
- setData(element, "ujs:enable-with", element.innerHTML)
62
- element.innerHTML = replacement
63
- } else {
64
- setData(element, "ujs:enable-with", element.value)
65
- element.value = replacement
66
- }
67
- }
68
- element.disabled = true
69
- return setData(element, "ujs:disabled", true)
70
- }
71
-
72
- // Re-enables disabled form elements:
73
- // - Replaces element text with cached value from 'ujs:enable-with' data store (created in `disableFormElements`)
74
- // - Sets disabled property to false
75
- const enableFormElements = (form) => formElements(form, formEnableSelector).forEach(enableFormElement)
76
-
77
- const enableFormElement = function (element) {
78
- const originalText = getData(element, "ujs:enable-with")
79
- if (originalText != null) {
80
- if (matches(element, "button")) {
81
- element.innerHTML = originalText
82
- } else {
83
- element.value = originalText
84
- }
85
- setData(element, "ujs:enable-with", null) // clean up cache
86
- }
87
- element.disabled = false
88
- return setData(element, "ujs:disabled", null)
89
- }
90
-
91
- const isXhrRedirect = function (event) {
92
- const xhr = event.detail != null ? event.detail[0] : undefined
93
- return (xhr != null ? xhr.getResponseHeader("X-Xhr-Redirect") : undefined) != null
94
- }
@@ -1,107 +0,0 @@
1
- // This code was heavily inspired by the rails-ujs project.
2
- // Copyright (c) 2007-2021 Rails Core team.
3
- import { formSubmitSelector } from "../selectors"
4
- import { ajax, href, isCrossDomain } from "../utils/ajax"
5
- import { getData, matches, setData } from "../utils/dom"
6
- import { fire, stopEverything } from "../utils/event"
7
-
8
- const isRemote = function (element) {
9
- const value = element.getAttribute("data-remote")
10
- return value != null && value !== "false"
11
- }
12
-
13
- export const handleRemote = function (event: CustomEvent<{ formData: FormData; formControls: HTMLElement[] }>) {
14
- const element = this
15
-
16
- if (!isRemote(element)) {
17
- return true
18
- }
19
-
20
- if (!fire(element, "ajax:before")) {
21
- fire(element, "ajax:stopped")
22
- return false
23
- }
24
-
25
- let method, url, data
26
-
27
- const withCredentials = element.getAttribute("data-with-credentials")
28
- const dataType = element.getAttribute("data-type") || "script"
29
-
30
- if (matches(element, formSubmitSelector)) {
31
- // memoized value from clicked submit button
32
- method = getData(element, "ujs:submit-button-formmethod") || element.getAttribute("method") || "GET"
33
- url = getData(element, "ujs:submit-button-formaction") || element.getAttribute("action") || location.href
34
-
35
- // strip query string if it's a GET request
36
- if (method.toUpperCase() === "GET") {
37
- url = url.replace(/\?.*$/, "")
38
- data = Array.from<Array<string>, string>(event.detail.formData as any, (e) =>
39
- e.map(encodeURIComponent).join("=")
40
- ).join("&")
41
- } else {
42
- data = event.detail.formData
43
- }
44
-
45
- setData(element, "ujs:submit-button", null)
46
- setData(element, "ujs:submit-button-formmethod", null)
47
- setData(element, "ujs:submit-button-formaction", null)
48
- } else {
49
- method = element.getAttribute("data-method")
50
- url = href(element)
51
- data = element.getAttribute("data-params")
52
- }
53
-
54
- ajax({
55
- type: method,
56
- url,
57
- data,
58
- dataType,
59
- // stopping the "ajax:beforeSend" event will cancel the ajax request
60
- beforeSend: (xhr, options) => {
61
- if (fire(element, "ajax:beforeSend", [xhr, options])) {
62
- return fire(element, "ajax:send", [xhr])
63
- } else {
64
- fire(element, "ajax:stopped")
65
- return false
66
- }
67
- },
68
- success: (...args) => fire(element, "ajax:success", args),
69
- error: (...args) => fire(element, "ajax:error", args),
70
- complete: (...args) => fire(element, "ajax:complete", args),
71
- crossDomain: isCrossDomain(url),
72
- withCredentials: withCredentials != null && withCredentials !== "false",
73
- })
74
-
75
- return stopEverything(event)
76
- }
77
-
78
- export const formSubmitButtonClick = (event) => {
79
- const button: HTMLButtonElement = event.target
80
- const { form } = button
81
-
82
- if (!form) {
83
- return
84
- }
85
-
86
- if (button.name) {
87
- setData(form, "ujs:submit-button", { name: button.name, value: button.value })
88
- }
89
-
90
- setData(form, "ujs:formnovalidate-button", button.formNoValidate)
91
- setData(form, "ujs:submit-button-formaction", button.getAttribute("formaction"))
92
- return setData(form, "ujs:submit-button-formmethod", button.getAttribute("formmethod"))
93
- }
94
-
95
- export const preventInsignificantClick = (event) => {
96
- const link: HTMLElement = event.target
97
-
98
- const method = (link.getAttribute("data-method") || "GET").toUpperCase()
99
- const data = link.getAttribute("data-params")
100
- const metaClick = event.metaKey || event.ctrlKey
101
- const insignificantMetaClick = metaClick && method === "GET" && !data
102
- const nonPrimaryMouseClick = event.button != null && event.button !== 0
103
-
104
- if (nonPrimaryMouseClick || insignificantMetaClick) {
105
- return event.stopImmediatePropagation()
106
- }
107
- }
@@ -1,6 +0,0 @@
1
- export * from "./utils/event"
2
- export * from "./utils/dom"
3
- export * from "./features/remote"
4
- export * from "./selectors"
5
- export * from "./turbolinks"
6
- export * from "./start"
@@ -1,38 +0,0 @@
1
- // This code was heavily inspired by the rails-ujs project.
2
- // Copyright (c) 2007-2021 Rails Core team.
3
- export const buttonClickSelector = {
4
- selector: "sl-button[data-remote]:not([form]), sl-button[data-confirm]:not([form])",
5
- exclude: "sl-form sl-button",
6
- }
7
-
8
- export const formSubmitSelector = "sl-form[data-remote]"
9
-
10
- export const formInputClickSelector = [
11
- "sl-form sl-button[submit]",
12
- "sl-form sl-button:not([type])",
13
- "sl-button[submit][sl-form]",
14
- "sl-button[sl-form]:not([type])",
15
- ].join(", ")
16
-
17
- export const formDisableSelector = [
18
- "sl-input[data-disable-with]:not([disabled])",
19
- "sl-button[data-disable-with]:not([disabled])",
20
- "sl-textarea[data-disable-with]:not([disabled])",
21
- "sl-input[data-disable]:not([disabled])",
22
- "sl-button[data-disable]:not([disabled])",
23
- "sl-textarea[data-disable]:not([disabled])",
24
- ].join(", ")
25
-
26
- export const formEnableSelector = [
27
- "sl-input[data-disable-with][disabled]",
28
- "sl-button[data-disable-with][disabled]",
29
- "sl-textarea[data-disable-with][disabled]",
30
- "sl-input[data-disable][disabled]",
31
- "sl-button[data-disable][disabled]",
32
- "sl-textarea[data-disable][disabled]",
33
- ].join(", ")
34
-
35
- export const buttonDisableSelector = [
36
- "sl-button[data-remote][data-disable-with]",
37
- "sl-button[data-remote][data-disable]",
38
- ].join(", ")
@@ -1,38 +0,0 @@
1
- // This code was heavily inspired by the rails-ujs project.
2
- // Copyright (c) 2007-2021 Rails Core team.
3
- import { handleConfirm } from "./features/confirm"
4
- import { disableElement, enableElement, handleDisabledElement } from "./features/disable"
5
- import { formSubmitButtonClick, handleRemote, preventInsignificantClick } from "./features/remote"
6
- import { buttonClickSelector, buttonDisableSelector, formInputClickSelector, formSubmitSelector } from "./selectors"
7
-
8
- import { delegate } from "./utils/event"
9
-
10
- export const getDefaultAssetPath = () => {
11
- const rootUrl = (document.currentScript as any).src.replace(/\/packs.*$/, "")
12
-
13
- return `${rootUrl}/packs/js/`
14
- }
15
-
16
- export const startUjs = () => {
17
- delegate(document, buttonDisableSelector, "ajax:complete", enableElement)
18
- delegate(document, buttonDisableSelector, "ajax:stopped", enableElement)
19
-
20
- delegate(document, buttonClickSelector, "click", preventInsignificantClick)
21
- delegate(document, buttonClickSelector, "click", handleDisabledElement)
22
- delegate(document, buttonClickSelector, "click", handleConfirm)
23
- delegate(document, buttonClickSelector, "click", disableElement)
24
- delegate(document, buttonClickSelector, "click", handleRemote)
25
-
26
- delegate(document, formSubmitSelector, "sl-submit", handleDisabledElement)
27
- delegate(document, formSubmitSelector, "sl-submit", handleConfirm)
28
- delegate(document, formSubmitSelector, "sl-submit", handleRemote)
29
-
30
- // simulates a normal form submit:
31
- delegate(document, formSubmitSelector, "ajax:send", disableElement)
32
- delegate(document, formSubmitSelector, "ajax:complete", enableElement)
33
-
34
- delegate(document, formInputClickSelector, "click", preventInsignificantClick)
35
- delegate(document, formInputClickSelector, "click", handleDisabledElement)
36
- // delegate(document, formInputClickSelector, "click", handleConfirm)
37
- delegate(document, formInputClickSelector, "click", formSubmitButtonClick)
38
- }
@@ -1,78 +0,0 @@
1
- import { Snapshot, SnapshotRenderer, ErrorRenderer, uuid } from "turbolinks"
2
- import { formSubmitSelector } from "./selectors"
3
- import { matches } from "./utils/dom"
4
- import { delegate } from "./utils/event"
5
-
6
- const nullCallback = function () {}
7
- const nullDelegate = {
8
- viewInvalidated: nullCallback,
9
- viewWillRender: nullCallback,
10
- viewRendered: nullCallback,
11
- }
12
-
13
- const renderWithTurbolinks = (htmlContent) => {
14
- const currentSnapshot = Snapshot.fromHTMLElement(document.documentElement)
15
- const newSnapshot = Snapshot.fromHTMLString(htmlContent)
16
- let renderer = new SnapshotRenderer(currentSnapshot, newSnapshot, false)
17
-
18
- if (!renderer.shouldRender()) {
19
- renderer = new ErrorRenderer(htmlContent)
20
- }
21
-
22
- renderer.delegate = nullDelegate
23
- renderer.render(nullCallback)
24
- }
25
-
26
- const findActiveElement = (shadowRoot: ShadowRoot) => {
27
- let el = shadowRoot.activeElement
28
-
29
- while (el && el.shadowRoot && el.shadowRoot.activeElement) {
30
- el = el.shadowRoot.activeElement
31
- }
32
-
33
- return el
34
- }
35
-
36
- export const addShadowDomSupportToTurbolinks = (turbolinksController) => {
37
- // From https://github.com/turbolinks/turbolinks/blob/71b7a7d0546a573735af99113b622180e8a813c2/src/util.ts#L9
38
- // © 2019 Basecamp, LLC.
39
- const originalClosest: typeof turbolinksController.closest = turbolinksController.closest
40
-
41
- turbolinksController.closest = (node, selector) => {
42
- if (!!node.shadowRoot) {
43
- const rootActiveElement = findActiveElement(node.shadowRoot) || node
44
-
45
- if (matches(rootActiveElement, selector)) {
46
- return rootActiveElement
47
- }
48
- } else {
49
- return originalClosest(node, selector)
50
- }
51
- }
52
- }
53
-
54
- // Turbolinks does not automatically handle form responses. This creates a handler that does it.
55
- // From https://github.com/turbolinks/turbolinks/issues/85#issuecomment-299617076
56
- export const handleResponse = (turbolinksInstance) => {
57
- return (event: CustomEvent<[XMLHttpRequest, string]>) => {
58
- const [xhr, _status] = event.detail
59
-
60
- if (xhr.getResponseHeader("Content-Type").startsWith("text/html")) {
61
- turbolinksInstance.restorationIdentifier = uuid()
62
- turbolinksInstance.clearCache()
63
- turbolinksInstance.dispatch("turbolinks:before-cache")
64
- turbolinksInstance.controller.pushHistoryWithLocationAndRestorationIdentifier(
65
- xhr.responseURL,
66
- turbolinksInstance.restorationIdentifier
67
- )
68
- renderWithTurbolinks(xhr.responseText)
69
- window.scroll(0, 0)
70
- turbolinksInstance.dispatch("turbolinks:load")
71
- }
72
- }
73
- }
74
-
75
- export const startTurbolinks = (turbolinksInstance) => {
76
- delegate(document, formSubmitSelector, "ajax:complete", handleResponse(turbolinksInstance))
77
- addShadowDomSupportToTurbolinks(turbolinksInstance)
78
- }
@@ -1,146 +0,0 @@
1
- // This code was heavily inspired by the rails-ujs project.
2
- // Copyright (c) 2007-2021 Rails Core team.
3
- import { cspNonce } from "./csp"
4
- import { CSRFProtection } from "./csrf"
5
-
6
- const AcceptHeaders = {
7
- "*": "*/*",
8
- text: "text/plain",
9
- html: "text/html",
10
- xml: "application/xml, text/xml",
11
- json: "application/json, text/javascript",
12
- script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript",
13
- }
14
-
15
- export const ajax = (options) => {
16
- options = prepareOptions(options)
17
- var xhr = createXHR(options, function () {
18
- const response = processResponse(
19
- xhr.response != null ? xhr.response : xhr.responseText,
20
- xhr.getResponseHeader("Content-Type")
21
- )
22
-
23
- if (Math.floor(xhr.status / 100) === 2) {
24
- if (typeof options.success === "function") {
25
- options.success(response, xhr.statusText, xhr)
26
- }
27
- } else {
28
- if (typeof options.error === "function") {
29
- options.error(response, xhr.statusText, xhr)
30
- }
31
- }
32
- return typeof options.complete === "function" ? options.complete(xhr, xhr.statusText) : undefined
33
- })
34
-
35
- if (options.beforeSend != null && !options.beforeSend(xhr, options)) {
36
- return false
37
- }
38
-
39
- if (xhr.readyState === XMLHttpRequest.OPENED) {
40
- return xhr.send(options.data)
41
- }
42
- }
43
-
44
- const prepareOptions = (options) => {
45
- options.url = options.url || location.href
46
- options.type = options.type.toUpperCase()
47
- // append data to url if it's a GET request
48
- if (options.type === "GET" && options.data) {
49
- if (options.url.indexOf("?") < 0) {
50
- options.url += "?" + options.data
51
- } else {
52
- options.url += "&" + options.data
53
- }
54
- }
55
-
56
- // Use "*" as default dataType
57
- if (AcceptHeaders[options.dataType] == null) {
58
- options.dataType = "*"
59
- }
60
-
61
- options.accept = AcceptHeaders[options.dataType]
62
- if (options.dataType !== "*") {
63
- options.accept += ", */*; q=0.01"
64
- }
65
-
66
- return options
67
- }
68
-
69
- const createXHR = (options, done) => {
70
- const xhr = new XMLHttpRequest()
71
-
72
- // Open and set up xhr
73
- xhr.open(options.type, options.url, true)
74
- xhr.setRequestHeader("Accept", options.accept)
75
-
76
- // Set Content-Type only when sending a string
77
- // Sending FormData will automatically set Content-Type to multipart/form-data
78
- if (typeof options.data === "string") {
79
- xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
80
- }
81
-
82
- if (!options.crossDomain) {
83
- xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")
84
- CSRFProtection(xhr)
85
- }
86
-
87
- xhr.withCredentials = !!options.withCredentials
88
- xhr.onreadystatechange = function () {
89
- if (xhr.readyState === XMLHttpRequest.DONE) {
90
- return done(xhr)
91
- }
92
- }
93
- return xhr
94
- }
95
-
96
- const processResponse = (response, type) => {
97
- if (typeof response === "string" && typeof type === "string") {
98
- if (type.match(/\bjson\b/)) {
99
- try {
100
- response = JSON.parse(response)
101
- } catch (error) {
102
- // no-op...
103
- }
104
- } else if (type.match(/\b(?:java|ecma)script\b/)) {
105
- const script = document.createElement("script")
106
- script.setAttribute("nonce", cspNonce())
107
- script.text = response
108
- document.head.appendChild(script).parentNode.removeChild(script)
109
- } else if (type.match(/\b(xml|html|svg)\b/)) {
110
- const parser = new DOMParser()
111
- type = type.replace(/;.+/, "") // remove something like ';charset=utf-8'
112
-
113
- try {
114
- response = parser.parseFromString(response, type)
115
- } catch (error1) {}
116
- }
117
- }
118
-
119
- return response
120
- }
121
-
122
- // Default way to get an element's href. May be overridden at Rails.href.
123
- export const href = (element) => element.href
124
-
125
- // Determines if the request is a cross domain request.
126
- export const isCrossDomain = (url) => {
127
- const originAnchor = document.createElement("a")
128
- originAnchor.href = location.href
129
- const urlAnchor = document.createElement("a")
130
-
131
- try {
132
- urlAnchor.href = url
133
- // If URL protocol is false or is a string containing a single colon
134
- // *and* host are false, assume it is not a cross-domain request
135
- // (should only be the case for IE7 and IE compatibility mode).
136
- // Otherwise, evaluate protocol and host of the URL against the origin
137
- // protocol and host.
138
- return !(
139
- ((!urlAnchor.protocol || urlAnchor.protocol === ":") && !urlAnchor.host) ||
140
- originAnchor.protocol + "//" + originAnchor.host === urlAnchor.protocol + "//" + urlAnchor.host
141
- )
142
- } catch (e) {
143
- // If there is an error parsing the URL, assume it is crossDomain.
144
- return true
145
- }
146
- }
@@ -1,20 +0,0 @@
1
- // This code was heavily inspired by the rails-ujs project.
2
- // Copyright (c) 2007-2021 Rails Core team.
3
- let nonce = null
4
-
5
- const loadCSPNonce = () => {
6
- if (nonce) {
7
- return nonce
8
- }
9
-
10
- const cspMetaTag: HTMLMetaElement = document.querySelector("meta[name=csp-nonce]")
11
-
12
- if (cspMetaTag) {
13
- nonce = cspMetaTag.content
14
- }
15
-
16
- return nonce
17
- }
18
-
19
- // Returns the Content-Security-Policy nonce for inline scripts.
20
- export const cspNonce = () => (nonce != null ? nonce : loadCSPNonce())
@@ -1,33 +0,0 @@
1
- // This code was heavily inspired by the rails-ujs project.
2
- // Copyright (c) 2007-2021 Rails Core team.
3
- const $ = (selector) => Array.prototype.slice.call(document.querySelectorAll(selector))
4
-
5
- // Up-to-date Cross-Site Request Forgery token
6
- export const csrfToken = () => {
7
- const meta: HTMLMetaElement = document.querySelector("meta[name=csrf-token]")
8
- return meta && meta.content
9
- }
10
-
11
- // URL param that must contain the CSRF token
12
- export const csrfParam = () => {
13
- const meta: HTMLMetaElement = document.querySelector("meta[name=csrf-param]")
14
- return meta && meta.content
15
- }
16
-
17
- // Make sure that every Ajax request sends the CSRF token
18
- export const CSRFProtection = (xhr) => {
19
- const token = csrfToken()
20
- if (token != null) {
21
- return xhr.setRequestHeader("X-CSRF-Token", token)
22
- }
23
- }
24
-
25
- // Make sure that all forms have actual up-to-date tokens (cached forms contain old ones)
26
- export const refreshCSRFTokens = () => {
27
- const token = csrfToken()
28
- const param = csrfParam()
29
-
30
- if (token != null && param != null) {
31
- return $('sl-form input[name="' + param + '"]').forEach((input) => (input.value = token))
32
- }
33
- }
@@ -1,40 +0,0 @@
1
- // This code was heavily inspired by the rails-ujs project.
2
- // Copyright (c) 2007-2021 Rails Core team.
3
- const elementPrototype = Element.prototype as any
4
-
5
- const m: (this: Element, selector: string) => boolean =
6
- elementPrototype.matches ||
7
- elementPrototype.matchesSelector ||
8
- elementPrototype.mozMatchesSelector ||
9
- elementPrototype.msMatchesSelector ||
10
- elementPrototype.oMatchesSelector ||
11
- elementPrototype.webkitMatchesSelector
12
-
13
- // Checks if the given native dom element matches the selector
14
- // element::
15
- // native DOM element
16
- // selector::
17
- // CSS selector string or
18
- // a JavaScript object with `selector` and `exclude` properties
19
- // Examples: "form", { selector: "form", exclude: "form[data-remote='true']"}
20
- export const matches = (element, selector) => {
21
- if (selector.exclude != null) {
22
- return m.call(element, selector.selector) && !m.call(element, selector.exclude)
23
- } else {
24
- return m.call(element, selector)
25
- }
26
- }
27
-
28
- // get and set data on a given element using "expando properties"
29
- // See: https://developer.mozilla.org/en-US/docs/Glossary/Expando
30
- const expando = "_ujsData"
31
-
32
- export const getData = (element, key) => (element[expando] != null ? element[expando][key] : undefined)
33
-
34
- export const setData = (element, key, value) => {
35
- if (element[expando] == null) {
36
- element[expando] = {}
37
- }
38
-
39
- return (element[expando][key] = value)
40
- }
@@ -1,57 +0,0 @@
1
- // This code was heavily inspired by the rails-ujs project.
2
- // Copyright (c) 2007-2021 Rails Core team.
3
- import { matches } from "./dom"
4
-
5
- // Triggers a custom event on an element and returns false if the event result is false
6
- // obj::
7
- // a native DOM element
8
- // name::
9
- // string that corresponds to the event you want to trigger
10
- // e.g. 'click', 'submit'
11
- // data::
12
- // data you want to pass when you dispatch an event
13
- export const fire = (obj, name, data = {}) => {
14
- const event = new CustomEvent(name, {
15
- bubbles: true,
16
- cancelable: true,
17
- detail: data,
18
- })
19
-
20
- obj.dispatchEvent(event)
21
- return !event.defaultPrevented
22
- }
23
-
24
- // Helper function, needed to provide consistent behavior in IE
25
- export const stopEverything = (event) => {
26
- fire(event.target, "ujs:everythingStopped")
27
-
28
- event.preventDefault()
29
- event.stopPropagation()
30
-
31
- return event.stopImmediatePropagation()
32
- }
33
-
34
- // Delegates events
35
- // to a specified parent `element`, which fires event `handler`
36
- // for the specified `selector` when an event of `eventType` is triggered
37
- // element::
38
- // parent element that will listen for events e.g. document
39
- // selector::
40
- // CSS selector; or an object that has `selector` and `exclude` properties (see: Rails.matches)
41
- // eventType::
42
- // string representing the event e.g. 'submit', 'click'
43
- // handler::
44
- // the event handler to be called
45
- export const delegate = (element, selector, eventType, handler) =>
46
- element.addEventListener(eventType, function (event) {
47
- let { target } = event
48
-
49
- while (!!(target instanceof Element) && !matches(target, selector)) {
50
- target = target.parentNode
51
- }
52
-
53
- if (target instanceof Element && handler.call(target, event) === false) {
54
- event.preventDefault()
55
- return event.stopPropagation()
56
- }
57
- })