turbo_boost-commands 0.0.11 → 0.0.13

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.

Potentially problematic release.


This version of turbo_boost-commands might be problematic. Click here for more details.

@@ -0,0 +1 @@
1
+ {"inputs":{"app/javascript/meta.js":{"bytes":337,"imports":[],"format":"esm"},"app/javascript/events.js":{"bytes":783,"imports":[{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"},"app/javascript/state/observable.js":{"bytes":920,"imports":[{"path":"app/javascript/meta.js","kind":"import-statement","original":"../meta"},{"path":"app/javascript/events.js","kind":"import-statement","original":"../events"}],"format":"esm"},"app/javascript/state/index.js":{"bytes":1835,"imports":[{"path":"app/javascript/meta.js","kind":"import-statement","original":"../meta"},{"path":"app/javascript/state/observable.js","kind":"import-statement","original":"./observable"},{"path":"app/javascript/events.js","kind":"import-statement","original":"../events"},{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"},"app/javascript/renderer.js":{"bytes":475,"imports":[],"format":"esm"},"app/javascript/activity.js":{"bytes":279,"imports":[],"format":"esm"},"app/javascript/lifecycle.js":{"bytes":610,"imports":[{"path":"app/javascript/activity.js","kind":"import-statement","original":"./activity"},{"path":"app/javascript/events.js","kind":"import-statement","original":"./events"}],"format":"esm"},"app/javascript/turbo.js":{"bytes":1952,"imports":[{"path":"app/javascript/meta.js","kind":"import-statement","original":"./meta"},{"path":"app/javascript/state/index.js","kind":"import-statement","original":"./state"},{"path":"app/javascript/renderer.js","kind":"import-statement","original":"./renderer"},{"path":"app/javascript/events.js","kind":"import-statement","original":"./events"},{"path":"app/javascript/lifecycle.js","kind":"import-statement","original":"./lifecycle"},{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"},"app/javascript/schema.js":{"bytes":210,"imports":[{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"},"app/javascript/confirmation.js":{"bytes":947,"imports":[{"path":"app/javascript/events.js","kind":"import-statement","original":"./events"},{"path":"app/javascript/schema.js","kind":"import-statement","original":"./schema"}],"format":"esm"},"app/javascript/delegates.js":{"bytes":923,"imports":[{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"},"app/javascript/elements.js":{"bytes":1451,"imports":[{"path":"app/javascript/schema.js","kind":"import-statement","original":"./schema"},{"path":"app/javascript/lifecycle.js","kind":"import-statement","original":"./lifecycle"}],"format":"esm"},"app/javascript/drivers/form.js":{"bytes":313,"imports":[{"path":"app/javascript/meta.js","kind":"import-statement","original":"../meta"}],"format":"esm"},"app/javascript/urls.js":{"bytes":240,"imports":[],"format":"esm"},"app/javascript/drivers/frame.js":{"bytes":218,"imports":[{"path":"app/javascript/urls.js","kind":"import-statement","original":"../urls"},{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"},"app/javascript/drivers/method.js":{"bytes":265,"imports":[{"path":"app/javascript/urls.js","kind":"import-statement","original":"../urls"},{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"},"app/javascript/drivers/window.js":{"bytes":2074,"imports":[{"path":"app/javascript/meta.js","kind":"import-statement","original":"../meta"},{"path":"app/javascript/state/index.js","kind":"import-statement","original":"../state"},{"path":"app/javascript/events.js","kind":"import-statement","original":"../events"},{"path":"app/javascript/lifecycle.js","kind":"import-statement","original":"../lifecycle"},{"path":"app/javascript/urls.js","kind":"import-statement","original":"../urls"},{"path":"app/javascript/renderer.js","kind":"import-statement","original":"../renderer"},{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"},"app/javascript/drivers/index.js":{"bytes":2044,"imports":[{"path":"app/javascript/elements.js","kind":"import-statement","original":"../elements"},{"path":"app/javascript/drivers/form.js","kind":"import-statement","original":"./form"},{"path":"app/javascript/drivers/frame.js","kind":"import-statement","original":"./frame"},{"path":"app/javascript/drivers/method.js","kind":"import-statement","original":"./method"},{"path":"app/javascript/drivers/window.js","kind":"import-statement","original":"./window"}],"format":"esm"},"app/javascript/logger.js":{"bytes":729,"imports":[{"path":"app/javascript/events.js","kind":"import-statement","original":"./events"}],"format":"esm"},"app/javascript/uuids.js":{"bytes":202,"imports":[],"format":"esm"},"app/javascript/index.js":{"bytes":3551,"imports":[{"path":"app/javascript/turbo.js","kind":"import-statement","original":"./turbo"},{"path":"app/javascript/schema.js","kind":"import-statement","original":"./schema"},{"path":"app/javascript/events.js","kind":"import-statement","original":"./events"},{"path":"app/javascript/activity.js","kind":"import-statement","original":"./activity"},{"path":"app/javascript/confirmation.js","kind":"import-statement","original":"./confirmation"},{"path":"app/javascript/delegates.js","kind":"import-statement","original":"./delegates"},{"path":"app/javascript/drivers/index.js","kind":"import-statement","original":"./drivers"},{"path":"app/javascript/meta.js","kind":"import-statement","original":"./meta"},{"path":"app/javascript/elements.js","kind":"import-statement","original":"./elements"},{"path":"app/javascript/lifecycle.js","kind":"import-statement","original":"./lifecycle"},{"path":"app/javascript/logger.js","kind":"import-statement","original":"./logger"},{"path":"app/javascript/state/index.js","kind":"import-statement","original":"./state"},{"path":"app/javascript/urls.js","kind":"import-statement","original":"./urls"},{"path":"app/javascript/uuids.js","kind":"import-statement","original":"./uuids"},{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"}},"outputs":{"app/assets/builds/@turbo-boost/commands.js.map":{"imports":[],"exports":[],"inputs":{},"bytes":37483},"app/assets/builds/@turbo-boost/commands.js":{"imports":[],"exports":["default"],"entryPoint":"app/javascript/index.js","inputs":{"app/javascript/meta.js":{"bytesInOutput":252},"app/javascript/events.js":{"bytesInOutput":500},"app/javascript/state/observable.js":{"bytesInOutput":405},"app/javascript/state/index.js":{"bytesInOutput":762},"app/javascript/renderer.js":{"bytesInOutput":263},"app/javascript/activity.js":{"bytesInOutput":173},"app/javascript/lifecycle.js":{"bytesInOutput":294},"app/javascript/turbo.js":{"bytesInOutput":1024},"app/javascript/schema.js":{"bytesInOutput":166},"app/javascript/confirmation.js":{"bytesInOutput":424},"app/javascript/delegates.js":{"bytesInOutput":473},"app/javascript/elements.js":{"bytesInOutput":782},"app/javascript/drivers/form.js":{"bytesInOutput":187},"app/javascript/urls.js":{"bytesInOutput":166},"app/javascript/drivers/frame.js":{"bytesInOutput":96},"app/javascript/drivers/method.js":{"bytesInOutput":130},"app/javascript/drivers/window.js":{"bytesInOutput":1329},"app/javascript/drivers/index.js":{"bytesInOutput":991},"app/javascript/logger.js":{"bytesInOutput":399},"app/javascript/uuids.js":{"bytesInOutput":154},"app/javascript/index.js":{"bytesInOutput":1684}},"bytes":11151}}}
Binary file
@@ -1,20 +1,20 @@
1
1
  const active = {}
2
2
 
3
- function add (payload) {
3
+ function add(payload) {
4
4
  active[payload.id] = payload
5
5
  }
6
6
 
7
- function remove (id) {
7
+ function remove(id) {
8
8
  delete active[id]
9
9
  }
10
10
 
11
11
  export default {
12
12
  add,
13
13
  remove,
14
- get commands () {
14
+ get commands() {
15
15
  return [...Object.values(active)]
16
16
  },
17
- get length () {
17
+ get length() {
18
18
  return Object.keys(active).length
19
19
  }
20
20
  }
@@ -0,0 +1,33 @@
1
+ import { commandEvents } from './events'
2
+ import schema from './schema'
3
+
4
+ const confirmation = {
5
+ method: message => Promise.resolve(confirm(message))
6
+ }
7
+
8
+ const isTurboMethod = event => event.detail.driver === 'method'
9
+
10
+ const isTurboForm = event => {
11
+ if (event.detail.driver !== 'form') return false
12
+
13
+ const element = event.target
14
+ const frame = element.closest('turbo-frame')
15
+ const target = element.closest(`[${schema.frameAttribute}]`)
16
+ return !!(frame || target)
17
+ }
18
+
19
+ const shouldDelegate = event => isTurboMethod(event) || isTurboForm(event)
20
+
21
+ document.addEventListener(commandEvents.start, async event => {
22
+ const message = event.target.getAttribute(schema.confirmAttribute)
23
+ if (!message) return
24
+
25
+ event.detail.confirmation = true
26
+
27
+ if (shouldDelegate(event)) return // delegate confirmation handling to Turbo
28
+
29
+ const proceed = await confirmation.method(message)
30
+ if (!proceed) event.preventDefault()
31
+ })
32
+
33
+ export default confirmation
@@ -1,23 +1,24 @@
1
1
  let events = []
2
2
  let eventListener
3
3
 
4
- function register (eventName, selectors) {
4
+ function register(eventName, selectors) {
5
5
  const match = events.find(evt => evt.name === eventName)
6
6
  if (match) events.splice(events.indexOf(match), 1)
7
7
  events = [{ name: eventName, selectors }, ...events]
8
+
9
+ document.removeEventListener(eventName, eventListener, true)
8
10
  document.addEventListener(eventName, eventListener, true)
11
+
9
12
  return { ...events.find(evt => evt.name === eventName) }
10
13
  }
11
14
 
12
- function getRegisteredEventForElement (element) {
15
+ function getRegisteredEventForElement(element) {
13
16
  return events.find(evt =>
14
- evt.selectors.find(selector =>
15
- Array.from(document.querySelectorAll(selector)).find(el => el === element)
16
- )
17
+ evt.selectors.find(selector => Array.from(document.querySelectorAll(selector)).find(el => el === element))
17
18
  )
18
19
  }
19
20
 
20
- function isRegisteredForElement (eventName, element) {
21
+ function isRegisteredForElement(eventName, element) {
21
22
  const evt = getRegisteredEventForElement(element)
22
23
  return evt && evt.name === eventName
23
24
  }
@@ -25,10 +26,10 @@ function isRegisteredForElement (eventName, element) {
25
26
  export default {
26
27
  register,
27
28
  isRegisteredForElement,
28
- get events () {
29
+ get events() {
29
30
  return [...events]
30
31
  },
31
- set handler (fn) {
32
+ set handler(fn) {
32
33
  eventListener = fn
33
34
  }
34
35
  }
@@ -1,6 +1,6 @@
1
1
  import meta from '../meta'
2
2
 
3
- function invokeCommand (form, payload = {}) {
3
+ function invokeCommand(form, payload = {}) {
4
4
  payload.token = meta.token
5
5
  const input = document.createElement('input')
6
6
  input.type = 'hidden'
@@ -1,6 +1,6 @@
1
1
  import urls from '../urls'
2
2
 
3
- function invokeCommand (frame, payload) {
3
+ function invokeCommand(frame, payload) {
4
4
  const src = payload.src
5
5
  payload = { ...payload }
6
6
  delete payload.src
@@ -4,14 +4,12 @@ import frameDriver from './frame'
4
4
  import methodDriver from './method'
5
5
  import windowDriver from './window'
6
6
 
7
- function src (element, frame) {
7
+ function src(element, frame) {
8
8
  frame = frame || { dataset: {} }
9
- return (
10
- element.href || frame.src || frame.dataset.turboBoostSrc || location.href
11
- )
9
+ return element.href || frame.src || frame.dataset.turboBoostSrc || location.href
12
10
  }
13
11
 
14
- function find (element) {
12
+ function find(element) {
15
13
  let frame = elements.findClosestFrameWithSource(element)
16
14
 
17
15
  const { turboFrame, turboMethod } = element.dataset
@@ -50,8 +48,7 @@ function find (element) {
50
48
  if ((!turboFrame || turboFrame === '_self') && frame)
51
49
  return {
52
50
  name: 'frame',
53
- reason:
54
- 'element does NOT target a frame or targets _self and is contained by a frame',
51
+ reason: 'element does NOT target a frame or targets _self and is contained by a frame',
55
52
  frame,
56
53
  src: src(element, frame),
57
54
  invokeCommand: frameDriver.invokeCommand
@@ -1,6 +1,6 @@
1
1
  import urls from '../urls'
2
2
 
3
- function invokeCommand (element, payload = {}) {
3
+ function invokeCommand(element, payload = {}) {
4
4
  const src = payload.src
5
5
  payload = { ...payload }
6
6
  delete payload.src
@@ -5,40 +5,37 @@ import lifecycle from '../lifecycle'
5
5
  import urls from '../urls'
6
6
  import renderer from '../renderer'
7
7
 
8
- function aborted (event) {
8
+ function aborted(event) {
9
9
  const xhr = event.target
10
10
  dispatch(lifecycle.events.abort, document, {
11
11
  detail: { ...event.detail, xhr }
12
12
  })
13
13
  }
14
14
 
15
- function errored (event) {
15
+ function errored(event) {
16
16
  const xhr = event.target
17
17
 
18
- xhr.getResponseHeader('TurboBoost') === 'Append'
19
- ? renderer.append(xhr.responseText)
20
- : renderer.replaceDocument(xhr.responseText)
18
+ const append =
19
+ xhr.getResponseHeader('TurboBoost') === 'Append' ||
20
+ xhr.getResponseHeader('Content-Type').startsWith('text/vnd.turbo-boost.html')
21
+ append ? renderer.append(xhr.responseText) : renderer.replaceDocument(xhr.responseText)
21
22
 
22
23
  const error = `Server returned a ${xhr.status} status code! TurboBoost Commands require 2XX-3XX status codes.`
23
24
 
24
- dispatch(
25
- lifecycle.events.clientError,
26
- document,
27
- { detail: { ...event.detail, error, xhr } },
28
- true
29
- )
25
+ dispatch(lifecycle.events.clientError, document, { detail: { ...event.detail, error, xhr } }, true)
30
26
  }
31
27
 
32
- function loaded (event) {
28
+ function loaded(event) {
33
29
  const xhr = event.target
34
30
  if (xhr.status < 200 || xhr.status > 399) return errored(event)
35
31
  const content = xhr.responseText
36
- xhr.getResponseHeader('TurboBoost') === 'Append'
37
- ? renderer.append(xhr.responseText)
38
- : renderer.replaceDocument(xhr.responseText)
32
+ const append =
33
+ xhr.getResponseHeader('TurboBoost') === 'Append' ||
34
+ xhr.getResponseHeader('Content-Type').startsWith('text/vnd.turbo-boost.html')
35
+ append ? renderer.append(xhr.responseText) : renderer.replaceDocument(xhr.responseText)
39
36
  }
40
37
 
41
- function invokeCommand (payload) {
38
+ function invokeCommand(payload) {
42
39
  const src = payload.src
43
40
  payload = { ...payload }
44
41
  delete payload.src
@@ -46,16 +43,10 @@ function invokeCommand (payload) {
46
43
  try {
47
44
  const xhr = new XMLHttpRequest()
48
45
  xhr.open('GET', urls.build(src, payload), true)
49
- xhr.setRequestHeader(
50
- 'Accept',
51
- 'text/vnd.turbo-boost.html, text/html, application/xhtml+xml'
52
- )
46
+ xhr.setRequestHeader('Accept', 'text/vnd.turbo-boost.html, text/html, application/xhtml+xml')
53
47
  xhr.setRequestHeader('TurboBoost-Token', meta.token)
54
48
  state.payloadChunks.forEach((chunk, i) =>
55
- xhr.setRequestHeader(
56
- `TurboBoost-State-${i.toString().padStart(4, '0')}`,
57
- chunk
58
- )
49
+ xhr.setRequestHeader(`TurboBoost-State-${i.toString().padStart(4, '0')}`, chunk)
59
50
  )
60
51
 
61
52
  xhr.addEventListener('abort', aborted)
@@ -1,11 +1,11 @@
1
1
  import schema from './schema'
2
2
  import lifecycle from './lifecycle'
3
3
 
4
- function findClosestCommand (element) {
4
+ function findClosestCommand(element) {
5
5
  return element.closest(`[${schema.commandAttribute}]`)
6
6
  }
7
7
 
8
- function findClosestFrameWithSource (element) {
8
+ function findClosestFrameWithSource(element) {
9
9
  return (
10
10
  element.closest('turbo-frame[src]') ||
11
11
  element.closest('turbo-frame[data-turbo-frame-src]') ||
@@ -13,12 +13,10 @@ function findClosestFrameWithSource (element) {
13
13
  )
14
14
  }
15
15
 
16
- function assignElementValueToPayload (element, payload = {}) {
17
- if (element.tagName.toLowerCase() !== 'select')
18
- return (payload.value = element.value || null)
16
+ function assignElementValueToPayload(element, payload = {}) {
17
+ if (element.tagName.toLowerCase() !== 'select') return (payload.value = element.value || null)
19
18
 
20
- if (!element.multiple)
21
- return (payload.value = element.options[element.selectedIndex].value)
19
+ if (!element.multiple) return (payload.value = element.options[element.selectedIndex].value)
22
20
 
23
21
  payload.values = Array.from(element.options).reduce((memo, option) => {
24
22
  if (option.selected) memo.push(option.value)
@@ -26,7 +24,7 @@ function assignElementValueToPayload (element, payload = {}) {
26
24
  }, [])
27
25
  }
28
26
 
29
- function buildAttributePayload (element) {
27
+ function buildAttributePayload(element) {
30
28
  const payload = Array.from(element.attributes).reduce((memo, attr) => {
31
29
  let value = attr.value
32
30
  memo[attr.name] = value
@@ -14,11 +14,13 @@ export const stateEvents = {
14
14
 
15
15
  export const allEvents = { ...commandEvents, ...stateEvents }
16
16
 
17
- export function dispatch (name, target, options = {}) {
18
- options = options || {}
19
- options.detail = options.detail || {}
20
- target = target || document
21
- const evt = new CustomEvent(name, { ...options, bubbles: true })
22
- target.dispatchEvent(evt)
23
- return evt
17
+ export function dispatch(name, target, options = {}) {
18
+ return new Promise(resolve => {
19
+ options = options || {}
20
+ options.detail = options.detail || {}
21
+ target = target || document
22
+ const evt = new CustomEvent(name, { ...options, bubbles: true })
23
+ target.dispatchEvent(evt)
24
+ resolve(evt)
25
+ })
24
26
  }
@@ -1,8 +1,8 @@
1
- import '@turbo-boost/streams'
2
1
  import './turbo'
3
2
  import schema from './schema'
4
3
  import { dispatch, commandEvents, stateEvents } from './events'
5
4
  import activity from './activity'
5
+ import confirmation from './confirmation'
6
6
  import delegates from './delegates'
7
7
  import drivers from './drivers'
8
8
  import meta from './meta'
@@ -13,7 +13,7 @@ import state from './state'
13
13
  import urls from './urls'
14
14
  import uuids from './uuids'
15
15
 
16
- function buildCommandPayload (id, element) {
16
+ function buildCommandPayload(id, element) {
17
17
  return {
18
18
  id, // uniquely identifies the command
19
19
  name: element.getAttribute(schema.commandAttribute),
@@ -23,7 +23,7 @@ function buildCommandPayload (id, element) {
23
23
  }
24
24
  }
25
25
 
26
- function invokeCommand (event) {
26
+ async function invokeCommand(event) {
27
27
  let element
28
28
  let payload = {}
29
29
 
@@ -41,12 +41,12 @@ function invokeCommand (event) {
41
41
  src: driver.src
42
42
  }
43
43
 
44
- const startEvent = dispatch(commandEvents.start, element, {
44
+ const startEvent = await dispatch(commandEvents.start, element, {
45
45
  cancelable: true,
46
46
  detail: payload
47
47
  })
48
48
 
49
- if (startEvent.defaultPrevented)
49
+ if (startEvent.defaultPrevented || (startEvent.detail.confirmation && event.defaultPrevented))
50
50
  return dispatch(commandEvents.abort, element, {
51
51
  detail: {
52
52
  message: `An event handler for '${commandEvents.start}' prevented default behavior and blocked command invocation!`,
@@ -87,16 +87,6 @@ function invokeCommand (event) {
87
87
  }
88
88
  }
89
89
 
90
- // wire things up and setup defaults for event delegation
91
- delegates.handler = invokeCommand
92
- delegates.register('click', [`[${schema.commandAttribute}]`])
93
- delegates.register('submit', [`form[${schema.commandAttribute}]`])
94
- delegates.register('change', [
95
- `input[${schema.commandAttribute}]`,
96
- `select[${schema.commandAttribute}]`,
97
- `textarea[${schema.commandAttribute}]`
98
- ])
99
-
100
90
  self.TurboBoost = self.TurboBoost || {}
101
91
 
102
92
  self.TurboBoost = {
@@ -104,22 +94,35 @@ self.TurboBoost = {
104
94
 
105
95
  stateEvents,
106
96
 
107
- get state () {
97
+ get state() {
108
98
  return state.current
109
99
  },
110
100
 
111
- get stateDelta () {
101
+ get stateDelta() {
112
102
  return state.delta
113
103
  }
114
104
  }
115
105
 
116
- self.TurboBoost.Commands = {
117
- logger,
118
- schema,
119
- events: commandEvents,
120
- registerEventDelegate: delegates.register,
121
- get eventDelegates () {
122
- return delegates.events
106
+ if (!self.TurboBoost.Commands) {
107
+ // wire things up and setup defaults for event delegation
108
+ delegates.handler = invokeCommand
109
+ delegates.register('click', [`[${schema.commandAttribute}]`])
110
+ delegates.register('submit', [`form[${schema.commandAttribute}]`])
111
+ delegates.register('change', [
112
+ `input[${schema.commandAttribute}]`,
113
+ `select[${schema.commandAttribute}]`,
114
+ `textarea[${schema.commandAttribute}]`
115
+ ])
116
+
117
+ self.TurboBoost.Commands = {
118
+ confirmation,
119
+ logger,
120
+ schema,
121
+ events: commandEvents,
122
+ registerEventDelegate: delegates.register,
123
+ get eventDelegates() {
124
+ return delegates.events
125
+ }
123
126
  }
124
127
  }
125
128
 
@@ -1,23 +1,15 @@
1
1
  import activity from './activity'
2
2
  import { dispatch, commandEvents } from './events'
3
3
 
4
- function finish (event) {
4
+ function finish(event) {
5
5
  event.detail.endedAt = Date.now()
6
6
  event.detail.milliseconds = event.detail.endedAt - event.detail.startedAt
7
- setTimeout(
8
- () =>
9
- dispatch(commandEvents.finish, event.target, { detail: event.detail }),
10
- 25
11
- )
7
+ setTimeout(() => dispatch(commandEvents.finish, event.target, { detail: event.detail }), 25)
12
8
  }
13
9
 
14
10
  // TODO: forward source event to finish (error or success)
15
11
  addEventListener(commandEvents.serverError, finish)
16
12
  addEventListener(commandEvents.success, finish)
17
- addEventListener(
18
- commandEvents.finish,
19
- event => activity.remove(event.detail.id),
20
- true
21
- )
13
+ addEventListener(commandEvents.finish, event => activity.remove(event.detail.id), true)
22
14
 
23
15
  export default { events: commandEvents }
@@ -13,17 +13,17 @@ const logLevels = {
13
13
  Object.values(events).forEach(name => {
14
14
  addEventListener(name, event => {
15
15
  if (logLevels[currentLevel].includes(event.type)) {
16
- const level = currentLevel === 'debug' ? 'log' : currentLevel
17
- console[level](event.type, { target: event.target, detail: event.detail })
16
+ const { target, detail } = event
17
+ console[currentLevel](event.type, { target, detail })
18
18
  }
19
19
  })
20
20
  })
21
21
 
22
22
  export default {
23
- get level () {
23
+ get level() {
24
24
  return currentLevel
25
25
  },
26
- set level (value) {
26
+ set level(value) {
27
27
  if (!Object.keys(logLevels).includes(value)) value = 'unknown'
28
28
  return (currentLevel = value)
29
29
  }
@@ -1,17 +1,17 @@
1
1
  class Meta {
2
- get element () {
2
+ get element() {
3
3
  return document.querySelector('meta[name="turbo-boost"]')
4
4
  }
5
5
 
6
- get token () {
6
+ get token() {
7
7
  return this.element.getAttribute('content')
8
8
  }
9
9
 
10
- get busy () {
10
+ get busy() {
11
11
  return this.element.dataset.busy === 'true'
12
12
  }
13
13
 
14
- set busy (value) {
14
+ set busy(value) {
15
15
  return (this.element.dataset.busy = !!value)
16
16
  }
17
17
  }
@@ -1,4 +1,4 @@
1
- function replaceDocument (content) {
1
+ function replaceDocument(content) {
2
2
  const head = '<html'
3
3
  const tail = '</html'
4
4
  const headIndex = content.indexOf(head)
@@ -9,7 +9,7 @@ function replaceDocument (content) {
9
9
  }
10
10
  }
11
11
 
12
- function append (content) {
12
+ function append(content) {
13
13
  document.body.insertAdjacentHTML('beforeend', content)
14
14
  }
15
15
 
@@ -1,7 +1,8 @@
1
1
  const schema = {
2
2
  frameAttribute: 'data-turbo-frame',
3
3
  methodAttribute: 'data-turbo-method',
4
- commandAttribute: 'data-turbo-command'
4
+ commandAttribute: 'data-turbo-command',
5
+ confirmAttribute: 'data-turbo-confirm'
5
6
  }
6
7
 
7
8
  export default { ...schema }
@@ -5,7 +5,7 @@ import { dispatch, commandEvents, stateEvents } from '../events'
5
5
  let loadedState, currentState, changedState
6
6
  let loadStateTimeout
7
7
 
8
- function loadState () {
8
+ function loadState() {
9
9
  if (!meta.element) return loadStateLater()
10
10
  const json = atob(meta.element.dataset.state)
11
11
  changedState = {}
@@ -19,7 +19,7 @@ function loadState () {
19
19
  )
20
20
  }
21
21
 
22
- function loadStateLater () {
22
+ function loadStateLater() {
23
23
  clearTimeout(loadStateTimeout)
24
24
  loadStateTimeout = setTimeout(loadState, 10)
25
25
  }
@@ -43,11 +43,11 @@ addEventListener(stateEvents.stateChange, event => {
43
43
  export default {
44
44
  events: stateEvents,
45
45
 
46
- get current () {
46
+ get current() {
47
47
  return currentState
48
48
  },
49
49
 
50
- get delta () {
50
+ get delta() {
51
51
  return changedState
52
52
  },
53
53
 
@@ -56,7 +56,7 @@ export default {
56
56
  // A Base64 character is an 8-bit-padded ASCII character... or 1 byte
57
57
  //
58
58
  // SEE: lib/state.rb - for info on how `state` is serialized/deserialized
59
- get payloadChunks () {
59
+ get payloadChunks() {
60
60
  return btoa(JSON.stringify(changedState)).match(/.{1,2000}/g)
61
61
  }
62
62
  }
@@ -3,17 +3,17 @@ import { dispatch, stateEvents as events } from '../events'
3
3
 
4
4
  let head
5
5
 
6
- function observable (object, parent = null) {
6
+ function observable(object, parent = null) {
7
7
  if (!object || typeof object !== 'object') return object
8
8
 
9
9
  const proxy = new Proxy(object, {
10
- deleteProperty (target, key) {
10
+ deleteProperty(target, key) {
11
11
  delete target[key]
12
12
  dispatch(events.stateChange, meta.element, { detail: { state: head } })
13
13
  return true
14
14
  },
15
15
 
16
- set (target, key, value, receiver) {
16
+ set(target, key, value, receiver) {
17
17
  target[key] = observable(value, this)
18
18
  dispatch(events.stateChange, meta.element, { detail: { state: head } })
19
19
  return true
@@ -23,8 +23,7 @@ function observable (object, parent = null) {
23
23
  if (Array.isArray(object)) {
24
24
  object.forEach((value, index) => (object[index] = observable(value, proxy)))
25
25
  } else if (typeof object === 'object') {
26
- for (const [key, value] of Object.entries(object))
27
- object[key] = observable(value, proxy)
26
+ for (const [key, value] of Object.entries(object)) object[key] = observable(value, proxy)
28
27
  }
29
28
 
30
29
  if (!parent) head = proxy
@@ -13,22 +13,15 @@ addEventListener('turbo:before-fetch-request', event => {
13
13
 
14
14
  // command invoked and busy
15
15
  if (meta.busy) {
16
- let acceptHeaders = [
17
- 'text/vnd.turbo-boost.html',
18
- fetchOptions.headers['Accept']
19
- ]
20
- acceptHeaders = acceptHeaders
21
- .filter(entry => entry && entry.trim().length > 0)
22
- .join(', ')
16
+ let acceptHeaders = ['text/vnd.turbo-boost.html', fetchOptions.headers['Accept']]
17
+ acceptHeaders = acceptHeaders.filter(entry => entry && entry.trim().length > 0).join(', ')
23
18
  fetchOptions.headers['Accept'] = acceptHeaders
24
19
  fetchOptions.headers['TurboBoost-Token'] = meta.token
25
20
  }
26
21
 
27
22
  // always send state
28
23
  state.payloadChunks.forEach((chunk, i) => {
29
- fetchOptions.headers[
30
- `TurboBoost-State-${i.toString().padStart(4, '0')}`
31
- ] = chunk
24
+ fetchOptions.headers[`TurboBoost-State-${i.toString().padStart(4, '0')}`] = chunk
32
25
  })
33
26
  })
34
27
 
@@ -42,12 +35,7 @@ addEventListener('turbo:before-fetch-response', event => {
42
35
  if (response.header('TurboBoost')) {
43
36
  if (response.statusCode < 200 || response.statusCode > 399) {
44
37
  const error = `Server returned a ${response.statusCode} status code! TurboBoost Commands require 2XX-3XX status codes.`
45
- dispatch(
46
- lifecycle.events.clientError,
47
- document,
48
- { detail: { ...event.detail, error } },
49
- true
50
- )
38
+ dispatch(lifecycle.events.clientError, document, { detail: { ...event.detail, error } }, true)
51
39
  }
52
40
 
53
41
  if (response.header('TurboBoost') === 'Append') {
@@ -60,7 +48,6 @@ addEventListener('turbo:before-fetch-response', event => {
60
48
  // fires when a frame element is navigated and finishes loading
61
49
  addEventListener('turbo:frame-load', event => {
62
50
  const frame = event.target.closest('turbo-frame')
63
- frame.dataset.turboBoostSrc =
64
- frameSources[frame.id] || frame.src || frame.dataset.turboBoostSrc
51
+ frame.dataset.turboBoostSrc = frameSources[frame.id] || frame.src || frame.dataset.turboBoostSrc
65
52
  delete frameSources[frame.id]
66
53
  })
@@ -1,4 +1,4 @@
1
- function build (urlString, payload = {}) {
1
+ function build(urlString, payload = {}) {
2
2
  const a = document.createElement('a')
3
3
  a.href = urlString
4
4
  const url = new URL(a)