turbo_boost-commands 0.0.11 → 0.0.13

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

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)