phoenix_live_view
Advanced tools
Comparing version 0.1.0-dev to 0.1.0
/* | ||
================================================================================ | ||
Phoenix LiveView Javascript Client | ||
Phoenix LiveView JavaScript Client | ||
================================================================================ | ||
## Usage | ||
See the hexdocs at `https://hexdocs.pm/phoenix_live_view` for documentation. | ||
Instantiate a single LiveSocket instances to enable LiveView | ||
client/server interaction, for example: | ||
import LiveSocket from "live_view" | ||
let liveSocket = new LiveSocket("/live") | ||
liveSocket.connect() | ||
A LiveSocket can also be created from an existing socket: | ||
import { Socket } from "phoenix" | ||
import LiveSocket from "live_view" | ||
let socket = new Socket("/live") | ||
let liveSocket = new LiveSocket(socket) | ||
liveSocket.connect() | ||
All options are passed directly to the `Phoenix.Socket` constructor, | ||
except for the following LiveView specific options: | ||
* `bindingPrefix` - the prefix to use for phoenix bindings. Defaults `"phx-"` | ||
## Events | ||
### Click Events | ||
When pushed, the value sent to the server will be chosen with the | ||
following priority: | ||
- An optional `"phx-value"` binding on the clicked element | ||
- The clicked element's `value` property | ||
- An empty string | ||
### Key Events | ||
The onkeypress, onkeydown, and onkeyup events are supported via | ||
the `phx-keypress`, `phx-keydown`, and `phx-keyup` bindings. By | ||
default, the bound element will be the event listener, but an | ||
optional `phx-target` may be provided which may be `"document"`, | ||
`"window"`, or the DOM id of a target element. | ||
When pushed, the value sent to the server will be the event's keyCode. | ||
## Loading state and Errors | ||
By default, the following classes are applied to the Live View's parent | ||
container: | ||
- `"phx-connected"` - applied when the view has connected to the server | ||
- `"phx-disconnected"` - applied when the view is not connected to the server | ||
- `"phx-error"` - applied when an error occurs on the server. Note, this | ||
class will be applied in conjunction with `"phx-disconnected"` connection | ||
to the server is lost. | ||
In addition to applied classes, an empty `"phx-loader"` exists adjacent | ||
to every LiveView, and its display status is toggled automatically based on | ||
connection and error class changes. This behavior may be disabled by overriding | ||
`.phx-loader` in your css to `display: none!important`. | ||
*/ | ||
import morphdom from "morphdom" | ||
import {Socket} from "phoenix" | ||
import morphdom from "morphdom" | ||
const PHX_VIEW = "data-phx-view" | ||
const PHX_LIVE_LINK = "data-phx-live-link" | ||
const PHX_CONNECTED_CLASS = "phx-connected" | ||
const PHX_LOADING_CLASS = "phx-loading" | ||
const PHX_DISCONNECTED_CLASS = "phx-disconnected" | ||
@@ -78,12 +22,18 @@ const PHX_ERROR_CLASS = "phx-error" | ||
const PHX_ERROR_FOR = "data-phx-error-for" | ||
const PHX_HAS_FOCUSED = "data-phx-has-focused" | ||
const PHX_HAS_FOCUSED = "phx-has-focused" | ||
const PHX_BOUND = "data-phx-bound" | ||
const FOCUSABLE_INPUTS = ["text", "textarea", "password"] | ||
const PHX_HAS_SUBMITTED = "data-phx-has-submitted" | ||
const FOCUSABLE_INPUTS = ["text", "textarea", "number", "email", "password", "search", "tel", "url"] | ||
const PHX_HAS_SUBMITTED = "phx-has-submitted" | ||
const PHX_SESSION = "data-phx-session" | ||
const PHX_STATIC = "data-phx-static" | ||
const PHX_READONLY = "data-phx-readonly" | ||
const LOADER_TIMEOUT = 100 | ||
const LOADER_ZOOM = 2 | ||
const PHX_DISABLED = "data-phx-disabled" | ||
const PHX_DISABLE_WITH = "disable-with" | ||
const PHX_HOOK = "hook" | ||
const PHX_UPDATE = "update" | ||
const LOADER_TIMEOUT = 1 | ||
const BEFORE_UNLOAD_LOADER_TIMEOUT = 200 | ||
const BINDING_PREFIX = "phx-" | ||
const PUSH_TIMEOUT = 20000 | ||
const PUSH_TIMEOUT = 30000 | ||
const LINK_HEADER = "x-requested-with" | ||
@@ -94,8 +44,23 @@ export let debug = (view, kind, msg, obj) => { | ||
// wraps value in closure or returns closure | ||
let closure = (val) => typeof val === "function" ? val : function(){ return val } | ||
let clone = (obj) => { return JSON.parse(JSON.stringify(obj)) } | ||
let closestPhxBinding = (el, binding) => { | ||
do { | ||
if(el.matches(`[${binding}]`)){ return el } | ||
el = el.parentElement || el.parentNode | ||
} while(el !== null && el.nodeType === 1 && !el.matches(PHX_VIEW_SELECTOR)) | ||
return null | ||
} | ||
let isObject = (obj) => { | ||
return typeof(obj) === "object" && !(obj instanceof Array) | ||
return obj !== null && typeof obj === "object" && !(obj instanceof Array) | ||
} | ||
let isEmpty = (obj) => { | ||
return Object.keys(obj).length === 0 | ||
for (let x in obj){ return false } | ||
return true | ||
} | ||
@@ -111,7 +76,18 @@ | ||
let serializeForm = (form, meta = {}) => { | ||
let formData = new FormData(form) | ||
let params = new URLSearchParams() | ||
for(let [key, val] of formData.entries()){ params.append(key, val) } | ||
for(let metaKey in meta){ params.append(metaKey, meta[metaKey]) } | ||
return params.toString() | ||
} | ||
let recursiveMerge = (target, source) => { | ||
for(let key in source){ | ||
let val = source[key] | ||
if(isObject(val) && target[key]){ | ||
recursiveMerge(target[key], val) | ||
let targetVal = target[key] | ||
if(isObject(val) && isObject(targetVal)){ | ||
if(targetVal.dynamics && !val.dynamics){ delete targetVal.dynamics} | ||
recursiveMerge(targetVal, val) | ||
} else { | ||
@@ -123,4 +99,10 @@ target[key] = val | ||
let Rendered = { | ||
let Session = { | ||
get(el){ return el.getAttribute(PHX_SESSION) }, | ||
isEqual(el1, el2){ return this.get(el1) === this.get(el2) } | ||
} | ||
export let Rendered = { | ||
mergeDiff(source, diff){ | ||
@@ -135,3 +117,3 @@ if(this.isNewFingerprint(diff)){ | ||
isNewFingerprint(diff){ return diff.static }, | ||
isNewFingerprint(diff = {}){ return !!diff.static }, | ||
@@ -147,3 +129,3 @@ toString(rendered){ | ||
let {static: statics} = rendered | ||
output.buffer += statics[0] | ||
@@ -180,32 +162,37 @@ for(let i = 1; i < statics.length; i++){ | ||
export class LiveSocket { | ||
constructor(urlOrSocket, opts = {}){ | ||
constructor(url, opts = {}){ | ||
this.unloaded = false | ||
window.addEventListener("beforeunload", e => { | ||
this.unloaded = true | ||
}) | ||
this.socket = this.buildSocket(urlOrSocket, opts) | ||
this.socket.onOpen(() => this.unloaded = false) | ||
this.socket = new Socket(url, opts) | ||
this.bindingPrefix = opts.bindingPrefix || BINDING_PREFIX | ||
this.opts = opts | ||
this.views = {} | ||
this.params = closure(opts.params || {}) | ||
this.viewLogger = opts.viewLogger | ||
this.activeElement = null | ||
this.prevActive = null | ||
} | ||
this.prevInput = null | ||
this.prevValue = null | ||
this.silenced = false | ||
this.root = null | ||
this.linkRef = 0 | ||
this.href = window.location.href | ||
this.pendingLink = null | ||
this.currentLocation = clone(window.location) | ||
this.hooks = opts.hooks || {} | ||
buildSocket(urlOrSocket, opts){ | ||
if(typeof urlOrSocket !== "string"){ return urlOrSocket } | ||
if(!opts.reconnectAfterMs){ | ||
opts.reconnectAfterMs = (tries) => { | ||
if(this.unloaded){ | ||
return [50, 100, 250][tries - 1] || 500 | ||
} else { | ||
return [1000, 2000, 5000, 10000][tries - 1] || 10000 | ||
} | ||
this.socket.onOpen(() => { | ||
if(this.isUnloaded()){ | ||
this.destroyAllViews() | ||
this.joinRootViews() | ||
} | ||
} | ||
return new Socket(urlOrSocket, opts) | ||
this.unloaded = false | ||
}) | ||
window.addEventListener("beforeunload", e => { | ||
this.unloaded = true | ||
}) | ||
this.bindTopLevelEvents() | ||
} | ||
getSocket(){ return this.socket } | ||
log(view, kind, msgCallback){ | ||
@@ -229,18 +216,62 @@ if(this.viewLogger){ | ||
disconnect(){ return this.socket.disconnect()} | ||
disconnect(){ this.socket.disconnect() } | ||
channel(topic, params){ return this.socket.channel(topic, params || {}) } | ||
// private | ||
getHookCallbacks(hookName){ return this.hooks[hookName] } | ||
isUnloaded(){ return this.unloaded } | ||
getBindingPrefix(){ return this.bindingPrefix } | ||
binding(kind){ return `${this.getBindingPrefix()}${kind}` } | ||
channel(topic, params){ return this.socket.channel(topic, params) } | ||
joinRootViews(){ | ||
document.querySelectorAll(`${PHX_VIEW_SELECTOR}:not([${PHX_PARENT_ID}])`).forEach(rootEl => { | ||
this.joinView(rootEl) | ||
Browser.all(document, `${PHX_VIEW_SELECTOR}:not([${PHX_PARENT_ID}])`, rootEl => { | ||
let view = this.joinView(rootEl, null, this.getHref()) | ||
this.root = this.root || view | ||
}) | ||
} | ||
joinView(el, parentView){ | ||
let view = new View(el, this, parentView) | ||
replaceRoot(href, callback = null, linkRef = this.setPendingLink(href)){ | ||
this.root.showLoader(LOADER_TIMEOUT) | ||
let rootEl = this.root.el | ||
let rootID = this.root.id | ||
let wasLoading = this.root.isLoading() | ||
Browser.fetchPage(href, (status, html) => { | ||
if(status !== 200){ return Browser.redirect(href) } | ||
let div = document.createElement("div") | ||
div.innerHTML = html | ||
this.joinView(div.firstChild, null, href, newRoot => { | ||
if(!this.commitPendingLink(linkRef)){ | ||
newRoot.destroy() | ||
return | ||
} | ||
callback && callback() | ||
this.destroyViewById(rootID) | ||
rootEl.replaceWith(newRoot.el) | ||
this.root = newRoot | ||
if(wasLoading){ this.root.showLoader() } | ||
}) | ||
}) | ||
} | ||
joinView(el, parentView, href, callback){ | ||
if(this.getViewById(el.id)){ return } | ||
let view = new View(el, this, parentView, href) | ||
this.views[view.id] = view | ||
view.join() | ||
view.join(callback) | ||
return view | ||
} | ||
owner(childEl, callback){ | ||
let view = this.getViewById(maybe(childEl.closest(PHX_VIEW_SELECTOR), "id")) | ||
if(view){ callback(view) } | ||
} | ||
getViewById(id){ return this.views[id] } | ||
@@ -252,2 +283,6 @@ | ||
destroyAllViews(){ | ||
for(let id in this.views){ this.destroyViewById(id) } | ||
} | ||
destroyViewById(id){ | ||
@@ -257,2 +292,3 @@ let view = this.views[id] | ||
delete this.views[view.id] | ||
if(this.root && view.id === this.root.id){ this.root = null } | ||
view.destroy() | ||
@@ -262,4 +298,2 @@ } | ||
getBindingPrefix(){ return this.bindingPrefix } | ||
setActiveElement(target){ | ||
@@ -290,3 +324,3 @@ if(this.activeElement === target){ return } | ||
} | ||
restorePreviouslyActiveFocus(){ | ||
@@ -302,5 +336,229 @@ if(this.prevActive && this.prevActive !== document.body){ | ||
} | ||
bindTopLevelEvents(){ | ||
this.bindClicks() | ||
this.bindNav() | ||
this.bindForms() | ||
this.bindTargetable({keyup: "keyup", keydown: "keydown"}, (e, type, view, target, phxEvent, phxTarget) => { | ||
view.pushKey(target, type, phxEvent, { | ||
altGraphKey: e.altGraphKey, | ||
altKey: e.altKey, | ||
charCode: e.charCode, | ||
code: e.code, | ||
ctrlKey: e.ctrlKey, | ||
key: e.key, | ||
keyCode: e.keyCode, | ||
keyIdentifier: e.keyIdentifier, | ||
keyLocation: e.keyLocation, | ||
location: e.location, | ||
metaKey: e.metaKey, | ||
repeat: e.repeat, | ||
shiftKey: e.shiftKey, | ||
which: e.which | ||
}) | ||
}) | ||
this.bindTargetable({blur: "focusout", focus: "focusin"}, (e, type, view, targetEl, phxEvent, phxTarget) => { | ||
if(!phxTarget){ | ||
view.pushEvent(type, targetEl, phxEvent, {type: "focus"}) | ||
} | ||
}) | ||
this.bindTargetable({blur: "blur", focus: "focus"}, (e, type, view, targetEl, phxEvent, phxTarget) => { | ||
// blur and focus are triggered on document and window. Discard one to avoid dups | ||
if(phxTarget && !phxTarget !== "window"){ | ||
view.pushEvent(type, targetEl, phxEvent, {type: e.type}) | ||
} | ||
}) | ||
} | ||
setPendingLink(href){ | ||
this.linkRef++ | ||
let ref = this.linkRef | ||
this.pendingLink = href | ||
return this.linkRef | ||
} | ||
commitPendingLink(linkRef){ | ||
if(this.linkRef !== linkRef){ | ||
return false | ||
} else { | ||
this.href = this.pendingLink | ||
this.pendingLink = null | ||
return true | ||
} | ||
} | ||
getHref(){ return this.href } | ||
hasPendingLink(){ return !!this.pendingLink } | ||
bindTargetable(events, callback){ | ||
for(let event in events){ | ||
let browserEventName = events[event] | ||
this.on(browserEventName, e => { | ||
let binding = this.binding(event) | ||
let bindTarget = this.binding("target") | ||
let targetPhxEvent = e.target.getAttribute && e.target.getAttribute(binding) | ||
if(targetPhxEvent && !e.target.getAttribute(bindTarget)){ | ||
this.owner(e.target, view => callback(e, event, view, e.target, targetPhxEvent, null)) | ||
} else { | ||
Browser.all(document, `[${binding}][${bindTarget}=window]`, el => { | ||
let phxEvent = el.getAttribute(binding) | ||
this.owner(el, view => callback(e, event, view, el, phxEvent, "window")) | ||
}) | ||
} | ||
}) | ||
} | ||
} | ||
bindClicks(){ | ||
window.addEventListener("click", e => { | ||
let click = this.binding("click") | ||
let target = closestPhxBinding(e.target, click) | ||
let phxEvent = target && target.getAttribute(click) | ||
if(!phxEvent){ return } | ||
e.preventDefault() | ||
let meta = { | ||
altKey: e.altKey, | ||
shiftKey: e.shiftKey, | ||
ctrlKey: e.ctrlKey, | ||
metaKey: e.metaKey, | ||
x: e.x || e.clientX, | ||
y: e.y || e.clientY, | ||
pageX: e.pageX, | ||
pageY: e.pageY, | ||
screenX: e.screenX, | ||
screenY: e.screenY, | ||
} | ||
this.owner(target, view => view.pushEvent("click", target, phxEvent, meta)) | ||
}, false) | ||
} | ||
bindNav(){ | ||
if(!Browser.canPushState()){ return } | ||
window.onpopstate = (event) => { | ||
if(!this.registerNewLocation(window.location)){ return } | ||
let href = window.location.href | ||
if(this.root.isConnected()) { | ||
this.root.pushInternalLink(href) | ||
} else { | ||
this.replaceRoot(href) | ||
} | ||
} | ||
window.addEventListener("click", e => { | ||
let target = closestPhxBinding(e.target, PHX_LIVE_LINK) | ||
let phxEvent = target && target.getAttribute(PHX_LIVE_LINK) | ||
if(!phxEvent){ return } | ||
let href = target.href | ||
e.preventDefault() | ||
this.root.pushInternalLink(href, () => { | ||
Browser.pushState(phxEvent, {}, href) | ||
this.registerNewLocation(window.location) | ||
}) | ||
}, false) | ||
} | ||
registerNewLocation(newLocation){ | ||
let {pathname, search} = this.currentLocation | ||
if(pathname + search === newLocation.pathname + newLocation.search){ | ||
return false | ||
} else { | ||
this.currentLocation = clone(newLocation) | ||
return true | ||
} | ||
} | ||
bindForms(){ | ||
this.on("submit", e => { | ||
let phxEvent = e.target.getAttribute(this.binding("submit")) | ||
if(!phxEvent){ return } | ||
e.preventDefault() | ||
e.target.disabled = true | ||
this.owner(e.target, view => view.submitForm(e.target, phxEvent)) | ||
}, false) | ||
for(let type of ["change", "input"]){ | ||
this.on(type, e => { | ||
let input = e.target | ||
let key = input.type === "checkbox" ? "checked" : "value" | ||
if(this.prevInput === input && this.prevValue === input[key]){ return } | ||
this.prevInput = input | ||
this.prevValue = input[key] | ||
let phxEvent = input.form && input.form.getAttribute(this.binding("change")) | ||
if(!phxEvent){ return } | ||
this.owner(input, view => { | ||
if(DOM.isTextualInput(input)){ | ||
input[PHX_HAS_FOCUSED] = true | ||
} else { | ||
this.setActiveElement(input) | ||
} | ||
view.pushInput(input, phxEvent, e) | ||
}) | ||
}, false) | ||
} | ||
} | ||
silenceEvents(callback){ | ||
this.silenced = true | ||
callback() | ||
this.silenced = false | ||
} | ||
on(event, callback){ | ||
window.addEventListener(event, e => { | ||
if(!this.silenced){ callback(e) } | ||
}) | ||
} | ||
} | ||
let Browser = { | ||
export let Browser = { | ||
all(node, query, callback){ | ||
node.querySelectorAll(query).forEach(callback) | ||
}, | ||
canPushState(){ return (typeof(history.pushState) !== "undefined") }, | ||
fetchPage(href, callback){ | ||
let req = new XMLHttpRequest() | ||
req.open("GET", href, true) | ||
req.timeout = PUSH_TIMEOUT | ||
req.setRequestHeader("content-type", "text/html") | ||
req.setRequestHeader("cache-control", "max-age=0, no-cache, no-store, must-revalidate, post-check=0, pre-check=0") | ||
req.setRequestHeader(LINK_HEADER, "live-link") | ||
req.onerror = () => callback(400) | ||
req.ontimeout = () => callback(504) | ||
req.onreadystatechange = () => { | ||
if(req.readyState !== 4){ return } | ||
if(req.getResponseHeader(LINK_HEADER) !== "live-link"){ return callback(400) } | ||
if(req.status !== 200){ return callback(req.status) } | ||
callback(200, req.responseText) | ||
} | ||
req.send() | ||
}, | ||
pushState(kind, meta, to){ | ||
if(this.canPushState()){ | ||
if(to !== window.location.href){ history[kind + "State"](meta, "", to) } | ||
} else { | ||
this.redirect(to) | ||
} | ||
}, | ||
dispatchEvent(target, eventString){ | ||
let event = null | ||
if(typeof(Event) === "function"){ | ||
event = new Event(eventString) | ||
} else { | ||
event = document.createEvent("Event") | ||
event.initEvent(eventString, true, true) | ||
} | ||
target.dispatchEvent(event) | ||
}, | ||
setCookie(name, value){ | ||
@@ -322,4 +580,15 @@ document.cookie = `${name}=${value}` | ||
setInputsReadOnly(form){ | ||
form.querySelectorAll("input").forEach(input => { | ||
disableForm(form, prefix){ | ||
let disableWith = `${prefix}${PHX_DISABLE_WITH}` | ||
form.classList.add(PHX_LOADING_CLASS) | ||
Browser.all(form, `[${disableWith}]`, el => { | ||
let value = el.getAttribute(disableWith) | ||
el.setAttribute(`${disableWith}-restore`, el.innerText) | ||
el.innerText = value | ||
}) | ||
Browser.all(form, "button", button => { | ||
button.setAttribute(PHX_DISABLED, button.disabled) | ||
button.disabled = true | ||
}) | ||
Browser.all(form, "input", input => { | ||
input.setAttribute(PHX_READONLY, input.readOnly) | ||
@@ -330,7 +599,28 @@ input.readOnly = true | ||
restoreReadOnlyInputs(form){ | ||
form.querySelectorAll("input").forEach(input => { | ||
restoreDisabledForm(form, prefix){ | ||
let disableWith = `${prefix}${PHX_DISABLE_WITH}` | ||
form.classList.remove(PHX_LOADING_CLASS) | ||
Browser.all(form, `[${disableWith}]`, el => { | ||
let value = el.getAttribute(`${disableWith}-restore`) | ||
if(value){ | ||
if(el.nodeName === "INPUT") { | ||
el.value = value | ||
} else { | ||
el.innerText = value | ||
} | ||
el.removeAttribute(`${disableWith}-restore`) | ||
} | ||
}) | ||
Browser.all(form, "button", button => { | ||
let prev = button.getAttribute(PHX_DISABLED) | ||
if(prev){ | ||
button.disabled = prev === "true" | ||
button.removeAttribute(PHX_DISABLED) | ||
} | ||
}) | ||
Browser.all(form, "input", input => { | ||
let prev = input.getAttribute(PHX_READONLY) | ||
if(prev){ | ||
input.readOnly = prev == "true" | ||
input.readOnly = prev === "true" | ||
input.removeAttribute(PHX_READONLY) | ||
@@ -346,3 +636,3 @@ } | ||
if(field && !(input.getAttribute(PHX_HAS_FOCUSED) || input.form.getAttribute(PHX_HAS_SUBMITTED))){ | ||
if(field && !(input[PHX_HAS_FOCUSED] || input.form[PHX_HAS_SUBMITTED])){ | ||
el.style.display = "none" | ||
@@ -356,6 +646,31 @@ } | ||
applyPhxUpdate(fromEl, toEl, phxUpdate){ | ||
let type = toEl.getAttribute && toEl.getAttribute(phxUpdate) | ||
if(!type || type === "replace"){ | ||
return false | ||
} else { | ||
DOM.mergeAttrs(fromEl, toEl) | ||
} | ||
switch(type){ | ||
case "ignore": break | ||
case "append": | ||
fromEl.innerHTML += toEl.innerHTML | ||
break | ||
case "prepend": | ||
fromEl.innerHTML = toEl.innerHTML + fromEl.innerHTML | ||
break | ||
default: throw new Error(`unsupported phx-update "${type}"`) | ||
} | ||
return true | ||
}, | ||
patch(view, container, id, html){ | ||
let changes = {added: [], updated: [], discarded: []} | ||
let focused = view.liveSocket.getActiveElement() | ||
let selectionStart = null | ||
let selectionEnd = null | ||
let phxUpdate = view.liveSocket.binding(PHX_UPDATE) | ||
let containerTagName = container.tagName.toLowerCase() | ||
if(DOM.isTextualInput(focused)){ | ||
@@ -366,3 +681,3 @@ selectionStart = focused.selectionStart | ||
morphdom(container, `<div>${html}</div>`, { | ||
morphdom(container, `<${containerTagName}>${html}</${containerTagName}>`, { | ||
childrenOnly: true, | ||
@@ -377,6 +692,7 @@ onBeforeNodeAdded: function(el){ | ||
if(DOM.isPhxChild(el) && view.ownsElement(el)){ | ||
view.onNewChildAdded(el) | ||
view.onNewChildAdded() | ||
return true | ||
} else { | ||
changes.added.push(el) | ||
} | ||
view.maybeBindAddedNode(el) | ||
}, | ||
@@ -389,7 +705,22 @@ onBeforeNodeDiscarded: function(el){ | ||
} | ||
changes.discarded.push(el) | ||
}, | ||
onBeforeElUpdated: function(fromEl, toEl) { | ||
if(fromEl.isEqualNode(toEl)){ return false } // Skip subtree if both elems and children are equal | ||
if(DOM.applyPhxUpdate(fromEl, toEl, phxUpdate)){ | ||
changes.updated.push({fromEl, toEl: fromEl}) | ||
return false | ||
} | ||
// nested view handling | ||
if(DOM.isPhxChild(toEl)){ | ||
let prevStatic = fromEl.getAttribute(PHX_STATIC) | ||
if(!Session.isEqual(toEl, fromEl)){ | ||
view.liveSocket.destroyViewById(fromEl.id) | ||
view.onNewChildAdded() | ||
} | ||
DOM.mergeAttrs(fromEl, toEl) | ||
fromEl.setAttribute(PHX_STATIC, prevStatic) | ||
return false | ||
@@ -399,7 +730,7 @@ } | ||
// input handling | ||
if(fromEl.getAttribute && fromEl.getAttribute(PHX_HAS_SUBMITTED)){ | ||
toEl.setAttribute(PHX_HAS_SUBMITTED, true) | ||
if(fromEl.getAttribute && fromEl[PHX_HAS_SUBMITTED]){ | ||
toEl[PHX_HAS_SUBMITTED] = true | ||
} | ||
if(fromEl.getAttribute && fromEl.getAttribute(PHX_HAS_FOCUSED)){ | ||
toEl.setAttribute(PHX_HAS_FOCUSED, true) | ||
if(fromEl[PHX_HAS_FOCUSED]){ | ||
toEl[PHX_HAS_FOCUSED] = true | ||
} | ||
@@ -410,4 +741,6 @@ DOM.discardError(toEl) | ||
DOM.mergeInputs(fromEl, toEl) | ||
changes.updated.push({fromEl, toEl: fromEl}) | ||
return false | ||
} else { | ||
changes.updated.push({fromEl, toEl}) | ||
return true | ||
@@ -418,11 +751,16 @@ } | ||
DOM.restoreFocus(focused, selectionStart, selectionEnd) | ||
document.dispatchEvent(new Event("phx:update")) | ||
view.liveSocket.silenceEvents(() => { | ||
DOM.restoreFocus(focused, selectionStart, selectionEnd) | ||
}) | ||
Browser.dispatchEvent(document, "phx:update") | ||
return changes | ||
}, | ||
mergeAttrs(target, source){ | ||
source.getAttributeNames().forEach(name => { | ||
var attrs = source.attributes | ||
for (let i = 0, length = attrs.length; i < length; i++){ | ||
let name = attrs[i].name | ||
let value = source.getAttribute(name) | ||
target.setAttribute(name, value) | ||
}) | ||
} | ||
}, | ||
@@ -449,4 +787,4 @@ | ||
class View { | ||
constructor(el, liveSocket, parentView){ | ||
export class View { | ||
constructor(el, liveSocket, parentView, href){ | ||
this.liveSocket = liveSocket | ||
@@ -457,43 +795,73 @@ this.parent = parentView | ||
this.el = el | ||
this.prevKey = null | ||
this.bindingPrefix = liveSocket.getBindingPrefix() | ||
this.loader = this.el.nextElementSibling | ||
this.id = this.el.id | ||
this.view = this.el.getAttribute(PHX_VIEW) | ||
this.hasBoundUI = false | ||
this.loaderTimer = null | ||
this.pendingDiffs = [] | ||
this.href = href | ||
this.joinedOnce = false | ||
this.viewHooks = {} | ||
this.channel = this.liveSocket.channel(`lv:${this.id}`, () => { | ||
return {session: this.getSession()} | ||
return { | ||
url: this.href || this.liveSocket.root.href, | ||
params: this.liveSocket.params(this.view), | ||
session: this.getSession(), | ||
static: this.getStatic() | ||
} | ||
}) | ||
this.loaderTimer = setTimeout(() => this.showLoader(), LOADER_TIMEOUT) | ||
this.showLoader(LOADER_TIMEOUT) | ||
this.bindChannel() | ||
} | ||
getSession(){ | ||
return this.el.getAttribute(PHX_SESSION)|| this.parent.getSession() | ||
isConnected(){ return this.channel.canPush() } | ||
getSession(){ return Session.get(this.el) } | ||
getStatic(){ | ||
let val = this.el.getAttribute(PHX_STATIC) | ||
return val === "" ? null : val | ||
} | ||
destroy(callback = function(){}){ | ||
clearTimeout(this.loaderTimer) | ||
let onFinished = () => { | ||
callback() | ||
for(let id in this.viewHooks){ this.destroyHook(this.viewHooks[id]) } | ||
} | ||
if(this.hasGracefullyClosed()){ | ||
this.log("destroyed", () => ["the server view has gracefully closed"]) | ||
callback() | ||
onFinished() | ||
} else { | ||
this.log("destroyed", () => ["the child has been removed from the parent"]) | ||
this.channel.leave() | ||
.receive("ok", callback) | ||
.receive("error", callback) | ||
.receive("timeout", callback) | ||
.receive("ok", onFinished) | ||
.receive("error", onFinished) | ||
.receive("timeout", onFinished) | ||
} | ||
} | ||
hideLoader(){ | ||
setContainerClasses(...classes){ | ||
this.el.classList.remove( | ||
PHX_CONNECTED_CLASS, | ||
PHX_DISCONNECTED_CLASS, | ||
PHX_ERROR_CLASS | ||
) | ||
this.el.classList.add(...classes) | ||
} | ||
isLoading(){ return this.el.classList.contains(PHX_DISCONNECTED_CLASS)} | ||
showLoader(timeout){ | ||
clearTimeout(this.loaderTimer) | ||
this.loader.style.display = "none" | ||
if(timeout){ | ||
this.loaderTimer = setTimeout(() => this.showLoader(), timeout) | ||
} else { | ||
for(let id in this.viewHooks){ this.viewHooks[id].__trigger__("disconnected") } | ||
this.setContainerClasses(PHX_DISCONNECTED_CLASS) | ||
} | ||
} | ||
showLoader(){ | ||
hideLoader(){ | ||
clearTimeout(this.loaderTimer) | ||
this.el.classList = PHX_DISCONNECTED_CLASS | ||
this.loader.style.display = "block" | ||
let middle = Math.floor(this.el.clientHeight / LOADER_ZOOM) | ||
this.loader.style.top = `-${middle}px` | ||
for(let id in this.viewHooks){ this.viewHooks[id].__trigger__("reconnected") } | ||
this.setContainerClasses(PHX_CONNECTED_CLASS) | ||
} | ||
@@ -504,20 +872,23 @@ | ||
} | ||
onJoin({rendered}){ | ||
onJoin({rendered, live_redirect}){ | ||
this.log("join", () => ["", JSON.stringify(rendered)]) | ||
this.rendered = rendered | ||
this.hideLoader() | ||
this.el.classList = PHX_CONNECTED_CLASS | ||
DOM.patch(this, this.el, this.id, Rendered.toString(this.rendered)) | ||
if(!this.hasBoundUI){ this.bindUI() } | ||
this.hasBoundUI = true | ||
let changes = DOM.patch(this, this.el, this.id, Rendered.toString(this.rendered)) | ||
changes.added.push(this.el) | ||
Browser.all(this.el, `[${this.binding(PHX_HOOK)}]`, hookEl => changes.added.push(hookEl)) | ||
this.triggerHooks(changes) | ||
this.joinNewChildren() | ||
if(live_redirect){ | ||
let {kind, to} = live_redirect | ||
Browser.pushState(kind, {}, to) | ||
} | ||
} | ||
joinNewChildren(){ | ||
let selector = `${PHX_VIEW_SELECTOR}[${PHX_PARENT_ID}="${this.id}"]` | ||
document.querySelectorAll(selector).forEach(childEl => { | ||
let child = this.liveSocket.getViewById(childEl.id) | ||
Browser.all(document, `${PHX_VIEW_SELECTOR}[${PHX_PARENT_ID}="${this.id}"]`, el => { | ||
let child = this.liveSocket.getViewById(el.id) | ||
if(!child){ | ||
this.liveSocket.joinView(childEl, this) | ||
this.liveSocket.joinView(el, this) | ||
} | ||
@@ -529,2 +900,4 @@ }) | ||
if(isEmpty(diff)){ return } | ||
if(this.liveSocket.hasPendingLink()){ return this.pendingDiffs.push(diff) } | ||
this.log("update", () => ["", JSON.stringify(diff)]) | ||
@@ -534,7 +907,47 @@ this.rendered = Rendered.mergeDiff(this.rendered, diff) | ||
this.newChildrenAdded = false | ||
DOM.patch(this, this.el, this.id, html) | ||
this.triggerHooks(DOM.patch(this, this.el, this.id, html)) | ||
if(this.newChildrenAdded){ this.joinNewChildren() } | ||
} | ||
onNewChildAdded(el){ | ||
getHook(el){ return this.viewHooks[ViewHook.elementID(el)] } | ||
addHook(el){ if(ViewHook.elementID(el) || !el.getAttribute){ return } | ||
let callbacks = this.liveSocket.getHookCallbacks(el.getAttribute(this.binding(PHX_HOOK))) | ||
if(callbacks && this.ownsElement(el)){ | ||
let hook = new ViewHook(this, el, callbacks) | ||
this.viewHooks[ViewHook.elementID(hook.el)] = hook | ||
hook.__trigger__("mounted") | ||
} | ||
} | ||
destroyHook(hook){ | ||
hook.__trigger__("destroyed") | ||
delete this.viewHooks[ViewHook.elementID(hook.el)] | ||
} | ||
triggerHooks(changes){ | ||
changes.updated.push({fromEl: this.el, toEl: this.el}) | ||
changes.added.forEach(el => this.addHook(el)) | ||
changes.updated.forEach(({fromEl, toEl}) => { | ||
let hook = this.getHook(fromEl) | ||
let phxAttr = this.binding(PHX_HOOK) | ||
if(hook && toEl.getAttribute && fromEl.getAttribute(phxAttr) === toEl.getAttribute(phxAttr)){ | ||
hook.__trigger__("updated") | ||
} else if(hook){ | ||
this.destroyHook(hook) | ||
this.addHook(fromEl) | ||
} | ||
}) | ||
changes.discarded.forEach(el => { | ||
let hook = this.getHook(el) | ||
hook && this.destroyHook(hook) | ||
}) | ||
} | ||
applyPendingUpdates(){ | ||
this.pendingDiffs.forEach(diff => this.update(diff)) | ||
this.pendingDiffs = [] | ||
} | ||
onNewChildAdded(){ | ||
this.newChildrenAdded = true | ||
@@ -544,4 +957,6 @@ } | ||
bindChannel(){ | ||
this.channel.on("render", (diff) => this.update(diff)) | ||
this.channel.on("redirect", ({to, flash}) => Browser.redirect(to, flash) ) | ||
this.channel.on("diff", (diff) => this.update(diff)) | ||
this.channel.on("redirect", ({to, flash}) => this.onRedirect({to, flash})) | ||
this.channel.on("live_redirect", ({to, kind}) => this.onLiveRedirect({to, kind})) | ||
this.channel.on("external_live_redirect", ({to, kind}) => this.onExternalLiveRedirect({to, kind})) | ||
this.channel.on("session", ({token}) => this.el.setAttribute(PHX_SESSION, token)) | ||
@@ -557,12 +972,32 @@ this.channel.onError(reason => this.onError(reason)) | ||
onExternalLiveRedirect({to, kind}){ | ||
this.liveSocket.replaceRoot(to, () => Browser.pushState(kind, {}, to)) | ||
} | ||
onLiveRedirect({to, kind}){ | ||
Browser.pushState(kind, {}, to) | ||
} | ||
onRedirect({to, flash}){ Browser.redirect(to, flash) } | ||
hasGracefullyClosed(){ return this.gracefullyClosed } | ||
join(){ | ||
if(this.parent){ this.parent.channel.onError(() => this.channel.leave())} | ||
join(callback){ | ||
if(this.parent){ | ||
this.parent.channel.onClose(() => this.onGracefulClose()) | ||
this.parent.channel.onError(() => this.liveSocket.destroyViewById(this.id)) | ||
} | ||
this.channel.join() | ||
.receive("ok", data => this.onJoin(data)) | ||
.receive("ok", data => { | ||
if(!this.joinedOnce){ callback && callback(this) } | ||
this.joinedOnce = true | ||
this.onJoin(data) | ||
}) | ||
.receive("error", resp => this.onJoinError(resp)) | ||
.receive("timeout", () => this.onJoinError("timeout")) | ||
} | ||
onJoinError(resp){ | ||
if(resp.redirect){ return this.onRedirect(resp.redirect) } | ||
if(resp.external_live_redirect){ return this.onExternalLiveRedirect(resp.external_live_redirect) } | ||
this.displayError() | ||
@@ -576,3 +1011,7 @@ this.log("error", () => ["unable to join", resp]) | ||
document.activeElement.blur() | ||
this.displayError() | ||
if(this.liveSocket.isUnloaded()){ | ||
this.showLoader(BEFORE_UNLOAD_LOADER_TIMEOUT) | ||
} else { | ||
this.displayError() | ||
} | ||
} | ||
@@ -582,58 +1021,77 @@ | ||
this.showLoader() | ||
this.el.classList = `${PHX_DISCONNECTED_CLASS} ${PHX_ERROR_CLASS}` | ||
this.setContainerClasses(PHX_DISCONNECTED_CLASS, PHX_ERROR_CLASS) | ||
} | ||
pushWithReply(event, payload, onReply = function(){ }){ | ||
this.channel.push(event, payload, PUSH_TIMEOUT) | ||
.receive("ok", diff => { | ||
this.update(diff) | ||
onReply() | ||
return( | ||
this.channel.push(event, payload, PUSH_TIMEOUT).receive("ok", resp => { | ||
if(resp.diff){ this.update(resp.diff) } | ||
if(resp.redirect){ this.onRedirect(resp.redirect) } | ||
if(resp.live_redirect){ this.onLiveRedirect(resp.live_redirect) } | ||
if(resp.external_live_redirect){ this.onExternalLiveRedirect(resp.external_live_redirect) } | ||
onReply(resp) | ||
}) | ||
) | ||
} | ||
pushClick(clickedEl, event, phxEvent){ | ||
event.preventDefault() | ||
let val = clickedEl.getAttribute(this.binding("value")) || clickedEl.value || "" | ||
pushEvent(type, el, phxEvent, meta){ | ||
let value = el.getAttribute(this.binding("value")) | ||
if(value === null){ | ||
value = meta | ||
let prefix = this.binding("value-") | ||
for(let key of el.getAttributeNames()){ if(!key.startsWith(prefix)){ continue } | ||
value[key.replace(prefix, "")] = el.getAttribute(key) | ||
} | ||
if(el.value !== undefined){ value.value = el.value } | ||
} | ||
this.pushWithReply("event", { | ||
type: "click", | ||
type: type, | ||
event: phxEvent, | ||
id: clickedEl.id, | ||
value: val | ||
value: value | ||
}) | ||
} | ||
pushKey(keyElement, kind, event, phxEvent){ | ||
if(this.prevKey === event.key){ return } | ||
this.prevKey = event.key | ||
pushKey(keyElement, kind, phxEvent, meta){ | ||
let value = keyElement.getAttribute(this.binding("value")) | ||
if(value === null){ | ||
value = meta | ||
if(keyElement.value !== undefined){ value.value = keyElement.value } | ||
} | ||
this.pushWithReply("event", { | ||
type: `key${kind}`, | ||
type: kind, | ||
event: phxEvent, | ||
id: event.target.id, | ||
value: keyElement.value || event.key | ||
value: value | ||
}) | ||
} | ||
pushInput(inputEl, event, phxEvent){ | ||
pushInput(inputEl, phxEvent, e){ | ||
this.pushWithReply("event", { | ||
type: "form", | ||
event: phxEvent, | ||
id: event.target.id, | ||
value: this.serializeForm(inputEl.form) | ||
value: serializeForm(inputEl.form, {_target: e.target.name}) | ||
}) | ||
} | ||
pushFormSubmit(formEl, event, phxEvent, onReply){ | ||
if(event){ event.target.disabled = true } | ||
pushFormSubmit(formEl, phxEvent, onReply){ | ||
this.pushWithReply("event", { | ||
type: "form", | ||
event: phxEvent, | ||
id: event && event.target.id || null, | ||
value: this.serializeForm(formEl) | ||
value: serializeForm(formEl) | ||
}, onReply) | ||
} | ||
eachChild(selector, each){ | ||
return this.el.querySelectorAll(selector).forEach(child => { | ||
if(this.ownsElement(child)){ each(child) } | ||
}) | ||
pushInternalLink(href, callback){ | ||
if(!this.isLoading()){ this.showLoader(LOADER_TIMEOUT) } | ||
let linkRef = this.liveSocket.setPendingLink(href) | ||
this.pushWithReply("link", {url: href}, resp => { | ||
if(resp.link_redirect){ | ||
this.liveSocket.replaceRoot(href, callback, linkRef) | ||
} else if(this.liveSocket.commitPendingLink(linkRef)){ | ||
this.href = href | ||
this.applyPendingUpdates() | ||
this.hideLoader() | ||
callback && callback() | ||
} | ||
}).receive("timeout", () => Browser.redirect(window.location.href)) | ||
} | ||
@@ -646,71 +1104,9 @@ | ||
bindUI(){ | ||
this.bindForms() | ||
this.eachChild(`[${this.binding("click")}]`, el => this.bindClick(el)) | ||
this.eachChild(`[${this.binding("keyup")}]`, el => this.bindKey(el, "up")) | ||
this.eachChild(`[${this.binding("keydown")}]`, el => this.bindKey(el, "down")) | ||
this.eachChild(`[${this.binding("keypress")}]`, el => this.bindKey(el, "press")) | ||
} | ||
bindClick(el){ | ||
this.bindOwnAddedNode(el, el, this.binding("click"), phxEvent => { | ||
el.addEventListener("click", e => this.pushClick(el, e, phxEvent)) | ||
}) | ||
} | ||
bindKey(el, kind){ | ||
let event = `key${kind}` | ||
this.bindOwnAddedNode(el, el, this.binding(event), (phxEvent) => { | ||
let phxTarget = this.target(el) | ||
phxTarget.addEventListener(event, e => { | ||
this.pushKey(el, kind, e, phxEvent) | ||
}) | ||
}) | ||
} | ||
bindForms(){ | ||
let change = this.binding("change") | ||
this.eachChild(`form[${change}] input`, input => { | ||
this.bindChange(input) | ||
}) | ||
this.eachChild(`form[${change}] select`, input => { | ||
this.bindChange(input) | ||
}) | ||
this.eachChild(`form[${change}] textarea`, textarea => { | ||
this.bindChange(textarea) | ||
}) | ||
let submit = this.binding("submit") | ||
this.eachChild(`form[${submit}]`, form => { | ||
this.bindSubmit(form) | ||
}) | ||
} | ||
bindChange(input){ | ||
this.onInput(input, (phxEvent, e) => { | ||
if(DOM.isTextualInput(input)){ | ||
input.setAttribute(PHX_HAS_FOCUSED, true) | ||
} else { | ||
this.liveSocket.setActiveElement(e.target) | ||
} | ||
this.pushInput(input, e, phxEvent) | ||
}) | ||
} | ||
bindSubmit(form){ | ||
this.bindOwnAddedNode(form, form, this.binding("submit"), phxEvent => { | ||
form.addEventListener("submit", e => { | ||
e.preventDefault() | ||
this.submitForm(form, phxEvent, e) | ||
}) | ||
this.scheduleSubmit(form, phxEvent) | ||
}) | ||
} | ||
submitForm(form, phxEvent, e){ | ||
form.setAttribute(PHX_HAS_SUBMITTED, "true") | ||
DOM.setInputsReadOnly(form) | ||
submitForm(form, phxEvent){ | ||
let prefix = this.liveSocket.getBindingPrefix() | ||
form[PHX_HAS_SUBMITTED] = "true" | ||
DOM.disableForm(form, prefix) | ||
this.liveSocket.blurActiveElement(this) | ||
this.pushFormSubmit(form, e, phxEvent, () => { | ||
DOM.restoreReadOnlyInputs(form) | ||
this.pushFormSubmit(form, phxEvent, () => { | ||
DOM.restoreDisabledForm(form, prefix) | ||
this.liveSocket.restorePreviouslyActiveFocus() | ||
@@ -720,64 +1116,28 @@ }) | ||
scheduleSubmit(form, phxEvent){ | ||
let everyMs = parseInt(form.getAttribute(this.binding("submit-every"))) | ||
if(everyMs && this.el.contains(form)){ | ||
setTimeout(() => { | ||
this.submitForm(form, phxEvent) | ||
this.scheduleSubmit(form, phxEvent) | ||
}, everyMs) | ||
} | ||
} | ||
binding(kind){ return this.liveSocket.binding(kind)} | ||
} | ||
maybeBindAddedNode(el){ | ||
if(!el.getAttribute || !this.ownsElement(el)) { return } | ||
let viewHookID = 1 | ||
class ViewHook { | ||
static makeID(){ return viewHookID++ } | ||
static elementID(el){ return el.phxHookId } | ||
this.bindClick(el) | ||
this.bindSubmit(el) | ||
this.bindChange(el) | ||
this.bindKey(el, "up") | ||
this.bindKey(el, "down") | ||
this.bindKey(el, "press") | ||
constructor(view, el, callbacks){ | ||
this.__view = view | ||
this.__callbacks = callbacks | ||
this.el = el | ||
this.viewName = view.view | ||
this.el.phxHookId = this.constructor.makeID() | ||
for(let key in this.__callbacks){ this[key] = this.__callbacks[key] } | ||
} | ||
binding(kind){ return `${this.bindingPrefix}${kind}` } | ||
// private | ||
serializeForm(form){ | ||
return((new URLSearchParams(new FormData(form))).toString()) | ||
pushEvent(event, payload){ | ||
this.__view.pushWithReply("event", {type: "hook", event: event, value: payload}) | ||
} | ||
bindOwnAddedNode(el, targetEl, event, callback){ | ||
if(targetEl && !targetEl.getAttribute){ return } | ||
let phxEvent = targetEl.getAttribute(event) | ||
if(phxEvent && !el.getAttribute(PHX_BOUND) && this.ownsElement(el)){ | ||
el.setAttribute(PHX_BOUND, true) | ||
callback(phxEvent) | ||
} | ||
__trigger__(kind){ | ||
let callback = this.__callbacks[kind] | ||
callback && callback.call(this) | ||
} | ||
onInput(input, callback){ | ||
if(!input.form){ return } | ||
this.bindOwnAddedNode(input, input.form, this.binding("change"), phxEvent => { | ||
let event = input.type === "radio" ? "change" : "input" | ||
input.addEventListener(event, e => callback(phxEvent, e)) | ||
}) | ||
} | ||
target(el){ | ||
let target = el.getAttribute(this.binding("target")) | ||
if(target === "window"){ | ||
return window | ||
}else if(target === "document"){ | ||
return document | ||
} else if(target){ | ||
return document.getElementById(target) | ||
} else { | ||
return el | ||
} | ||
} | ||
} | ||
export default LiveSocket |
@@ -10,13 +10,16 @@ { | ||
"build": "webpack --mode production", | ||
"watch": "webpack --mode development --watch" | ||
"watch": "webpack --mode development --watch", | ||
"test": "jest", | ||
"test.coverage": "jest --coverage", | ||
"test.watch": "jest --watch" | ||
}, | ||
"dependencies": { | ||
"morphdom": "^2.3.3", | ||
"phoenix": "file:~/oss/phoenix", | ||
"morphdom": "2.5.5", | ||
"phoenix": "file:../deps/phoenix", | ||
"phoenix_html": "file:../deps/phoenix_html" | ||
}, | ||
"devDependencies": { | ||
"babel-core": "^6.26.0", | ||
"babel-loader": "^7.1.3", | ||
"babel-preset-env": "^1.6.1", | ||
"@babel/core": "^7.3.4", | ||
"@babel/preset-env": "^7.4.1", | ||
"babel-loader": "^8.0.5", | ||
"copy-webpack-plugin": "^4.5.0", | ||
@@ -26,7 +29,11 @@ "css-loader": "^0.28.10", | ||
"extract-text-webpack-plugin": "^4.0.0-beta.0", | ||
"jasmine": "^3.3.1", | ||
"jest": "^24.5.0", | ||
"style-loader": "^0.20.2", | ||
"wait-for-expect": "^1.1.0", | ||
"webpack": "4.0.0", | ||
"webpack-cli": "^2.0.10" | ||
}, | ||
"jest": { | ||
"testRegex": "/test/.*_test\\.js$" | ||
} | ||
} |
{ | ||
"name": "phoenix_live_view", | ||
"version": "0.1.0-dev", | ||
"description": "The JavaScript client for the Phoenix LiveView", | ||
"version": "0.1.0", | ||
"description": "The Phoenix LiveView JavaScript client.", | ||
"license": "MIT", | ||
@@ -6,0 +6,0 @@ "main": "./priv/static/phoenix_live_view.js", |
@@ -1,1 +0,1 @@ | ||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.phoenix_live_view=t():e.phoenix_live_view=t()}(this,function(){return function(e){var t={};function n(i){if(t[i])return t[i].exports;var o=t[i]={i:i,l:!1,exports:{}};return e[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:i})},n.r=function(e){Object.defineProperty(e,"__esModule",{value:!0})},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=4)}([function(e,t,n){"use strict";var i,o="http://www.w3.org/1999/xhtml",r="undefined"==typeof document?void 0:document,s=r?r.body||r.createElement("div"):{},u=s.hasAttributeNS?function(e,t,n){return e.hasAttributeNS(t,n)}:s.hasAttribute?function(e,t,n){return e.hasAttribute(n)}:function(e,t,n){return null!=e.getAttributeNode(t,n)};function a(e,t){var n=e.nodeName,i=t.nodeName;return n===i||!!(t.actualize&&n.charCodeAt(0)<91&&i.charCodeAt(0)>90)&&n===i.toUpperCase()}function c(e,t,n){e[n]!==t[n]&&(e[n]=t[n],e[n]?e.setAttribute(n,""):e.removeAttribute(n,""))}var l={OPTION:function(e,t){c(e,t,"selected")},INPUT:function(e,t){c(e,t,"checked"),c(e,t,"disabled"),e.value!==t.value&&(e.value=t.value),u(t,null,"value")||e.removeAttribute("value")},TEXTAREA:function(e,t){var n=t.value;e.value!==n&&(e.value=n);var i=e.firstChild;if(i){var o=i.nodeValue;if(o==n||!n&&o==e.placeholder)return;i.nodeValue=n}},SELECT:function(e,t){if(!u(t,null,"multiple")){for(var n=0,i=t.firstChild;i;){var o=i.nodeName;if(o&&"OPTION"===o.toUpperCase()){if(u(i,null,"selected")){n;break}n++}i=i.nextSibling}e.selectedIndex=n}}},h=1,f=3,d=8;function v(){}function p(e){return e.id}var y=function(e){return function(t,n,s){if(s||(s={}),"string"==typeof n)if("#document"===t.nodeName||"HTML"===t.nodeName){var u=n;(n=r.createElement("html")).innerHTML=u}else c=n,!i&&r.createRange&&(i=r.createRange()).selectNode(r.body),i&&i.createContextualFragment?y=i.createContextualFragment(c):(y=r.createElement("body")).innerHTML=c,n=y.childNodes[0];var c,y,m,g=s.getNodeKey||p,b=s.onBeforeNodeAdded||v,k=s.onNodeAdded||v,w=s.onBeforeElUpdated||v,E=s.onElUpdated||v,x=s.onBeforeNodeDiscarded||v,A=s.onNodeDiscarded||v,C=s.onBeforeElChildrenUpdated||v,S=!0===s.childrenOnly,j={};function R(e){m?m.push(e):m=[e]}function T(e,t,n){!1!==x(e)&&(t&&t.removeChild(e),A(e),function e(t,n){if(t.nodeType===h)for(var i=t.firstChild;i;){var o=void 0;n&&(o=g(i))?R(o):(A(i),i.firstChild&&e(i,n)),i=i.nextSibling}}(e,n))}function O(e){k(e);for(var t=e.firstChild;t;){var n=t.nextSibling,i=g(t);if(i){var o=j[i];o&&a(t,o)&&(t.parentNode.replaceChild(o,t),N(o,t))}O(t),t=n}}function N(i,o,s){var u,c=g(o);if(c&&delete j[c],!n.isSameNode||!n.isSameNode(t)){if(!s){if(!1===w(i,o))return;if(e(i,o),E(i),!1===C(i,o))return}if("TEXTAREA"!==i.nodeName){var v,p,y,m,k=o.firstChild,x=i.firstChild;e:for(;k;){for(y=k.nextSibling,v=g(k);x;){if(p=x.nextSibling,k.isSameNode&&k.isSameNode(x)){k=y,x=p;continue e}u=g(x);var A=x.nodeType,S=void 0;if(A===k.nodeType&&(A===h?(v?v!==u&&((m=j[v])?x.nextSibling===m?S=!1:(i.insertBefore(m,x),p=x.nextSibling,u?R(u):T(x,i,!0),x=m):S=!1):u&&(S=!1),(S=!1!==S&&a(x,k))&&N(x,k)):A!==f&&A!=d||(S=!0,x.nodeValue!==k.nodeValue&&(x.nodeValue=k.nodeValue))),S){k=y,x=p;continue e}u?R(u):T(x,i,!0),x=p}if(v&&(m=j[v])&&a(m,k))i.appendChild(m),N(m,k);else{var L=b(k);!1!==L&&(L&&(k=L),k.actualize&&(k=k.actualize(i.ownerDocument||r)),i.appendChild(k),O(k))}k=y,x=p}for(;x;)p=x.nextSibling,(u=g(x))?R(u):T(x,i,!0),x=p}var P=l[i.nodeName];P&&P(i,o)}}!function e(t){if(t.nodeType===h)for(var n=t.firstChild;n;){var i=g(n);i&&(j[i]=n),e(n),n=n.nextSibling}}(t);var L,P,I=t,_=I.nodeType,B=n.nodeType;if(!S)if(_===h)B===h?a(t,n)||(A(t),I=function(e,t){for(var n=e.firstChild;n;){var i=n.nextSibling;t.appendChild(n),n=i}return t}(t,(L=n.nodeName,(P=n.namespaceURI)&&P!==o?r.createElementNS(P,L):r.createElement(L)))):I=n;else if(_===f||_===d){if(B===_)return I.nodeValue!==n.nodeValue&&(I.nodeValue=n.nodeValue),I;I=n}if(I===n)A(t);else if(N(I,n,S),m)for(var M=0,U=m.length;M<U;M++){var J=j[m[M]];J&&T(J,J.parentNode,!1)}return!S&&I!==t&&t.parentNode&&(I.actualize&&(I=I.actualize(t.ownerDocument||r)),t.parentNode.replaceChild(I,t)),I}}(function(e,t){var n,i,o,r,s,a=t.attributes;for(n=a.length-1;n>=0;--n)o=(i=a[n]).name,r=i.namespaceURI,s=i.value,r?(o=i.localName||o,e.getAttributeNS(r,o)!==s&&e.setAttributeNS(r,o,s)):e.getAttribute(o)!==s&&e.setAttribute(o,s);for(n=(a=e.attributes).length-1;n>=0;--n)!1!==(i=a[n]).specified&&(o=i.name,(r=i.namespaceURI)?(o=i.localName||o,u(t,r,o)||e.removeAttributeNS(r,o)):u(t,null,o)||e.removeAttribute(o))});e.exports=y},function(e,t,n){e.exports=function(e){var t={};function n(i){if(t[i])return t[i].exports;var o=t[i]={i:i,l:!1,exports:{}};return e[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(i,o,function(t){return e[t]}.bind(null,o));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){(function(t){e.exports=t.Phoenix=n(2)}).call(this,n(1))},function(e,t){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){"use strict";function i(e){return(i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}function s(e,t,n){return t&&r(e.prototype,t),n&&r(e,n),e}n.r(t),n.d(t,"Channel",function(){return g}),n.d(t,"Socket",function(){return k}),n.d(t,"LongPoll",function(){return w}),n.d(t,"Ajax",function(){return E}),n.d(t,"Presence",function(){return x});var u="undefined"!=typeof self?self:null,a="undefined"!=typeof window?window:null,c=u||a||void 0,l={connecting:0,open:1,closing:2,closed:3},h=1e4,f={closed:"closed",errored:"errored",joined:"joined",joining:"joining",leaving:"leaving"},d={close:"phx_close",error:"phx_error",join:"phx_join",reply:"phx_reply",leave:"phx_leave"},v=[d.close,d.error,d.join,d.reply,d.leave],p={longpoll:"longpoll",websocket:"websocket"},y=function(e){return"function"==typeof e?e:function(){return e}},m=function(){function e(t,n,i,r){o(this,e),this.channel=t,this.event=n,this.payload=i||function(){return{}},this.receivedResp=null,this.timeout=r,this.timeoutTimer=null,this.recHooks=[],this.sent=!1}return s(e,[{key:"resend",value:function(e){this.timeout=e,this.reset(),this.send()}},{key:"send",value:function(){this.hasReceived("timeout")||(this.startTimeout(),this.sent=!0,this.channel.socket.push({topic:this.channel.topic,event:this.event,payload:this.payload(),ref:this.ref,join_ref:this.channel.joinRef()}))}},{key:"receive",value:function(e,t){return this.hasReceived(e)&&t(this.receivedResp.response),this.recHooks.push({status:e,callback:t}),this}},{key:"reset",value:function(){this.cancelRefEvent(),this.ref=null,this.refEvent=null,this.receivedResp=null,this.sent=!1}},{key:"matchReceive",value:function(e){var t=e.status,n=e.response;e.ref,this.recHooks.filter(function(e){return e.status===t}).forEach(function(e){return e.callback(n)})}},{key:"cancelRefEvent",value:function(){this.refEvent&&this.channel.off(this.refEvent)}},{key:"cancelTimeout",value:function(){clearTimeout(this.timeoutTimer),this.timeoutTimer=null}},{key:"startTimeout",value:function(){var e=this;this.timeoutTimer&&this.cancelTimeout(),this.ref=this.channel.socket.makeRef(),this.refEvent=this.channel.replyEventName(this.ref),this.channel.on(this.refEvent,function(t){e.cancelRefEvent(),e.cancelTimeout(),e.receivedResp=t,e.matchReceive(t)}),this.timeoutTimer=setTimeout(function(){e.trigger("timeout",{})},this.timeout)}},{key:"hasReceived",value:function(e){return this.receivedResp&&this.receivedResp.status===e}},{key:"trigger",value:function(e,t){this.channel.trigger(this.refEvent,{status:e,response:t})}}]),e}(),g=function(){function e(t,n,i){var r=this;o(this,e),this.state=f.closed,this.topic=t,this.params=y(n||{}),this.socket=i,this.bindings=[],this.bindingRef=0,this.timeout=this.socket.timeout,this.joinedOnce=!1,this.joinPush=new m(this,d.join,this.params,this.timeout),this.pushBuffer=[],this.rejoinTimer=new A(function(){return r.rejoinUntilConnected()},this.socket.reconnectAfterMs),this.joinPush.receive("ok",function(){r.state=f.joined,r.rejoinTimer.reset(),r.pushBuffer.forEach(function(e){return e.send()}),r.pushBuffer=[]}),this.onClose(function(){r.rejoinTimer.reset(),r.socket.hasLogger()&&r.socket.log("channel","close ".concat(r.topic," ").concat(r.joinRef())),r.state=f.closed,r.socket.remove(r)}),this.onError(function(e){r.isLeaving()||r.isClosed()||(r.socket.hasLogger()&&r.socket.log("channel","error ".concat(r.topic),e),r.state=f.errored,r.rejoinTimer.scheduleTimeout())}),this.joinPush.receive("timeout",function(){r.isJoining()&&(r.socket.hasLogger()&&r.socket.log("channel","timeout ".concat(r.topic," (").concat(r.joinRef(),")"),r.joinPush.timeout),new m(r,d.leave,y({}),r.timeout).send(),r.state=f.errored,r.joinPush.reset(),r.rejoinTimer.scheduleTimeout())}),this.on(d.reply,function(e,t){r.trigger(r.replyEventName(t),e)})}return s(e,[{key:"rejoinUntilConnected",value:function(){this.rejoinTimer.scheduleTimeout(),this.socket.isConnected()&&this.rejoin()}},{key:"join",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;if(this.joinedOnce)throw new Error("tried to join multiple times. 'join' can only be called a single time per channel instance");return this.joinedOnce=!0,this.rejoin(e),this.joinPush}},{key:"onClose",value:function(e){this.on(d.close,e)}},{key:"onError",value:function(e){return this.on(d.error,function(t){return e(t)})}},{key:"on",value:function(e,t){var n=this.bindingRef++;return this.bindings.push({event:e,ref:n,callback:t}),n}},{key:"off",value:function(e,t){this.bindings=this.bindings.filter(function(n){return!(n.event===e&&(void 0===t||t===n.ref))})}},{key:"canPush",value:function(){return this.socket.isConnected()&&this.isJoined()}},{key:"push",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:this.timeout;if(!this.joinedOnce)throw new Error("tried to push '".concat(e,"' to '").concat(this.topic,"' before joining. Use channel.join() before pushing events"));var i=new m(this,e,function(){return t},n);return this.canPush()?i.send():(i.startTimeout(),this.pushBuffer.push(i)),i}},{key:"leave",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;this.state=f.leaving;var n=function(){e.socket.hasLogger()&&e.socket.log("channel","leave ".concat(e.topic)),e.trigger(d.close,"leave")},i=new m(this,d.leave,y({}),t);return i.receive("ok",function(){return n()}).receive("timeout",function(){return n()}),i.send(),this.canPush()||i.trigger("ok",{}),i}},{key:"onMessage",value:function(e,t,n){return t}},{key:"isLifecycleEvent",value:function(e){return v.indexOf(e)>=0}},{key:"isMember",value:function(e,t,n,i){return!(this.topic!==e||i&&i!==this.joinRef()&&this.isLifecycleEvent(t)&&(this.socket.hasLogger()&&this.socket.log("channel","dropping outdated message",{topic:e,event:t,payload:n,joinRef:i}),1))}},{key:"joinRef",value:function(){return this.joinPush.ref}},{key:"sendJoin",value:function(e){this.state=f.joining,this.joinPush.resend(e)}},{key:"rejoin",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;this.isLeaving()||this.sendJoin(e)}},{key:"trigger",value:function(e,t,n,i){var o=this.onMessage(e,t,n,i);if(t&&!o)throw new Error("channel onMessage callbacks must return the payload, modified or unmodified");for(var r=0;r<this.bindings.length;r++){var s=this.bindings[r];s.event===e&&s.callback(o,n,i||this.joinRef())}}},{key:"replyEventName",value:function(e){return"chan_reply_".concat(e)}},{key:"isClosed",value:function(){return this.state===f.closed}},{key:"isErrored",value:function(){return this.state===f.errored}},{key:"isJoined",value:function(){return this.state===f.joined}},{key:"isJoining",value:function(){return this.state===f.joining}},{key:"isLeaving",value:function(){return this.state===f.leaving}}]),e}(),b={encode:function(e,t){var n=[e.join_ref,e.ref,e.topic,e.event,e.payload];return t(JSON.stringify(n))},decode:function(e,t){var n=function(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=[],i=!0,o=!1,r=void 0;try{for(var s,u=e[Symbol.iterator]();!(i=(s=u.next()).done)&&(n.push(s.value),!t||n.length!==t);i=!0);}catch(e){o=!0,r=e}finally{try{i||null==u.return||u.return()}finally{if(o)throw r}}return n}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}(JSON.parse(e),5);return t({join_ref:n[0],ref:n[1],topic:n[2],event:n[3],payload:n[4]})}},k=function(){function e(t){var n=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};o(this,e),this.stateChangeCallbacks={open:[],close:[],error:[],message:[]},this.channels=[],this.sendBuffer=[],this.ref=0,this.timeout=i.timeout||h,this.transport=i.transport||c.WebSocket||w,this.defaultEncoder=b.encode,this.defaultDecoder=b.decode,this.transport!==w?(this.encode=i.encode||this.defaultEncoder,this.decode=i.decode||this.defaultDecoder):(this.encode=this.defaultEncoder,this.decode=this.defaultDecoder),this.heartbeatIntervalMs=i.heartbeatIntervalMs||3e4,this.reconnectAfterMs=i.reconnectAfterMs||function(e){return[1e3,2e3,5e3,1e4][e-1]||1e4},this.logger=i.logger||null,this.longpollerTimeout=i.longpollerTimeout||2e4,this.params=y(i.params||{}),this.endPoint="".concat(t,"/").concat(p.websocket),this.heartbeatTimer=null,this.pendingHeartbeatRef=null,this.reconnectTimer=new A(function(){n.teardown(function(){return n.connect()})},this.reconnectAfterMs)}return s(e,[{key:"protocol",value:function(){return location.protocol.match(/^https/)?"wss":"ws"}},{key:"endPointURL",value:function(){var e=E.appendParams(E.appendParams(this.endPoint,this.params()),{vsn:"2.0.0"});return"/"!==e.charAt(0)?e:"/"===e.charAt(1)?"".concat(this.protocol(),":").concat(e):"".concat(this.protocol(),"://").concat(location.host).concat(e)}},{key:"disconnect",value:function(e,t,n){this.reconnectTimer.reset(),this.teardown(e,t,n)}},{key:"connect",value:function(e){var t=this;e&&(console&&console.log("passing params to connect is deprecated. Instead pass :params to the Socket constructor"),this.params=y(e)),this.conn||(this.conn=new this.transport(this.endPointURL()),this.conn.timeout=this.longpollerTimeout,this.conn.onopen=function(){return t.onConnOpen()},this.conn.onerror=function(e){return t.onConnError(e)},this.conn.onmessage=function(e){return t.onConnMessage(e)},this.conn.onclose=function(e){return t.onConnClose(e)})}},{key:"log",value:function(e,t,n){this.logger(e,t,n)}},{key:"hasLogger",value:function(){return null!==this.logger}},{key:"onOpen",value:function(e){this.stateChangeCallbacks.open.push(e)}},{key:"onClose",value:function(e){this.stateChangeCallbacks.close.push(e)}},{key:"onError",value:function(e){this.stateChangeCallbacks.error.push(e)}},{key:"onMessage",value:function(e){this.stateChangeCallbacks.message.push(e)}},{key:"onConnOpen",value:function(){this.hasLogger()&&this.log("transport","connected to ".concat(this.endPointURL())),this.flushSendBuffer(),this.reconnectTimer.reset(),this.resetHeartbeat(),this.stateChangeCallbacks.open.forEach(function(e){return e()})}},{key:"resetHeartbeat",value:function(){var e=this;this.conn.skipHeartbeat||(this.pendingHeartbeatRef=null,clearInterval(this.heartbeatTimer),this.heartbeatTimer=setInterval(function(){return e.sendHeartbeat()},this.heartbeatIntervalMs))}},{key:"teardown",value:function(e,t,n){this.conn&&(this.conn.onclose=function(){},t?this.conn.close(t,n||""):this.conn.close(),this.conn=null),e&&e()}},{key:"onConnClose",value:function(e){this.hasLogger()&&this.log("transport","close",e),this.triggerChanError(),clearInterval(this.heartbeatTimer),e&&1e3!==e.code&&this.reconnectTimer.scheduleTimeout(),this.stateChangeCallbacks.close.forEach(function(t){return t(e)})}},{key:"onConnError",value:function(e){this.hasLogger()&&this.log("transport",e),this.triggerChanError(),this.stateChangeCallbacks.error.forEach(function(t){return t(e)})}},{key:"triggerChanError",value:function(){this.channels.forEach(function(e){return e.trigger(d.error)})}},{key:"connectionState",value:function(){switch(this.conn&&this.conn.readyState){case l.connecting:return"connecting";case l.open:return"open";case l.closing:return"closing";default:return"closed"}}},{key:"isConnected",value:function(){return"open"===this.connectionState()}},{key:"remove",value:function(e){this.channels=this.channels.filter(function(t){return t.joinRef()!==e.joinRef()})}},{key:"channel",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=new g(e,t,this);return this.channels.push(n),n}},{key:"push",value:function(e){var t=this;if(this.hasLogger()){var n=e.topic,i=e.event,o=e.payload,r=e.ref,s=e.join_ref;this.log("push","".concat(n," ").concat(i," (").concat(s,", ").concat(r,")"),o)}this.isConnected()?this.encode(e,function(e){return t.conn.send(e)}):this.sendBuffer.push(function(){return t.encode(e,function(e){return t.conn.send(e)})})}},{key:"makeRef",value:function(){var e=this.ref+1;return e===this.ref?this.ref=0:this.ref=e,this.ref.toString()}},{key:"sendHeartbeat",value:function(){if(this.isConnected()){if(this.pendingHeartbeatRef)return this.pendingHeartbeatRef=null,this.hasLogger()&&this.log("transport","heartbeat timeout. Attempting to re-establish connection"),void this.conn.close(1e3,"hearbeat timeout");this.pendingHeartbeatRef=this.makeRef(),this.push({topic:"phoenix",event:"heartbeat",payload:{},ref:this.pendingHeartbeatRef})}}},{key:"flushSendBuffer",value:function(){this.isConnected()&&this.sendBuffer.length>0&&(this.sendBuffer.forEach(function(e){return e()}),this.sendBuffer=[])}},{key:"onConnMessage",value:function(e){var t=this;this.decode(e.data,function(e){var n=e.topic,i=e.event,o=e.payload,r=e.ref,s=e.join_ref;r&&r===t.pendingHeartbeatRef&&(t.pendingHeartbeatRef=null),t.hasLogger()&&t.log("receive","".concat(o.status||""," ").concat(n," ").concat(i," ").concat(r&&"("+r+")"||""),o);for(var u=0;u<t.channels.length;u++){var a=t.channels[u];a.isMember(n,i,o,s)&&a.trigger(i,o,r,s)}for(var c=0;c<t.stateChangeCallbacks.message.length;c++)t.stateChangeCallbacks.message[c](e)})}}]),e}(),w=function(){function e(t){o(this,e),this.endPoint=null,this.token=null,this.skipHeartbeat=!0,this.onopen=function(){},this.onerror=function(){},this.onmessage=function(){},this.onclose=function(){},this.pollEndpoint=this.normalizeEndpoint(t),this.readyState=l.connecting,this.poll()}return s(e,[{key:"normalizeEndpoint",value:function(e){return e.replace("ws://","http://").replace("wss://","https://").replace(new RegExp("(.*)/"+p.websocket),"$1/"+p.longpoll)}},{key:"endpointURL",value:function(){return E.appendParams(this.pollEndpoint,{token:this.token})}},{key:"closeAndRetry",value:function(){this.close(),this.readyState=l.connecting}},{key:"ontimeout",value:function(){this.onerror("timeout"),this.closeAndRetry()}},{key:"poll",value:function(){var e=this;this.readyState!==l.open&&this.readyState!==l.connecting||E.request("GET",this.endpointURL(),"application/json",null,this.timeout,this.ontimeout.bind(this),function(t){if(t){var n=t.status,i=t.token,o=t.messages;e.token=i}else n=0;switch(n){case 200:o.forEach(function(t){return e.onmessage({data:t})}),e.poll();break;case 204:e.poll();break;case 410:e.readyState=l.open,e.onopen(),e.poll();break;case 0:case 500:e.onerror(),e.closeAndRetry();break;default:throw new Error("unhandled poll status ".concat(n))}})}},{key:"send",value:function(e){var t=this;E.request("POST",this.endpointURL(),"application/json",e,this.timeout,this.onerror.bind(this,"timeout"),function(e){e&&200===e.status||(t.onerror(e&&e.status),t.closeAndRetry())})}},{key:"close",value:function(e,t){this.readyState=l.closed,this.onclose()}}]),e}(),E=function(){function e(){o(this,e)}return s(e,null,[{key:"request",value:function(e,t,n,i,o,r,s){if(c.XDomainRequest){var u=new XDomainRequest;this.xdomainRequest(u,e,t,i,o,r,s)}else{var a=c.XMLHttpRequest?new c.XMLHttpRequest:new ActiveXObject("Microsoft.XMLHTTP");this.xhrRequest(a,e,t,n,i,o,r,s)}}},{key:"xdomainRequest",value:function(e,t,n,i,o,r,s){var u=this;e.timeout=o,e.open(t,n),e.onload=function(){var t=u.parseJSON(e.responseText);s&&s(t)},r&&(e.ontimeout=r),e.onprogress=function(){},e.send(i)}},{key:"xhrRequest",value:function(e,t,n,i,o,r,s,u){var a=this;e.open(t,n,!0),e.timeout=r,e.setRequestHeader("Content-Type",i),e.onerror=function(){u&&u(null)},e.onreadystatechange=function(){if(e.readyState===a.states.complete&&u){var t=a.parseJSON(e.responseText);u(t)}},s&&(e.ontimeout=s),e.send(o)}},{key:"parseJSON",value:function(e){if(!e||""===e)return null;try{return JSON.parse(e)}catch(t){return console&&console.log("failed to parse JSON response",e),null}}},{key:"serialize",value:function(e,t){var n=[];for(var o in e)if(e.hasOwnProperty(o)){var r=t?"".concat(t,"[").concat(o,"]"):o,s=e[o];"object"===i(s)?n.push(this.serialize(s,r)):n.push(encodeURIComponent(r)+"="+encodeURIComponent(s))}return n.join("&")}},{key:"appendParams",value:function(e,t){if(0===Object.keys(t).length)return e;var n=e.match(/\?/)?"&":"?";return"".concat(e).concat(n).concat(this.serialize(t))}}]),e}();E.states={complete:4};var x=function(){function e(t){var n=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};o(this,e);var r=i.events||{state:"presence_state",diff:"presence_diff"};this.state={},this.pendingDiffs=[],this.channel=t,this.joinRef=null,this.caller={onJoin:function(){},onLeave:function(){},onSync:function(){}},this.channel.on(r.state,function(t){var i=n.caller,o=i.onJoin,r=i.onLeave,s=i.onSync;n.joinRef=n.channel.joinRef(),n.state=e.syncState(n.state,t,o,r),n.pendingDiffs.forEach(function(t){n.state=e.syncDiff(n.state,t,o,r)}),n.pendingDiffs=[],s()}),this.channel.on(r.diff,function(t){var i=n.caller,o=i.onJoin,r=i.onLeave,s=i.onSync;n.inPendingSyncState()?n.pendingDiffs.push(t):(n.state=e.syncDiff(n.state,t,o,r),s())})}return s(e,[{key:"onJoin",value:function(e){this.caller.onJoin=e}},{key:"onLeave",value:function(e){this.caller.onLeave=e}},{key:"onSync",value:function(e){this.caller.onSync=e}},{key:"list",value:function(t){return e.list(this.state,t)}},{key:"inPendingSyncState",value:function(){return!this.joinRef||this.joinRef!==this.channel.joinRef()}}],[{key:"syncState",value:function(e,t,n,i){var o=this,r=this.clone(e),s={},u={};return this.map(r,function(e,n){t[e]||(u[e]=n)}),this.map(t,function(e,t){var n=r[e];if(n){var i=t.metas.map(function(e){return e.phx_ref}),a=n.metas.map(function(e){return e.phx_ref}),c=t.metas.filter(function(e){return a.indexOf(e.phx_ref)<0}),l=n.metas.filter(function(e){return i.indexOf(e.phx_ref)<0});c.length>0&&(s[e]=t,s[e].metas=c),l.length>0&&(u[e]=o.clone(n),u[e].metas=l)}else s[e]=t}),this.syncDiff(r,{joins:s,leaves:u},n,i)}},{key:"syncDiff",value:function(e,t,n,i){var o=t.joins,r=t.leaves,s=this.clone(e);return n||(n=function(){}),i||(i=function(){}),this.map(o,function(e,t){var i=s[e];if(s[e]=t,i){var o,r=s[e].metas.map(function(e){return e.phx_ref}),u=i.metas.filter(function(e){return r.indexOf(e.phx_ref)<0});(o=s[e].metas).unshift.apply(o,function(e){return function(e){if(Array.isArray(e)){for(var t=0,n=new Array(e.length);t<e.length;t++)n[t]=e[t];return n}}(e)||function(e){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e))return Array.from(e)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance")}()}(u))}n(e,i,t)}),this.map(r,function(e,t){var n=s[e];if(n){var o=t.metas.map(function(e){return e.phx_ref});n.metas=n.metas.filter(function(e){return o.indexOf(e.phx_ref)<0}),i(e,n,t),0===n.metas.length&&delete s[e]}}),s}},{key:"list",value:function(e,t){return t||(t=function(e,t){return t}),this.map(e,function(e,n){return t(e,n)})}},{key:"map",value:function(e,t){return Object.getOwnPropertyNames(e).map(function(n){return t(n,e[n])})}},{key:"clone",value:function(e){return JSON.parse(JSON.stringify(e))}}]),e}(),A=function(){function e(t,n){o(this,e),this.callback=t,this.timerCalc=n,this.timer=null,this.tries=0}return s(e,[{key:"reset",value:function(){this.tries=0,clearTimeout(this.timer)}},{key:"scheduleTimeout",value:function(){var e=this;clearTimeout(this.timer),this.timer=setTimeout(function(){e.tries=e.tries+1,e.callback()},this.timerCalc(this.tries+1))}}]),e}()}])},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.LiveSocket=t.debug=void 0;var i,o=function(){return function(e,t){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return function(e,t){var n=[],i=!0,o=!1,r=void 0;try{for(var s,u=e[Symbol.iterator]();!(i=(s=u.next()).done)&&(n.push(s.value),!t||n.length!==t);i=!0);}catch(e){o=!0,r=e}finally{try{!i&&u.return&&u.return()}finally{if(o)throw r}}return n}(e,t);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),r=function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}(),s="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},u=n(1),a=n(0),c=(i=a)&&i.__esModule?i:{default:i};function l(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var h="data-phx-view",f="["+h+"]",d=["text","textarea","password"],v=100,p="phx-",y=(t.debug=function(e,t,n,i){console.log(e.id+" "+t+": "+n+" - ",i)},function(e){return"object"===(void 0===e?"undefined":s(e))&&!(e instanceof Array)}),m={mergeDiff:function(e,t){return this.isNewFingerprint(t)?t:(function e(t,n){for(var i in n){var o=n[i];y(o)&&t[i]?e(t[i],o):t[i]=o}}(e,t),e)},isNewFingerprint:function(e){return e.static},toString:function(e){var t={buffer:""};return this.toOutputBuffer(e,t),t.buffer},toOutputBuffer:function(e,t){if(e.dynamics)return this.comprehensionToBuffer(e,t);var n=e.static;t.buffer+=n[0];for(var i=1;i<n.length;i++)this.dynamicToBuffer(e[i-1],t),t.buffer+=n[i]},comprehensionToBuffer:function(e,t){for(var n=e.dynamics,i=e.static,o=0;o<n.length;o++){var r=n[o];t.buffer+=i[0];for(var s=1;s<i.length;s++)this.dynamicToBuffer(r[s-1],t),t.buffer+=i[s]}},dynamicToBuffer:function(e,t){y(e)?this.toOutputBuffer(e,t):t.buffer+=e}},g=t.LiveSocket=function(){function e(t){var n=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};l(this,e),this.unloaded=!1,window.addEventListener("beforeunload",function(e){n.unloaded=!0}),this.socket=this.buildSocket(t,i),this.socket.onOpen(function(){return n.unloaded=!1}),this.bindingPrefix=i.bindingPrefix||p,this.opts=i,this.views={},this.viewLogger=i.viewLogger,this.activeElement=null,this.prevActive=null}return r(e,[{key:"buildSocket",value:function(e,t){var n=this;return"string"!=typeof e?e:(t.reconnectAfterMs||(t.reconnectAfterMs=function(e){return n.unloaded?[50,100,250][e-1]||500:[1e3,2e3,5e3,1e4][e-1]||1e4}),new u.Socket(e,t))}},{key:"log",value:function(e,t,n){if(this.viewLogger){var i=n(),r=o(i,2),s=r[0],u=r[1];this.viewLogger(e,t,s,u)}}},{key:"connect",value:function(){var e=this;return["complete","loaded","interactive"].indexOf(document.readyState)>=0?this.joinRootViews():document.addEventListener("DOMContentLoaded",function(){e.joinRootViews()}),this.socket.connect()}},{key:"disconnect",value:function(){return this.socket.disconnect()}},{key:"channel",value:function(e,t){return this.socket.channel(e,t||{})}},{key:"joinRootViews",value:function(){var e=this;document.querySelectorAll(f+":not([data-phx-parent-id])").forEach(function(t){e.joinView(t)})}},{key:"joinView",value:function(e,t){var n=new w(e,this,t);this.views[n.id]=n,n.join()}},{key:"getViewById",value:function(e){return this.views[e]}},{key:"onViewError",value:function(e){this.dropActiveElement(e)}},{key:"destroyViewById",value:function(e){var t=this.views[e];t&&(delete this.views[t.id],t.destroy())}},{key:"getBindingPrefix",value:function(){return this.bindingPrefix}},{key:"setActiveElement",value:function(e){var t=this;if(this.activeElement!==e){this.activeElement=e;var n=function(){e===t.activeElement&&(t.activeElement=null),e.removeEventListener("mouseup",t),e.removeEventListener("touchend",t)};e.addEventListener("mouseup",n),e.addEventListener("touchend",n)}}},{key:"getActiveElement",value:function(){return document.activeElement===document.body&&this.activeElement||document.activeElement}},{key:"dropActiveElement",value:function(e){this.prevActive&&e.ownsElement(this.prevActive)&&(this.prevActive=null)}},{key:"restorePreviouslyActiveFocus",value:function(){this.prevActive&&this.prevActive!==document.body&&this.prevActive.focus()}},{key:"blurActiveElement",value:function(){this.prevActive=this.getActiveElement(),this.prevActive!==document.body&&this.prevActive.blur()}}]),e}(),b={setCookie:function(e,t){document.cookie=e+"="+t},getCookie:function(e){return document.cookie.replace(new RegExp("(?:(?:^|.*;s*)"+e+"s*=s*([^;]*).*$)|^.*$"),"$1")},redirect:function(e,t){t&&b.setCookie("__phoenix_flash__",t+"; max-age=60000; path=/"),window.location=e}},k={setInputsReadOnly:function(e){e.querySelectorAll("input").forEach(function(e){e.setAttribute("data-phx-readonly",e.readOnly),e.readOnly=!0})},restoreReadOnlyInputs:function(e){e.querySelectorAll("input").forEach(function(e){var t=e.getAttribute("data-phx-readonly");t&&(e.readOnly="true"==t,e.removeAttribute("data-phx-readonly"))})},discardError:function(e){var t=e.getAttribute&&e.getAttribute("data-phx-error-for");if(t){var n=document.getElementById(t);!t||n.getAttribute("data-phx-has-focused")||n.form.getAttribute("data-phx-has-submitted")||(e.style.display="none")}},isPhxChild:function(e){return e.getAttribute&&e.getAttribute("data-phx-parent-id")},patch:function(e,t,n,i){var o=e.liveSocket.getActiveElement(),r=null,s=null;k.isTextualInput(o)&&(r=o.selectionStart,s=o.selectionEnd),(0,c.default)(t,"<div>"+i+"</div>",{childrenOnly:!0,onBeforeNodeAdded:function(e){return k.discardError(e),e},onNodeAdded:function(t){if(k.isPhxChild(t)&&e.ownsElement(t))return e.onNewChildAdded(t),!0;e.maybeBindAddedNode(t)},onBeforeNodeDiscarded:function(t){if(k.isPhxChild(t))return e.liveSocket.destroyViewById(t.id),!0},onBeforeElUpdated:function(e,t){return k.isPhxChild(t)?(k.mergeAttrs(e,t),!1):(e.getAttribute&&e.getAttribute("data-phx-has-submitted")&&t.setAttribute("data-phx-has-submitted",!0),e.getAttribute&&e.getAttribute("data-phx-has-focused")&&t.setAttribute("data-phx-has-focused",!0),k.discardError(t),!k.isTextualInput(e)||e!==o||(k.mergeInputs(e,t),!1))}}),k.restoreFocus(o,r,s),document.dispatchEvent(new Event("phx:update"))},mergeAttrs:function(e,t){t.getAttributeNames().forEach(function(n){var i=t.getAttribute(n);e.setAttribute(n,i)})},mergeInputs:function(e,t){k.mergeAttrs(e,t),e.readOnly=t.readOnly},restoreFocus:function(e,t,n){k.isTextualInput(e)&&((""===e.value||e.readOnly)&&e.blur(),e.focus(),(e.setSelectionRange&&"text"===e.type||"textarea"===e.type)&&e.setSelectionRange(t,n))},isTextualInput:function(e){return d.indexOf(e.type)>=0}},w=function(){function e(t,n,i){var o=this;l(this,e),this.liveSocket=n,this.parent=i,this.newChildrenAdded=!1,this.gracefullyClosed=!1,this.el=t,this.prevKey=null,this.bindingPrefix=n.getBindingPrefix(),this.loader=this.el.nextElementSibling,this.id=this.el.id,this.view=this.el.getAttribute(h),this.hasBoundUI=!1,this.channel=this.liveSocket.channel("lv:"+this.id,function(){return{session:o.getSession()}}),this.loaderTimer=setTimeout(function(){return o.showLoader()},v),this.bindChannel()}return r(e,[{key:"getSession",value:function(){return this.el.getAttribute("data-phx-session")||this.parent.getSession()}},{key:"destroy",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:function(){};this.hasGracefullyClosed()?(this.log("destroyed",function(){return["the server view has gracefully closed"]}),e()):(this.log("destroyed",function(){return["the child has been removed from the parent"]}),this.channel.leave().receive("ok",e).receive("error",e).receive("timeout",e))}},{key:"hideLoader",value:function(){clearTimeout(this.loaderTimer),this.loader.style.display="none"}},{key:"showLoader",value:function(){clearTimeout(this.loaderTimer),this.el.classList="phx-disconnected",this.loader.style.display="block";var e=Math.floor(this.el.clientHeight/2);this.loader.style.top="-"+e+"px"}},{key:"log",value:function(e,t){this.liveSocket.log(this,e,t)}},{key:"onJoin",value:function(e){var t=e.rendered;this.log("join",function(){return["",JSON.stringify(t)]}),this.rendered=t,this.hideLoader(),this.el.classList="phx-connected",k.patch(this,this.el,this.id,m.toString(this.rendered)),this.hasBoundUI||this.bindUI(),this.hasBoundUI=!0,this.joinNewChildren()}},{key:"joinNewChildren",value:function(){var e=this,t=f+'[data-phx-parent-id="'+this.id+'"]';document.querySelectorAll(t).forEach(function(t){e.liveSocket.getViewById(t.id)||e.liveSocket.joinView(t,e)})}},{key:"update",value:function(e){if(t=e,0!==Object.keys(t).length){var t;this.log("update",function(){return["",JSON.stringify(e)]}),this.rendered=m.mergeDiff(this.rendered,e);var n=m.toString(this.rendered);this.newChildrenAdded=!1,k.patch(this,this.el,this.id,n),this.newChildrenAdded&&this.joinNewChildren()}}},{key:"onNewChildAdded",value:function(e){this.newChildrenAdded=!0}},{key:"bindChannel",value:function(){var e=this;this.channel.on("render",function(t){return e.update(t)}),this.channel.on("redirect",function(e){var t=e.to,n=e.flash;return b.redirect(t,n)}),this.channel.on("session",function(t){var n=t.token;return e.el.setAttribute("data-phx-session",n)}),this.channel.onError(function(t){return e.onError(t)}),this.channel.onClose(function(){return e.onGracefulClose()})}},{key:"onGracefulClose",value:function(){this.gracefullyClosed=!0,this.liveSocket.destroyViewById(this.id)}},{key:"hasGracefullyClosed",value:function(){return this.gracefullyClosed}},{key:"join",value:function(){var e=this;this.parent&&this.parent.channel.onError(function(){return e.channel.leave()}),this.channel.join().receive("ok",function(t){return e.onJoin(t)}).receive("error",function(t){return e.onJoinError(t)})}},{key:"onJoinError",value:function(e){this.displayError(),this.log("error",function(){return["unable to join",e]})}},{key:"onError",value:function(e){this.log("error",function(){return["view crashed",e]}),this.liveSocket.onViewError(this),document.activeElement.blur(),this.displayError()}},{key:"displayError",value:function(){this.showLoader(),this.el.classList="phx-disconnected phx-error"}},{key:"pushWithReply",value:function(e,t){var n=this,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){};this.channel.push(e,t,2e4).receive("ok",function(e){n.update(e),i()})}},{key:"pushClick",value:function(e,t,n){t.preventDefault();var i=e.getAttribute(this.binding("value"))||e.value||"";this.pushWithReply("event",{type:"click",event:n,id:e.id,value:i})}},{key:"pushKey",value:function(e,t,n,i){this.prevKey!==n.key&&(this.prevKey=n.key,this.pushWithReply("event",{type:"key"+t,event:i,id:n.target.id,value:e.value||n.key}))}},{key:"pushInput",value:function(e,t,n){this.pushWithReply("event",{type:"form",event:n,id:t.target.id,value:this.serializeForm(e.form)})}},{key:"pushFormSubmit",value:function(e,t,n,i){t&&(t.target.disabled=!0),this.pushWithReply("event",{type:"form",event:n,id:t&&t.target.id||null,value:this.serializeForm(e)},i)}},{key:"eachChild",value:function(e,t){var n=this;return this.el.querySelectorAll(e).forEach(function(e){n.ownsElement(e)&&t(e)})}},{key:"ownsElement",value:function(e){return e.getAttribute("data-phx-parent-id")===this.id||((t=e.closest(f))?t["id"]:null)===this.id;var t}},{key:"bindUI",value:function(){var e=this;this.bindForms(),this.eachChild("["+this.binding("click")+"]",function(t){return e.bindClick(t)}),this.eachChild("["+this.binding("keyup")+"]",function(t){return e.bindKey(t,"up")}),this.eachChild("["+this.binding("keydown")+"]",function(t){return e.bindKey(t,"down")}),this.eachChild("["+this.binding("keypress")+"]",function(t){return e.bindKey(t,"press")})}},{key:"bindClick",value:function(e){var t=this;this.bindOwnAddedNode(e,e,this.binding("click"),function(n){e.addEventListener("click",function(i){return t.pushClick(e,i,n)})})}},{key:"bindKey",value:function(e,t){var n=this,i="key"+t;this.bindOwnAddedNode(e,e,this.binding(i),function(o){n.target(e).addEventListener(i,function(i){n.pushKey(e,t,i,o)})})}},{key:"bindForms",value:function(){var e=this,t=this.binding("change");this.eachChild("form["+t+"] input",function(t){e.bindChange(t)}),this.eachChild("form["+t+"] select",function(t){e.bindChange(t)}),this.eachChild("form["+t+"] textarea",function(t){e.bindChange(t)});var n=this.binding("submit");this.eachChild("form["+n+"]",function(t){e.bindSubmit(t)})}},{key:"bindChange",value:function(e){var t=this;this.onInput(e,function(n,i){k.isTextualInput(e)?e.setAttribute("data-phx-has-focused",!0):t.liveSocket.setActiveElement(i.target),t.pushInput(e,i,n)})}},{key:"bindSubmit",value:function(e){var t=this;this.bindOwnAddedNode(e,e,this.binding("submit"),function(n){e.addEventListener("submit",function(i){i.preventDefault(),t.submitForm(e,n,i)}),t.scheduleSubmit(e,n)})}},{key:"submitForm",value:function(e,t,n){var i=this;e.setAttribute("data-phx-has-submitted","true"),k.setInputsReadOnly(e),this.liveSocket.blurActiveElement(this),this.pushFormSubmit(e,n,t,function(){k.restoreReadOnlyInputs(e),i.liveSocket.restorePreviouslyActiveFocus()})}},{key:"scheduleSubmit",value:function(e,t){var n=this,i=parseInt(e.getAttribute(this.binding("submit-every")));i&&this.el.contains(e)&&setTimeout(function(){n.submitForm(e,t),n.scheduleSubmit(e,t)},i)}},{key:"maybeBindAddedNode",value:function(e){e.getAttribute&&this.ownsElement(e)&&(this.bindClick(e),this.bindSubmit(e),this.bindChange(e),this.bindKey(e,"up"),this.bindKey(e,"down"),this.bindKey(e,"press"))}},{key:"binding",value:function(e){return""+this.bindingPrefix+e}},{key:"serializeForm",value:function(e){return new URLSearchParams(new FormData(e)).toString()}},{key:"bindOwnAddedNode",value:function(e,t,n,i){if(!t||t.getAttribute){var o=t.getAttribute(n);o&&!e.getAttribute("data-phx-bound")&&this.ownsElement(e)&&(e.setAttribute("data-phx-bound",!0),i(o))}}},{key:"onInput",value:function(e,t){e.form&&this.bindOwnAddedNode(e,e.form,this.binding("change"),function(n){var i="radio"===e.type?"change":"input";e.addEventListener(i,function(e){return t(n,e)})})}},{key:"target",value:function(e){var t=e.getAttribute(this.binding("target"));return"window"===t?window:"document"===t?document:t?document.getElementById(t):e}}]),e}();t.default=g},function(e,t){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){(function(t){t.Phoenix||(t.Phoenix={}),e.exports=t.Phoenix.LiveView=n(2)}).call(this,n(3))}])}); | ||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.phoenix_live_view=t():e.phoenix_live_view=t()}(this,function(){return function(e){var t={};function n(i){if(t[i])return t[i].exports;var o=t[i]={i:i,l:!1,exports:{}};return e[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:i})},n.r=function(e){Object.defineProperty(e,"__esModule",{value:!0})},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=4)}([function(e,t,n){(function(e){var n,i,o;function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}!function(s,a){"object"==r(t)&&"object"==r(e)?e.exports=a():(i=[],void 0===(o="function"==typeof(n=a)?n.apply(t,i):n)||(e.exports=o))}(0,function(){return function(e){var t={};function n(i){if(t[i])return t[i].exports;var o=t[i]={i:i,l:!1,exports:{}};return e[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==r(e)&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(i,o,function(t){return e[t]}.bind(null,o));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){(function(t){e.exports=t.Phoenix=n(2)}).call(this,n(1))},function(e,t){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(e){"object"==("undefined"==typeof window?"undefined":r(window))&&(n=window)}e.exports=n},function(e,t,n){"use strict";function i(e){return(i="function"==typeof Symbol&&"symbol"==r(Symbol.iterator)?function(e){return r(e)}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":r(e)})(e)}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function s(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}function a(e,t,n){return t&&s(e.prototype,t),n&&s(e,n),e}n.r(t),n.d(t,"Channel",function(){return k}),n.d(t,"Serializer",function(){return b}),n.d(t,"Socket",function(){return w}),n.d(t,"LongPoll",function(){return E}),n.d(t,"Ajax",function(){return x}),n.d(t,"Presence",function(){return S});var u="undefined"!=typeof self?self:null,c="undefined"!=typeof window?window:null,l=u||c||void 0,h={connecting:0,open:1,closing:2,closed:3},f=1e4,d={closed:"closed",errored:"errored",joined:"joined",joining:"joining",leaving:"leaving"},v={close:"phx_close",error:"phx_error",join:"phx_join",reply:"phx_reply",leave:"phx_leave"},p=[v.close,v.error,v.join,v.reply,v.leave],y={longpoll:"longpoll",websocket:"websocket"},g=function(e){return"function"==typeof e?e:function(){return e}},m=function(){function e(t,n,i,r){o(this,e),this.channel=t,this.event=n,this.payload=i||function(){return{}},this.receivedResp=null,this.timeout=r,this.timeoutTimer=null,this.recHooks=[],this.sent=!1}return a(e,[{key:"resend",value:function(e){this.timeout=e,this.reset(),this.send()}},{key:"send",value:function(){this.hasReceived("timeout")||(this.startTimeout(),this.sent=!0,this.channel.socket.push({topic:this.channel.topic,event:this.event,payload:this.payload(),ref:this.ref,join_ref:this.channel.joinRef()}))}},{key:"receive",value:function(e,t){return this.hasReceived(e)&&t(this.receivedResp.response),this.recHooks.push({status:e,callback:t}),this}},{key:"reset",value:function(){this.cancelRefEvent(),this.ref=null,this.refEvent=null,this.receivedResp=null,this.sent=!1}},{key:"matchReceive",value:function(e){var t=e.status,n=e.response;e.ref,this.recHooks.filter(function(e){return e.status===t}).forEach(function(e){return e.callback(n)})}},{key:"cancelRefEvent",value:function(){this.refEvent&&this.channel.off(this.refEvent)}},{key:"cancelTimeout",value:function(){clearTimeout(this.timeoutTimer),this.timeoutTimer=null}},{key:"startTimeout",value:function(){var e=this;this.timeoutTimer&&this.cancelTimeout(),this.ref=this.channel.socket.makeRef(),this.refEvent=this.channel.replyEventName(this.ref),this.channel.on(this.refEvent,function(t){e.cancelRefEvent(),e.cancelTimeout(),e.receivedResp=t,e.matchReceive(t)}),this.timeoutTimer=setTimeout(function(){e.trigger("timeout",{})},this.timeout)}},{key:"hasReceived",value:function(e){return this.receivedResp&&this.receivedResp.status===e}},{key:"trigger",value:function(e,t){this.channel.trigger(this.refEvent,{status:e,response:t})}}]),e}(),k=function(){function e(t,n,i){var r=this;o(this,e),this.state=d.closed,this.topic=t,this.params=g(n||{}),this.socket=i,this.bindings=[],this.bindingRef=0,this.timeout=this.socket.timeout,this.joinedOnce=!1,this.joinPush=new m(this,v.join,this.params,this.timeout),this.pushBuffer=[],this.rejoinTimer=new C(function(){r.socket.isConnected()&&r.rejoin()},this.socket.rejoinAfterMs),this.socket.onError(function(){return r.rejoinTimer.reset()}),this.socket.onOpen(function(){r.rejoinTimer.reset(),r.isErrored()&&r.rejoin()}),this.joinPush.receive("ok",function(){r.state=d.joined,r.rejoinTimer.reset(),r.pushBuffer.forEach(function(e){return e.send()}),r.pushBuffer=[]}),this.joinPush.receive("error",function(){r.state=d.errored,r.socket.isConnected()&&r.rejoinTimer.scheduleTimeout()}),this.onClose(function(){r.rejoinTimer.reset(),r.socket.hasLogger()&&r.socket.log("channel","close ".concat(r.topic," ").concat(r.joinRef())),r.state=d.closed,r.socket.remove(r)}),this.onError(function(e){r.socket.hasLogger()&&r.socket.log("channel","error ".concat(r.topic),e),r.isJoining()&&r.joinPush.reset(),r.state=d.errored,r.socket.isConnected()&&r.rejoinTimer.scheduleTimeout()}),this.joinPush.receive("timeout",function(){r.socket.hasLogger()&&r.socket.log("channel","timeout ".concat(r.topic," (").concat(r.joinRef(),")"),r.joinPush.timeout),new m(r,v.leave,g({}),r.timeout).send(),r.state=d.errored,r.joinPush.reset(),r.socket.isConnected()&&r.rejoinTimer.scheduleTimeout()}),this.on(v.reply,function(e,t){r.trigger(r.replyEventName(t),e)})}return a(e,[{key:"join",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;if(this.joinedOnce)throw new Error("tried to join multiple times. 'join' can only be called a single time per channel instance");return this.timeout=e,this.joinedOnce=!0,this.rejoin(),this.joinPush}},{key:"onClose",value:function(e){this.on(v.close,e)}},{key:"onError",value:function(e){return this.on(v.error,function(t){return e(t)})}},{key:"on",value:function(e,t){var n=this.bindingRef++;return this.bindings.push({event:e,ref:n,callback:t}),n}},{key:"off",value:function(e,t){this.bindings=this.bindings.filter(function(n){return!(n.event===e&&(void 0===t||t===n.ref))})}},{key:"canPush",value:function(){return this.socket.isConnected()&&this.isJoined()}},{key:"push",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:this.timeout;if(!this.joinedOnce)throw new Error("tried to push '".concat(e,"' to '").concat(this.topic,"' before joining. Use channel.join() before pushing events"));var i=new m(this,e,function(){return t},n);return this.canPush()?i.send():(i.startTimeout(),this.pushBuffer.push(i)),i}},{key:"leave",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;this.rejoinTimer.reset(),this.joinPush.cancelTimeout(),this.state=d.leaving;var n=function(){e.socket.hasLogger()&&e.socket.log("channel","leave ".concat(e.topic)),e.trigger(v.close,"leave")},i=new m(this,v.leave,g({}),t);return i.receive("ok",function(){return n()}).receive("timeout",function(){return n()}),i.send(),this.canPush()||i.trigger("ok",{}),i}},{key:"onMessage",value:function(e,t,n){return t}},{key:"isLifecycleEvent",value:function(e){return p.indexOf(e)>=0}},{key:"isMember",value:function(e,t,n,i){return!(this.topic!==e||i&&i!==this.joinRef()&&this.isLifecycleEvent(t)&&(this.socket.hasLogger()&&this.socket.log("channel","dropping outdated message",{topic:e,event:t,payload:n,joinRef:i}),1))}},{key:"joinRef",value:function(){return this.joinPush.ref}},{key:"sendJoin",value:function(e){this.state=d.joining,this.joinPush.resend(e)}},{key:"rejoin",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;this.isLeaving()||this.sendJoin(e)}},{key:"trigger",value:function(e,t,n,i){var o=this.onMessage(e,t,n,i);if(t&&!o)throw new Error("channel onMessage callbacks must return the payload, modified or unmodified");for(var r=0;r<this.bindings.length;r++){var s=this.bindings[r];s.event===e&&s.callback(o,n,i||this.joinRef())}}},{key:"replyEventName",value:function(e){return"chan_reply_".concat(e)}},{key:"isClosed",value:function(){return this.state===d.closed}},{key:"isErrored",value:function(){return this.state===d.errored}},{key:"isJoined",value:function(){return this.state===d.joined}},{key:"isJoining",value:function(){return this.state===d.joining}},{key:"isLeaving",value:function(){return this.state===d.leaving}}]),e}(),b={encode:function(e,t){var n=[e.join_ref,e.ref,e.topic,e.event,e.payload];return t(JSON.stringify(n))},decode:function(e,t){var n=function(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=[],i=!0,o=!1,r=void 0;try{for(var s,a=e[Symbol.iterator]();!(i=(s=a.next()).done)&&(n.push(s.value),!t||n.length!==t);i=!0);}catch(e){o=!0,r=e}finally{try{i||null==a.return||a.return()}finally{if(o)throw r}}return n}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}(JSON.parse(e),5);return t({join_ref:n[0],ref:n[1],topic:n[2],event:n[3],payload:n[4]})}},w=function(){function e(t){var n=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};o(this,e),this.stateChangeCallbacks={open:[],close:[],error:[],message:[]},this.channels=[],this.sendBuffer=[],this.ref=0,this.timeout=i.timeout||f,this.transport=i.transport||l.WebSocket||E,this.defaultEncoder=b.encode,this.defaultDecoder=b.decode,this.closeWasClean=!1,this.unloaded=!1,this.binaryType=i.binaryType||"arraybuffer",this.transport!==E?(this.encode=i.encode||this.defaultEncoder,this.decode=i.decode||this.defaultDecoder):(this.encode=this.defaultEncoder,this.decode=this.defaultDecoder),c&&c.addEventListener&&c.addEventListener("beforeunload",function(e){n.conn&&(n.unloaded=!0,n.abnormalClose("unloaded"))}),this.heartbeatIntervalMs=i.heartbeatIntervalMs||3e4,this.rejoinAfterMs=function(e){return i.rejoinAfterMs?i.rejoinAfterMs(e):[1e3,2e3,5e3][e-1]||1e4},this.reconnectAfterMs=function(e){return n.unloaded?100:i.reconnectAfterMs?i.reconnectAfterMs(e):[10,50,100,150,200,250,500,1e3,2e3][e-1]||5e3},this.logger=i.logger||null,this.longpollerTimeout=i.longpollerTimeout||2e4,this.params=g(i.params||{}),this.endPoint="".concat(t,"/").concat(y.websocket),this.heartbeatTimer=null,this.pendingHeartbeatRef=null,this.reconnectTimer=new C(function(){n.teardown(function(){return n.connect()})},this.reconnectAfterMs)}return a(e,[{key:"protocol",value:function(){return location.protocol.match(/^https/)?"wss":"ws"}},{key:"endPointURL",value:function(){var e=x.appendParams(x.appendParams(this.endPoint,this.params()),{vsn:"2.0.0"});return"/"!==e.charAt(0)?e:"/"===e.charAt(1)?"".concat(this.protocol(),":").concat(e):"".concat(this.protocol(),"://").concat(location.host).concat(e)}},{key:"disconnect",value:function(e,t,n){this.closeWasClean=!0,this.reconnectTimer.reset(),this.teardown(e,t,n)}},{key:"connect",value:function(e){var t=this;e&&(console&&console.log("passing params to connect is deprecated. Instead pass :params to the Socket constructor"),this.params=g(e)),this.conn||(this.closeWasClean=!1,this.conn=new this.transport(this.endPointURL()),this.conn.binaryType=this.binaryType,this.conn.timeout=this.longpollerTimeout,this.conn.onopen=function(){return t.onConnOpen()},this.conn.onerror=function(e){return t.onConnError(e)},this.conn.onmessage=function(e){return t.onConnMessage(e)},this.conn.onclose=function(e){return t.onConnClose(e)})}},{key:"log",value:function(e,t,n){this.logger(e,t,n)}},{key:"hasLogger",value:function(){return null!==this.logger}},{key:"onOpen",value:function(e){this.stateChangeCallbacks.open.push(e)}},{key:"onClose",value:function(e){this.stateChangeCallbacks.close.push(e)}},{key:"onError",value:function(e){this.stateChangeCallbacks.error.push(e)}},{key:"onMessage",value:function(e){this.stateChangeCallbacks.message.push(e)}},{key:"onConnOpen",value:function(){this.hasLogger()&&this.log("transport","connected to ".concat(this.endPointURL())),this.unloaded=!1,this.closeWasClean=!1,this.flushSendBuffer(),this.reconnectTimer.reset(),this.resetHeartbeat(),this.stateChangeCallbacks.open.forEach(function(e){return e()})}},{key:"resetHeartbeat",value:function(){var e=this;this.conn&&this.conn.skipHeartbeat||(this.pendingHeartbeatRef=null,clearInterval(this.heartbeatTimer),this.heartbeatTimer=setInterval(function(){return e.sendHeartbeat()},this.heartbeatIntervalMs))}},{key:"teardown",value:function(e,t,n){this.conn&&(this.conn.onclose=function(){},t?this.conn.close(t,n||""):this.conn.close(),this.conn=null),e&&e()}},{key:"onConnClose",value:function(e){this.hasLogger()&&this.log("transport","close",e),this.triggerChanError(),clearInterval(this.heartbeatTimer),this.closeWasClean||this.reconnectTimer.scheduleTimeout(),this.stateChangeCallbacks.close.forEach(function(t){return t(e)})}},{key:"onConnError",value:function(e){this.hasLogger()&&this.log("transport",e),this.triggerChanError(),this.stateChangeCallbacks.error.forEach(function(t){return t(e)})}},{key:"triggerChanError",value:function(){this.channels.forEach(function(e){e.isErrored()||e.isLeaving()||e.isClosed()||e.trigger(v.error)})}},{key:"connectionState",value:function(){switch(this.conn&&this.conn.readyState){case h.connecting:return"connecting";case h.open:return"open";case h.closing:return"closing";default:return"closed"}}},{key:"isConnected",value:function(){return"open"===this.connectionState()}},{key:"remove",value:function(e){this.channels=this.channels.filter(function(t){return t.joinRef()!==e.joinRef()})}},{key:"channel",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=new k(e,t,this);return this.channels.push(n),n}},{key:"push",value:function(e){var t=this;if(this.hasLogger()){var n=e.topic,i=e.event,o=e.payload,r=e.ref,s=e.join_ref;this.log("push","".concat(n," ").concat(i," (").concat(s,", ").concat(r,")"),o)}this.isConnected()?this.encode(e,function(e){return t.conn.send(e)}):this.sendBuffer.push(function(){return t.encode(e,function(e){return t.conn.send(e)})})}},{key:"makeRef",value:function(){var e=this.ref+1;return e===this.ref?this.ref=0:this.ref=e,this.ref.toString()}},{key:"sendHeartbeat",value:function(){if(this.isConnected()){if(this.pendingHeartbeatRef)return this.pendingHeartbeatRef=null,this.hasLogger()&&this.log("transport","heartbeat timeout. Attempting to re-establish connection"),void this.abnormalClose("heartbeat timeout");this.pendingHeartbeatRef=this.makeRef(),this.push({topic:"phoenix",event:"heartbeat",payload:{},ref:this.pendingHeartbeatRef})}}},{key:"abnormalClose",value:function(e){this.closeWasClean=!1,this.conn.close(1e3,e)}},{key:"flushSendBuffer",value:function(){this.isConnected()&&this.sendBuffer.length>0&&(this.sendBuffer.forEach(function(e){return e()}),this.sendBuffer=[])}},{key:"onConnMessage",value:function(e){var t=this;this.decode(e.data,function(e){var n=e.topic,i=e.event,o=e.payload,r=e.ref,s=e.join_ref;r&&r===t.pendingHeartbeatRef&&(t.pendingHeartbeatRef=null),t.hasLogger()&&t.log("receive","".concat(o.status||""," ").concat(n," ").concat(i," ").concat(r&&"("+r+")"||""),o);for(var a=0;a<t.channels.length;a++){var u=t.channels[a];u.isMember(n,i,o,s)&&u.trigger(i,o,r,s)}for(var c=0;c<t.stateChangeCallbacks.message.length;c++)t.stateChangeCallbacks.message[c](e)})}}]),e}(),E=function(){function e(t){o(this,e),this.endPoint=null,this.token=null,this.skipHeartbeat=!0,this.onopen=function(){},this.onerror=function(){},this.onmessage=function(){},this.onclose=function(){},this.pollEndpoint=this.normalizeEndpoint(t),this.readyState=h.connecting,this.poll()}return a(e,[{key:"normalizeEndpoint",value:function(e){return e.replace("ws://","http://").replace("wss://","https://").replace(new RegExp("(.*)/"+y.websocket),"$1/"+y.longpoll)}},{key:"endpointURL",value:function(){return x.appendParams(this.pollEndpoint,{token:this.token})}},{key:"closeAndRetry",value:function(){this.close(),this.readyState=h.connecting}},{key:"ontimeout",value:function(){this.onerror("timeout"),this.closeAndRetry()}},{key:"poll",value:function(){var e=this;this.readyState!==h.open&&this.readyState!==h.connecting||x.request("GET",this.endpointURL(),"application/json",null,this.timeout,this.ontimeout.bind(this),function(t){if(t){var n=t.status,i=t.token,o=t.messages;e.token=i}else n=0;switch(n){case 200:o.forEach(function(t){return e.onmessage({data:t})}),e.poll();break;case 204:e.poll();break;case 410:e.readyState=h.open,e.onopen(),e.poll();break;case 0:case 500:e.onerror(),e.closeAndRetry();break;default:throw new Error("unhandled poll status ".concat(n))}})}},{key:"send",value:function(e){var t=this;x.request("POST",this.endpointURL(),"application/json",e,this.timeout,this.onerror.bind(this,"timeout"),function(e){e&&200===e.status||(t.onerror(e&&e.status),t.closeAndRetry())})}},{key:"close",value:function(e,t){this.readyState=h.closed,this.onclose()}}]),e}(),x=function(){function e(){o(this,e)}return a(e,null,[{key:"request",value:function(e,t,n,i,o,r,s){if(l.XDomainRequest){var a=new XDomainRequest;this.xdomainRequest(a,e,t,i,o,r,s)}else{var u=l.XMLHttpRequest?new l.XMLHttpRequest:new ActiveXObject("Microsoft.XMLHTTP");this.xhrRequest(u,e,t,n,i,o,r,s)}}},{key:"xdomainRequest",value:function(e,t,n,i,o,r,s){var a=this;e.timeout=o,e.open(t,n),e.onload=function(){var t=a.parseJSON(e.responseText);s&&s(t)},r&&(e.ontimeout=r),e.onprogress=function(){},e.send(i)}},{key:"xhrRequest",value:function(e,t,n,i,o,r,s,a){var u=this;e.open(t,n,!0),e.timeout=r,e.setRequestHeader("Content-Type",i),e.onerror=function(){a&&a(null)},e.onreadystatechange=function(){if(e.readyState===u.states.complete&&a){var t=u.parseJSON(e.responseText);a(t)}},s&&(e.ontimeout=s),e.send(o)}},{key:"parseJSON",value:function(e){if(!e||""===e)return null;try{return JSON.parse(e)}catch(t){return console&&console.log("failed to parse JSON response",e),null}}},{key:"serialize",value:function(e,t){var n=[];for(var o in e)if(e.hasOwnProperty(o)){var r=t?"".concat(t,"[").concat(o,"]"):o,s=e[o];"object"===i(s)?n.push(this.serialize(s,r)):n.push(encodeURIComponent(r)+"="+encodeURIComponent(s))}return n.join("&")}},{key:"appendParams",value:function(e,t){if(0===Object.keys(t).length)return e;var n=e.match(/\?/)?"&":"?";return"".concat(e).concat(n).concat(this.serialize(t))}}]),e}();x.states={complete:4};var S=function(){function e(t){var n=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};o(this,e);var r=i.events||{state:"presence_state",diff:"presence_diff"};this.state={},this.pendingDiffs=[],this.channel=t,this.joinRef=null,this.caller={onJoin:function(){},onLeave:function(){},onSync:function(){}},this.channel.on(r.state,function(t){var i=n.caller,o=i.onJoin,r=i.onLeave,s=i.onSync;n.joinRef=n.channel.joinRef(),n.state=e.syncState(n.state,t,o,r),n.pendingDiffs.forEach(function(t){n.state=e.syncDiff(n.state,t,o,r)}),n.pendingDiffs=[],s()}),this.channel.on(r.diff,function(t){var i=n.caller,o=i.onJoin,r=i.onLeave,s=i.onSync;n.inPendingSyncState()?n.pendingDiffs.push(t):(n.state=e.syncDiff(n.state,t,o,r),s())})}return a(e,[{key:"onJoin",value:function(e){this.caller.onJoin=e}},{key:"onLeave",value:function(e){this.caller.onLeave=e}},{key:"onSync",value:function(e){this.caller.onSync=e}},{key:"list",value:function(t){return e.list(this.state,t)}},{key:"inPendingSyncState",value:function(){return!this.joinRef||this.joinRef!==this.channel.joinRef()}}],[{key:"syncState",value:function(e,t,n,i){var o=this,r=this.clone(e),s={},a={};return this.map(r,function(e,n){t[e]||(a[e]=n)}),this.map(t,function(e,t){var n=r[e];if(n){var i=t.metas.map(function(e){return e.phx_ref}),u=n.metas.map(function(e){return e.phx_ref}),c=t.metas.filter(function(e){return u.indexOf(e.phx_ref)<0}),l=n.metas.filter(function(e){return i.indexOf(e.phx_ref)<0});c.length>0&&(s[e]=t,s[e].metas=c),l.length>0&&(a[e]=o.clone(n),a[e].metas=l)}else s[e]=t}),this.syncDiff(r,{joins:s,leaves:a},n,i)}},{key:"syncDiff",value:function(e,t,n,i){var o=t.joins,r=t.leaves,s=this.clone(e);return n||(n=function(){}),i||(i=function(){}),this.map(o,function(e,t){var i=s[e];if(s[e]=t,i){var o,r=s[e].metas.map(function(e){return e.phx_ref}),a=i.metas.filter(function(e){return r.indexOf(e.phx_ref)<0});(o=s[e].metas).unshift.apply(o,function(e){return function(e){if(Array.isArray(e)){for(var t=0,n=new Array(e.length);t<e.length;t++)n[t]=e[t];return n}}(e)||function(e){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e))return Array.from(e)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance")}()}(a))}n(e,i,t)}),this.map(r,function(e,t){var n=s[e];if(n){var o=t.metas.map(function(e){return e.phx_ref});n.metas=n.metas.filter(function(e){return o.indexOf(e.phx_ref)<0}),i(e,n,t),0===n.metas.length&&delete s[e]}}),s}},{key:"list",value:function(e,t){return t||(t=function(e,t){return t}),this.map(e,function(e,n){return t(e,n)})}},{key:"map",value:function(e,t){return Object.getOwnPropertyNames(e).map(function(n){return t(n,e[n])})}},{key:"clone",value:function(e){return JSON.parse(JSON.stringify(e))}}]),e}(),C=function(){function e(t,n){o(this,e),this.callback=t,this.timerCalc=n,this.timer=null,this.tries=0}return a(e,[{key:"reset",value:function(){this.tries=0,clearTimeout(this.timer)}},{key:"scheduleTimeout",value:function(){var e=this;clearTimeout(this.timer),this.timer=setTimeout(function(){e.tries=e.tries+1,e.callback()},this.timerCalc(this.tries+1))}}]),e}()}])})}).call(this,n(2)(e))},function(e,t,n){"use strict";var i;n.r(t);var o="http://www.w3.org/1999/xhtml",r="undefined"==typeof document?void 0:document,s=!!r&&"content"in r.createElement("template"),a=!!r&&r.createRange&&"createContextualFragment"in r.createRange();function u(e){return s?function(e){var t=r.createElement("template");return t.innerHTML=e,t.content.childNodes[0]}(e):a?function(e){return i||(i=r.createRange()).selectNode(r.body),i.createContextualFragment(e).childNodes[0]}(e):function(e){var t=r.createElement("body");return t.innerHTML=e,t.childNodes[0]}(e)}function c(e,t){var n=e.nodeName,i=t.nodeName;return n===i||!!(t.actualize&&n.charCodeAt(0)<91&&i.charCodeAt(0)>90)&&n===i.toUpperCase()}function l(e,t,n){e[n]!==t[n]&&(e[n]=t[n],e[n]?e.setAttribute(n,""):e.removeAttribute(n))}var h={OPTION:function(e,t){var n=e.parentNode;if(n){var i=n.nodeName.toUpperCase();"OPTGROUP"===i&&(i=(n=n.parentNode)&&n.nodeName.toUpperCase()),"SELECT"!==i||n.hasAttribute("multiple")||(e.hasAttribute("selected")&&!t.selected&&(e.setAttribute("selected","selected"),e.removeAttribute("selected")),n.selectedIndex=-1)}l(e,t,"selected")},INPUT:function(e,t){l(e,t,"checked"),l(e,t,"disabled"),e.value!==t.value&&(e.value=t.value),t.hasAttribute("value")||e.removeAttribute("value")},TEXTAREA:function(e,t){var n=t.value;e.value!==n&&(e.value=n);var i=e.firstChild;if(i){var o=i.nodeValue;if(o==n||!n&&o==e.placeholder)return;i.nodeValue=n}},SELECT:function(e,t){if(!t.hasAttribute("multiple")){for(var n,i,o=-1,r=0,s=e.firstChild;s;)if("OPTGROUP"===(i=s.nodeName&&s.nodeName.toUpperCase()))s=(n=s).firstChild;else{if("OPTION"===i){if(s.hasAttribute("selected")){o=r;break}r++}!(s=s.nextSibling)&&n&&(s=n.nextSibling,n=null)}e.selectedIndex=o}}},f=1,d=11,v=3,p=8;function y(){}function g(e){return e.id}var m=function(e){return function(t,n,i){if(i||(i={}),"string"==typeof n)if("#document"===t.nodeName||"HTML"===t.nodeName){var s=n;(n=r.createElement("html")).innerHTML=s}else n=u(n);var a,l=i.getNodeKey||g,m=i.onBeforeNodeAdded||y,k=i.onNodeAdded||y,b=i.onBeforeElUpdated||y,w=i.onElUpdated||y,E=i.onBeforeNodeDiscarded||y,x=i.onNodeDiscarded||y,S=i.onBeforeElChildrenUpdated||y,C=!0===i.childrenOnly,A={};function j(e){a?a.push(e):a=[e]}function T(e,t,n){!1!==E(e)&&(t&&t.removeChild(e),x(e),function e(t,n){if(t.nodeType===f)for(var i=t.firstChild;i;){var o=void 0;n&&(o=l(i))?j(o):(x(i),i.firstChild&&e(i,n)),i=i.nextSibling}}(e,n))}function L(e){k(e);for(var t=e.firstChild;t;){var n=t.nextSibling,i=l(t);if(i){var o=A[i];o&&c(t,o)&&(t.parentNode.replaceChild(o,t),R(o,t))}L(t),t=n}}function R(i,o,s){var a=l(o);if(a&&delete A[a],!n.isSameNode||!n.isSameNode(t)){if(!s){if(!1===b(i,o))return;if(e(i,o),w(i),!1===S(i,o))return}"TEXTAREA"!==i.nodeName?function(e,t){var n,i,o,s,a,u=t.firstChild,d=e.firstChild;e:for(;u;){for(s=u.nextSibling,n=l(u);d;){if(o=d.nextSibling,u.isSameNode&&u.isSameNode(d)){u=s,d=o;continue e}i=l(d);var y=d.nodeType,g=void 0;if(y===u.nodeType&&(y===f?(n?n!==i&&((a=A[n])?o===a?g=!1:(e.insertBefore(a,d),i?j(i):T(d,e,!0),d=a):g=!1):i&&(g=!1),(g=!1!==g&&c(d,u))&&R(d,u)):y!==v&&y!=p||(g=!0,d.nodeValue!==u.nodeValue&&(d.nodeValue=u.nodeValue))),g){u=s,d=o;continue e}i?j(i):T(d,e,!0),d=o}if(n&&(a=A[n])&&c(a,u))e.appendChild(a),R(a,u);else{var k=m(u);!1!==k&&(k&&(u=k),u.actualize&&(u=u.actualize(e.ownerDocument||r)),e.appendChild(u),L(u))}u=s,d=o}!function(e,t,n){for(;t;){var i=t.nextSibling;(n=l(t))?j(n):T(t,e,!0),t=i}}(e,d,i);var b=h[e.nodeName];b&&b(e,t)}(i,o):h.TEXTAREA(i,o)}}!function e(t){if(t.nodeType===f||t.nodeType===d)for(var n=t.firstChild;n;){var i=l(n);i&&(A[i]=n),e(n),n=n.nextSibling}}(t);var _=t,P=_.nodeType,N=n.nodeType;if(!C)if(P===f)N===f?c(t,n)||(x(t),_=function(e,t){for(var n=e.firstChild;n;){var i=n.nextSibling;t.appendChild(n),n=i}return t}(t,function(e,t){return t&&t!==o?r.createElementNS(t,e):r.createElement(e)}(n.nodeName,n.namespaceURI))):_=n;else if(P===v||P===p){if(N===P)return _.nodeValue!==n.nodeValue&&(_.nodeValue=n.nodeValue),_;_=n}if(_===n)x(t);else if(R(_,n,C),a)for(var O=0,H=a.length;O<H;O++){var I=A[a[O]];I&&T(I,I.parentNode,!1)}return!C&&_!==t&&t.parentNode&&(_.actualize&&(_=_.actualize(t.ownerDocument||r)),t.parentNode.replaceChild(_,t)),_}}(function(e,t){var n,i,o,r,s,a=t.attributes;for(n=a.length-1;n>=0;--n)o=(i=a[n]).name,r=i.namespaceURI,s=i.value,r?(o=i.localName||o,e.getAttributeNS(r,o)!==s&&e.setAttributeNS(r,o,s)):e.getAttribute(o)!==s&&e.setAttribute(o,s);for(n=(a=e.attributes).length-1;n>=0;--n)!1!==(i=a[n]).specified&&(o=i.name,(r=i.namespaceURI)?(o=i.localName||o,t.hasAttributeNS(r,o)||e.removeAttributeNS(r,o)):t.hasAttribute(o)||e.removeAttribute(o))}),k=n(0);function b(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function w(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}function E(e,t,n){return t&&w(e.prototype,t),n&&w(e,n),e}function x(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=[],i=!0,o=!1,r=void 0;try{for(var s,a=e[Symbol.iterator]();!(i=(s=a.next()).done)&&(n.push(s.value),!t||n.length!==t);i=!0);}catch(e){o=!0,r=e}finally{try{i||null==a.return||a.return()}finally{if(o)throw r}}return n}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}function S(e){return(S="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}n.d(t,"debug",function(){return R}),n.d(t,"Rendered",function(){return M}),n.d(t,"LiveSocket",function(){return D}),n.d(t,"Browser",function(){return V}),n.d(t,"View",function(){return J});var C="data-phx-view",A="[".concat(C,"]"),j=["text","textarea","number","email","password","search","tel","url"],T=1,L="phx-",R=function(e,t,n,i){console.log("".concat(e.id," ").concat(t,": ").concat(n," - "),i)},_=function(e){return"function"==typeof e?e:function(){return e}},P=function(e){return JSON.parse(JSON.stringify(e))},N=function(e,t){do{if(e.matches("[".concat(t,"]")))return e;e=e.parentElement||e.parentNode}while(null!==e&&1===e.nodeType&&!e.matches(A));return null},O=function(e){return null!==e&&"object"===S(e)&&!(e instanceof Array)},H=function(e,t){return e?e[t]:null},I=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=new FormData(e),i=new URLSearchParams,o=!0,r=!1,s=void 0;try{for(var a,u=n.entries()[Symbol.iterator]();!(o=(a=u.next()).done);o=!0){var c=x(a.value,2),l=c[0],h=c[1];i.append(l,h)}}catch(e){r=!0,s=e}finally{try{o||null==u.return||u.return()}finally{if(r)throw s}}for(var f in t)i.append(f,t[f]);return i.toString()},B={get:function(e){return e.getAttribute("data-phx-session")},isEqual:function(e,t){return this.get(e)===this.get(t)}},M={mergeDiff:function(e,t){return this.isNewFingerprint(t)?t:(function e(t,n){for(var i in n){var o=n[i],r=t[i];O(o)&&O(r)?(r.dynamics&&!o.dynamics&&delete r.dynamics,e(r,o)):t[i]=o}}(e,t),e)},isNewFingerprint:function(){return!!(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}).static},toString:function(e){var t={buffer:""};return this.toOutputBuffer(e,t),t.buffer},toOutputBuffer:function(e,t){if(e.dynamics)return this.comprehensionToBuffer(e,t);var n=e.static;t.buffer+=n[0];for(var i=1;i<n.length;i++)this.dynamicToBuffer(e[i-1],t),t.buffer+=n[i]},comprehensionToBuffer:function(e,t){for(var n=e.dynamics,i=e.static,o=0;o<n.length;o++){var r=n[o];t.buffer+=i[0];for(var s=1;s<i.length;s++)this.dynamicToBuffer(r[s-1],t),t.buffer+=i[s]}},dynamicToBuffer:function(e,t){O(e)?this.toOutputBuffer(e,t):t.buffer+=e}},D=function(){function e(t){var n=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};b(this,e),this.unloaded=!1,this.socket=new k.Socket(t,i),this.bindingPrefix=i.bindingPrefix||L,this.opts=i,this.views={},this.params=_(i.params||{}),this.viewLogger=i.viewLogger,this.activeElement=null,this.prevActive=null,this.prevInput=null,this.prevValue=null,this.silenced=!1,this.root=null,this.linkRef=0,this.href=window.location.href,this.pendingLink=null,this.currentLocation=P(window.location),this.hooks=i.hooks||{},this.socket.onOpen(function(){n.isUnloaded()&&(n.destroyAllViews(),n.joinRootViews()),n.unloaded=!1}),window.addEventListener("beforeunload",function(e){n.unloaded=!0}),this.bindTopLevelEvents()}return E(e,[{key:"getSocket",value:function(){return this.socket}},{key:"log",value:function(e,t,n){if(this.viewLogger){var i=x(n(),2),o=i[0],r=i[1];this.viewLogger(e,t,o,r)}}},{key:"connect",value:function(){var e=this;return["complete","loaded","interactive"].indexOf(document.readyState)>=0?this.joinRootViews():document.addEventListener("DOMContentLoaded",function(){e.joinRootViews()}),this.socket.connect()}},{key:"disconnect",value:function(){this.socket.disconnect()}},{key:"getHookCallbacks",value:function(e){return this.hooks[e]}},{key:"isUnloaded",value:function(){return this.unloaded}},{key:"getBindingPrefix",value:function(){return this.bindingPrefix}},{key:"binding",value:function(e){return"".concat(this.getBindingPrefix()).concat(e)}},{key:"channel",value:function(e,t){return this.socket.channel(e,t)}},{key:"joinRootViews",value:function(){var e=this;V.all(document,"".concat(A,":not([").concat("data-phx-parent-id","])"),function(t){var n=e.joinView(t,null,e.getHref());e.root=e.root||n})}},{key:"replaceRoot",value:function(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:this.setPendingLink(e);this.root.showLoader(T);var o=this.root.el,r=this.root.id,s=this.root.isLoading();V.fetchPage(e,function(a,u){if(200!==a)return V.redirect(e);var c=document.createElement("div");c.innerHTML=u,t.joinView(c.firstChild,null,e,function(e){t.commitPendingLink(i)?(n&&n(),t.destroyViewById(r),o.replaceWith(e.el),t.root=e,s&&t.root.showLoader()):e.destroy()})})}},{key:"joinView",value:function(e,t,n,i){if(!this.getViewById(e.id)){var o=new J(e,this,t,n);return this.views[o.id]=o,o.join(i),o}}},{key:"owner",value:function(e,t){var n=this.getViewById(H(e.closest(A),"id"));n&&t(n)}},{key:"getViewById",value:function(e){return this.views[e]}},{key:"onViewError",value:function(e){this.dropActiveElement(e)}},{key:"destroyAllViews",value:function(){for(var e in this.views)this.destroyViewById(e)}},{key:"destroyViewById",value:function(e){var t=this.views[e];t&&(delete this.views[t.id],this.root&&t.id===this.root.id&&(this.root=null),t.destroy())}},{key:"setActiveElement",value:function(e){var t=this;if(this.activeElement!==e){this.activeElement=e;var n=function(){e===t.activeElement&&(t.activeElement=null),e.removeEventListener("mouseup",t),e.removeEventListener("touchend",t)};e.addEventListener("mouseup",n),e.addEventListener("touchend",n)}}},{key:"getActiveElement",value:function(){return document.activeElement===document.body&&this.activeElement||document.activeElement}},{key:"dropActiveElement",value:function(e){this.prevActive&&e.ownsElement(this.prevActive)&&(this.prevActive=null)}},{key:"restorePreviouslyActiveFocus",value:function(){this.prevActive&&this.prevActive!==document.body&&this.prevActive.focus()}},{key:"blurActiveElement",value:function(){this.prevActive=this.getActiveElement(),this.prevActive!==document.body&&this.prevActive.blur()}},{key:"bindTopLevelEvents",value:function(){this.bindClicks(),this.bindNav(),this.bindForms(),this.bindTargetable({keyup:"keyup",keydown:"keydown"},function(e,t,n,i,o,r){n.pushKey(i,t,o,{altGraphKey:e.altGraphKey,altKey:e.altKey,charCode:e.charCode,code:e.code,ctrlKey:e.ctrlKey,key:e.key,keyCode:e.keyCode,keyIdentifier:e.keyIdentifier,keyLocation:e.keyLocation,location:e.location,metaKey:e.metaKey,repeat:e.repeat,shiftKey:e.shiftKey,which:e.which})}),this.bindTargetable({blur:"focusout",focus:"focusin"},function(e,t,n,i,o,r){r||n.pushEvent(t,i,o,{type:"focus"})}),this.bindTargetable({blur:"blur",focus:"focus"},function(e,t,n,i,o,r){r&&"window"!==!r&&n.pushEvent(t,i,o,{type:e.type})})}},{key:"setPendingLink",value:function(e){this.linkRef++;this.linkRef;return this.pendingLink=e,this.linkRef}},{key:"commitPendingLink",value:function(e){return this.linkRef===e&&(this.href=this.pendingLink,this.pendingLink=null,!0)}},{key:"getHref",value:function(){return this.href}},{key:"hasPendingLink",value:function(){return!!this.pendingLink}},{key:"bindTargetable",value:function(e,t){var n=this,i=function(i){var o=e[i];n.on(o,function(e){var o=n.binding(i),r=n.binding("target"),s=e.target.getAttribute&&e.target.getAttribute(o);s&&!e.target.getAttribute(r)?n.owner(e.target,function(n){return t(e,i,n,e.target,s,null)}):V.all(document,"[".concat(o,"][").concat(r,"=window]"),function(r){var s=r.getAttribute(o);n.owner(r,function(n){return t(e,i,n,r,s,"window")})})})};for(var o in e)i(o)}},{key:"bindClicks",value:function(){var e=this;window.addEventListener("click",function(t){var n=e.binding("click"),i=N(t.target,n),o=i&&i.getAttribute(n);if(o){t.preventDefault();var r={altKey:t.altKey,shiftKey:t.shiftKey,ctrlKey:t.ctrlKey,metaKey:t.metaKey,x:t.x||t.clientX,y:t.y||t.clientY,pageX:t.pageX,pageY:t.pageY,screenX:t.screenX,screenY:t.screenY};e.owner(i,function(e){return e.pushEvent("click",i,o,r)})}},!1)}},{key:"bindNav",value:function(){var e=this;V.canPushState()&&(window.onpopstate=function(t){if(e.registerNewLocation(window.location)){var n=window.location.href;e.root.isConnected()?e.root.pushInternalLink(n):e.replaceRoot(n)}},window.addEventListener("click",function(t){var n=N(t.target,"data-phx-live-link"),i=n&&n.getAttribute("data-phx-live-link");if(i){var o=n.href;t.preventDefault(),e.root.pushInternalLink(o,function(){V.pushState(i,{},o),e.registerNewLocation(window.location)})}},!1))}},{key:"registerNewLocation",value:function(e){var t=this.currentLocation;return t.pathname+t.search!==e.pathname+e.search&&(this.currentLocation=P(e),!0)}},{key:"bindForms",value:function(){var e=this;this.on("submit",function(t){var n=t.target.getAttribute(e.binding("submit"));n&&(t.preventDefault(),t.target.disabled=!0,e.owner(t.target,function(e){return e.submitForm(t.target,n)}))},!1);for(var t=["change","input"],n=0;n<t.length;n++){var i=t[n];this.on(i,function(t){var n=t.target,i="checkbox"===n.type?"checked":"value";if(e.prevInput!==n||e.prevValue!==n[i]){e.prevInput=n,e.prevValue=n[i];var o=n.form&&n.form.getAttribute(e.binding("change"));o&&e.owner(n,function(i){U.isTextualInput(n)?n["phx-has-focused"]=!0:e.setActiveElement(n),i.pushInput(n,o,t)})}},!1)}}},{key:"silenceEvents",value:function(e){this.silenced=!0,e(),this.silenced=!1}},{key:"on",value:function(e,t){var n=this;window.addEventListener(e,function(e){n.silenced||t(e)})}}]),e}(),V={all:function(e,t,n){e.querySelectorAll(t).forEach(n)},canPushState:function(){return void 0!==history.pushState},fetchPage:function(e,t){var n=new XMLHttpRequest;n.open("GET",e,!0),n.timeout=3e4,n.setRequestHeader("content-type","text/html"),n.setRequestHeader("cache-control","max-age=0, no-cache, no-store, must-revalidate, post-check=0, pre-check=0"),n.setRequestHeader("x-requested-with","live-link"),n.onerror=function(){return t(400)},n.ontimeout=function(){return t(504)},n.onreadystatechange=function(){if(4===n.readyState)return"live-link"!==n.getResponseHeader("x-requested-with")?t(400):200!==n.status?t(n.status):void t(200,n.responseText)},n.send()},pushState:function(e,t,n){this.canPushState()?n!==window.location.href&&history[e+"State"](t,"",n):this.redirect(n)},dispatchEvent:function(e,t){var n=null;"function"==typeof Event?n=new Event(t):(n=document.createEvent("Event")).initEvent(t,!0,!0),e.dispatchEvent(n)},setCookie:function(e,t){document.cookie="".concat(e,"=").concat(t)},getCookie:function(e){return document.cookie.replace(new RegExp("(?:(?:^|.*;s*)".concat(e,"s*=s*([^;]*).*$)|^.*$")),"$1")},redirect:function(e,t){t&&V.setCookie("__phoenix_flash__",t+"; max-age=60000; path=/"),window.location=e}},U={disableForm:function(e,t){var n="".concat(t).concat("disable-with");e.classList.add("phx-loading"),V.all(e,"[".concat(n,"]"),function(e){var t=e.getAttribute(n);e.setAttribute("".concat(n,"-restore"),e.innerText),e.innerText=t}),V.all(e,"button",function(e){e.setAttribute("data-phx-disabled",e.disabled),e.disabled=!0}),V.all(e,"input",function(e){e.setAttribute("data-phx-readonly",e.readOnly),e.readOnly=!0})},restoreDisabledForm:function(e,t){var n="".concat(t).concat("disable-with");e.classList.remove("phx-loading"),V.all(e,"[".concat(n,"]"),function(e){var t=e.getAttribute("".concat(n,"-restore"));t&&("INPUT"===e.nodeName?e.value=t:e.innerText=t,e.removeAttribute("".concat(n,"-restore")))}),V.all(e,"button",function(e){var t=e.getAttribute("data-phx-disabled");t&&(e.disabled="true"===t,e.removeAttribute("data-phx-disabled"))}),V.all(e,"input",function(e){var t=e.getAttribute("data-phx-readonly");t&&(e.readOnly="true"===t,e.removeAttribute("data-phx-readonly"))})},discardError:function(e){var t=e.getAttribute&&e.getAttribute("data-phx-error-for");if(t){var n=document.getElementById(t);!t||n["phx-has-focused"]||n.form["phx-has-submitted"]||(e.style.display="none")}},isPhxChild:function(e){return e.getAttribute&&e.getAttribute("data-phx-parent-id")},applyPhxUpdate:function(e,t,n){var i=t.getAttribute&&t.getAttribute(n);if(!i||"replace"===i)return!1;switch(U.mergeAttrs(e,t),i){case"ignore":break;case"append":e.innerHTML+=t.innerHTML;break;case"prepend":e.innerHTML=t.innerHTML+e.innerHTML;break;default:throw new Error('unsupported phx-update "'.concat(i,'"'))}return!0},patch:function(e,t,n,i){var o={added:[],updated:[],discarded:[]},r=e.liveSocket.getActiveElement(),s=null,a=null,u=e.liveSocket.binding("update"),c=t.tagName.toLowerCase();return U.isTextualInput(r)&&(s=r.selectionStart,a=r.selectionEnd),m(t,"<".concat(c,">").concat(i,"</").concat(c,">"),{childrenOnly:!0,onBeforeNodeAdded:function(e){return U.discardError(e),e},onNodeAdded:function(t){if(U.isPhxChild(t)&&e.ownsElement(t))return e.onNewChildAdded(),!0;o.added.push(t)},onBeforeNodeDiscarded:function(t){if(U.isPhxChild(t))return e.liveSocket.destroyViewById(t.id),!0;o.discarded.push(t)},onBeforeElUpdated:function(t,n){if(t.isEqualNode(n))return!1;if(U.applyPhxUpdate(t,n,u))return o.updated.push({fromEl:t,toEl:t}),!1;if(U.isPhxChild(n)){var i=t.getAttribute("data-phx-static");return B.isEqual(n,t)||(e.liveSocket.destroyViewById(t.id),e.onNewChildAdded()),U.mergeAttrs(t,n),t.setAttribute("data-phx-static",i),!1}return t.getAttribute&&t["phx-has-submitted"]&&(n["phx-has-submitted"]=!0),t["phx-has-focused"]&&(n["phx-has-focused"]=!0),U.discardError(n),U.isTextualInput(t)&&t===r?(U.mergeInputs(t,n),o.updated.push({fromEl:t,toEl:t}),!1):(o.updated.push({fromEl:t,toEl:n}),!0)}}),e.liveSocket.silenceEvents(function(){U.restoreFocus(r,s,a)}),V.dispatchEvent(document,"phx:update"),o},mergeAttrs:function(e,t){for(var n=t.attributes,i=0,o=n.length;i<o;i++){var r=n[i].name,s=t.getAttribute(r);e.setAttribute(r,s)}},mergeInputs:function(e,t){U.mergeAttrs(e,t),e.readOnly=t.readOnly},restoreFocus:function(e,t,n){U.isTextualInput(e)&&((""===e.value||e.readOnly)&&e.blur(),e.focus(),(e.setSelectionRange&&"text"===e.type||"textarea"===e.type)&&e.setSelectionRange(t,n))},isTextualInput:function(e){return j.indexOf(e.type)>=0}},J=function(){function e(t,n,i,o){var r=this;b(this,e),this.liveSocket=n,this.parent=i,this.newChildrenAdded=!1,this.gracefullyClosed=!1,this.el=t,this.id=this.el.id,this.view=this.el.getAttribute(C),this.loaderTimer=null,this.pendingDiffs=[],this.href=o,this.joinedOnce=!1,this.viewHooks={},this.channel=this.liveSocket.channel("lv:".concat(this.id),function(){return{url:r.href||r.liveSocket.root.href,params:r.liveSocket.params(r.view),session:r.getSession(),static:r.getStatic()}}),this.showLoader(T),this.bindChannel()}return E(e,[{key:"isConnected",value:function(){return this.channel.canPush()}},{key:"getSession",value:function(){return B.get(this.el)}},{key:"getStatic",value:function(){var e=this.el.getAttribute("data-phx-static");return""===e?null:e}},{key:"destroy",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:function(){};clearTimeout(this.loaderTimer);var n=function(){for(var n in t(),e.viewHooks)e.destroyHook(e.viewHooks[n])};this.hasGracefullyClosed()?(this.log("destroyed",function(){return["the server view has gracefully closed"]}),n()):(this.log("destroyed",function(){return["the child has been removed from the parent"]}),this.channel.leave().receive("ok",n).receive("error",n).receive("timeout",n))}},{key:"setContainerClasses",value:function(){var e;this.el.classList.remove("phx-connected","phx-disconnected","phx-error"),(e=this.el.classList).add.apply(e,arguments)}},{key:"isLoading",value:function(){return this.el.classList.contains("phx-disconnected")}},{key:"showLoader",value:function(e){var t=this;if(clearTimeout(this.loaderTimer),e)this.loaderTimer=setTimeout(function(){return t.showLoader()},e);else{for(var n in this.viewHooks)this.viewHooks[n].__trigger__("disconnected");this.setContainerClasses("phx-disconnected")}}},{key:"hideLoader",value:function(){for(var e in clearTimeout(this.loaderTimer),this.viewHooks)this.viewHooks[e].__trigger__("reconnected");this.setContainerClasses("phx-connected")}},{key:"log",value:function(e,t){this.liveSocket.log(this,e,t)}},{key:"onJoin",value:function(e){var t=e.rendered,n=e.live_redirect;this.log("join",function(){return["",JSON.stringify(t)]}),this.rendered=t,this.hideLoader();var i=U.patch(this,this.el,this.id,M.toString(this.rendered));if(i.added.push(this.el),V.all(this.el,"[".concat(this.binding("hook"),"]"),function(e){return i.added.push(e)}),this.triggerHooks(i),this.joinNewChildren(),n){var o=n.kind,r=n.to;V.pushState(o,{},r)}}},{key:"joinNewChildren",value:function(){var e=this;V.all(document,"".concat(A,"[").concat("data-phx-parent-id",'="').concat(this.id,'"]'),function(t){e.liveSocket.getViewById(t.id)||e.liveSocket.joinView(t,e)})}},{key:"update",value:function(e){if(!function(e){for(var t in e)return!1;return!0}(e)){if(this.liveSocket.hasPendingLink())return this.pendingDiffs.push(e);this.log("update",function(){return["",JSON.stringify(e)]}),this.rendered=M.mergeDiff(this.rendered,e);var t=M.toString(this.rendered);this.newChildrenAdded=!1,this.triggerHooks(U.patch(this,this.el,this.id,t)),this.newChildrenAdded&&this.joinNewChildren()}}},{key:"getHook",value:function(e){return this.viewHooks[F.elementID(e)]}},{key:"addHook",value:function(e){if(!F.elementID(e)&&e.getAttribute){var t=this.liveSocket.getHookCallbacks(e.getAttribute(this.binding("hook")));if(t&&this.ownsElement(e)){var n=new F(this,e,t);this.viewHooks[F.elementID(n.el)]=n,n.__trigger__("mounted")}}}},{key:"destroyHook",value:function(e){e.__trigger__("destroyed"),delete this.viewHooks[F.elementID(e.el)]}},{key:"triggerHooks",value:function(e){var t=this;e.updated.push({fromEl:this.el,toEl:this.el}),e.added.forEach(function(e){return t.addHook(e)}),e.updated.forEach(function(e){var n=e.fromEl,i=e.toEl,o=t.getHook(n),r=t.binding("hook");o&&i.getAttribute&&n.getAttribute(r)===i.getAttribute(r)?o.__trigger__("updated"):o&&(t.destroyHook(o),t.addHook(n))}),e.discarded.forEach(function(e){var n=t.getHook(e);n&&t.destroyHook(n)})}},{key:"applyPendingUpdates",value:function(){var e=this;this.pendingDiffs.forEach(function(t){return e.update(t)}),this.pendingDiffs=[]}},{key:"onNewChildAdded",value:function(){this.newChildrenAdded=!0}},{key:"bindChannel",value:function(){var e=this;this.channel.on("diff",function(t){return e.update(t)}),this.channel.on("redirect",function(t){var n=t.to,i=t.flash;return e.onRedirect({to:n,flash:i})}),this.channel.on("live_redirect",function(t){var n=t.to,i=t.kind;return e.onLiveRedirect({to:n,kind:i})}),this.channel.on("external_live_redirect",function(t){var n=t.to,i=t.kind;return e.onExternalLiveRedirect({to:n,kind:i})}),this.channel.on("session",function(t){var n=t.token;return e.el.setAttribute("data-phx-session",n)}),this.channel.onError(function(t){return e.onError(t)}),this.channel.onClose(function(){return e.onGracefulClose()})}},{key:"onGracefulClose",value:function(){this.gracefullyClosed=!0,this.liveSocket.destroyViewById(this.id)}},{key:"onExternalLiveRedirect",value:function(e){var t=e.to,n=e.kind;this.liveSocket.replaceRoot(t,function(){return V.pushState(n,{},t)})}},{key:"onLiveRedirect",value:function(e){var t=e.to,n=e.kind;V.pushState(n,{},t)}},{key:"onRedirect",value:function(e){var t=e.to,n=e.flash;V.redirect(t,n)}},{key:"hasGracefullyClosed",value:function(){return this.gracefullyClosed}},{key:"join",value:function(e){var t=this;this.parent&&(this.parent.channel.onClose(function(){return t.onGracefulClose()}),this.parent.channel.onError(function(){return t.liveSocket.destroyViewById(t.id)})),this.channel.join().receive("ok",function(n){t.joinedOnce||e&&e(t),t.joinedOnce=!0,t.onJoin(n)}).receive("error",function(e){return t.onJoinError(e)}).receive("timeout",function(){return t.onJoinError("timeout")})}},{key:"onJoinError",value:function(e){return e.redirect?this.onRedirect(e.redirect):e.external_live_redirect?this.onExternalLiveRedirect(e.external_live_redirect):(this.displayError(),void this.log("error",function(){return["unable to join",e]}))}},{key:"onError",value:function(e){this.log("error",function(){return["view crashed",e]}),this.liveSocket.onViewError(this),document.activeElement.blur(),this.liveSocket.isUnloaded()?this.showLoader(200):this.displayError()}},{key:"displayError",value:function(){this.showLoader(),this.setContainerClasses("phx-disconnected","phx-error")}},{key:"pushWithReply",value:function(e,t){var n=this,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){};return this.channel.push(e,t,3e4).receive("ok",function(e){e.diff&&n.update(e.diff),e.redirect&&n.onRedirect(e.redirect),e.live_redirect&&n.onLiveRedirect(e.live_redirect),e.external_live_redirect&&n.onExternalLiveRedirect(e.external_live_redirect),i(e)})}},{key:"pushEvent",value:function(e,t,n,i){var o=t.getAttribute(this.binding("value"));if(null===o){o=i;var r=this.binding("value-"),s=!0,a=!1,u=void 0;try{for(var c,l=t.getAttributeNames()[Symbol.iterator]();!(s=(c=l.next()).done);s=!0){var h=c.value;h.startsWith(r)&&(o[h.replace(r,"")]=t.getAttribute(h))}}catch(e){a=!0,u=e}finally{try{s||null==l.return||l.return()}finally{if(a)throw u}}void 0!==t.value&&(o.value=t.value)}this.pushWithReply("event",{type:e,event:n,value:o})}},{key:"pushKey",value:function(e,t,n,i){var o=e.getAttribute(this.binding("value"));null===o&&(o=i,void 0!==e.value&&(o.value=e.value)),this.pushWithReply("event",{type:t,event:n,value:o})}},{key:"pushInput",value:function(e,t,n){this.pushWithReply("event",{type:"form",event:t,value:I(e.form,{_target:n.target.name})})}},{key:"pushFormSubmit",value:function(e,t,n){this.pushWithReply("event",{type:"form",event:t,value:I(e)},n)}},{key:"pushInternalLink",value:function(e,t){var n=this;this.isLoading()||this.showLoader(T);var i=this.liveSocket.setPendingLink(e);this.pushWithReply("link",{url:e},function(o){o.link_redirect?n.liveSocket.replaceRoot(e,t,i):n.liveSocket.commitPendingLink(i)&&(n.href=e,n.applyPendingUpdates(),n.hideLoader(),t&&t())}).receive("timeout",function(){return V.redirect(window.location.href)})}},{key:"ownsElement",value:function(e){return e.getAttribute("data-phx-parent-id")===this.id||H(e.closest(A),"id")===this.id}},{key:"submitForm",value:function(e,t){var n=this,i=this.liveSocket.getBindingPrefix();e["phx-has-submitted"]="true",U.disableForm(e,i),this.liveSocket.blurActiveElement(this),this.pushFormSubmit(e,t,function(){U.restoreDisabledForm(e,i),n.liveSocket.restorePreviouslyActiveFocus()})}},{key:"binding",value:function(e){return this.liveSocket.binding(e)}}]),e}(),q=1,F=function(){function e(t,n,i){for(var o in b(this,e),this.__view=t,this.__callbacks=i,this.el=n,this.viewName=t.view,this.el.phxHookId=this.constructor.makeID(),this.__callbacks)this[o]=this.__callbacks[o]}return E(e,null,[{key:"makeID",value:function(){return q++}},{key:"elementID",value:function(e){return e.phxHookId}}]),E(e,[{key:"pushEvent",value:function(e,t){this.__view.pushWithReply("event",{type:"hook",event:e,value:t})}},{key:"__trigger__",value:function(e){var t=this.__callbacks[e];t&&t.call(this)}}]),e}();t.default=D},function(e,t){e.exports=function(e){return e.webpackPolyfill||(e.deprecate=function(){},e.paths=[],e.children||(e.children=[]),Object.defineProperty(e,"loaded",{enumerable:!0,get:function(){return e.l}}),Object.defineProperty(e,"id",{enumerable:!0,get:function(){return e.i}}),e.webpackPolyfill=1),e}},function(e,t){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){(function(t){t.Phoenix||(t.Phoenix={}),e.exports=t.Phoenix.LiveView=n(1)}).call(this,n(3))}])}); |
116
README.md
@@ -1,12 +0,21 @@ | ||
# Phoenix Live View | ||
# Phoenix LiveView | ||
[![Build Status](https://travis-ci.com/phoenixframework/phoenix_live_view.svg?token=Dc4VoVYF33Y2H4Gy8pGi&branch=master)](https://travis-ci.com/phoenixframework/phoenix_live_view) | ||
[![Build Status](https://travis-ci.org/phoenixframework/phoenix_live_view.svg?branch=master)](https://travis-ci.org/phoenixframework/phoenix_live_view) | ||
Phoenix LiveView enables rich, real-time user experiences with server-rendered HTML. For more information, [see the initial announcement](https://dockyard.com/blog/2018/12/12/phoenix-liveview-interactive-real-time-apps-no-need-to-write-javascript). | ||
**Note**: Currently Live View is under active development and we are focused on getting a stable and solid initial version out. For this reason, we will be accepting only bug reports in the issues tracker for now. We will open the issues tracker for features after the current milestone is ironed out. | ||
**Note**: Currently LiveView is under active development and we are focused on getting a stable and solid initial version out. For this reason, we will be accepting only bug reports in the issues tracker for now. We will open the issues tracker for features after the current milestone is ironed out. | ||
## Learning | ||
As official guides are being developed, see our existing | ||
comprehensive docs and examples to get up to speed: | ||
* [Phoenix.LiveView docs for Elixir and JavaScript usage](https://hexdocs.pm/phoenix_live_view) | ||
* [Phoenix.LiveViewTest for testing docs](https://github.com/phoenixframework/phoenix_live_view/blob/master/lib/phoenix_live_view/test/live_view_test.ex) | ||
* [LiveView example repo](https://github.com/chrismccord/phoenix_live_view_example) with a handful of examples from Weather widgets, autocomplete search, and games like Snake or Pacman | ||
## Installation | ||
Currently Live View is only avaialble from GitHub. To use it, add to your `mix.exs`: | ||
To use LiveView, add to your `mix.exs` and run `mix deps.get`: | ||
@@ -16,3 +25,3 @@ ```elixir | ||
[ | ||
{:phoenix_live_view, github: "phoenixframework/phoenix_live_view"} | ||
{:phoenix_live_view, "~> 0.1.0"} | ||
] | ||
@@ -25,2 +34,4 @@ end | ||
```elixir | ||
# config/config.exs | ||
config :my_app, MyAppWeb.Endpoint, | ||
@@ -32,12 +43,7 @@ live_view: [ | ||
Update your configuration to enable writing LiveView templates with the `.leex` extension. | ||
Next, add the LiveView flash plug to your browser pipeline, after `:fetch_flash`: | ||
```elixir | ||
config :phoenix, | ||
template_engines: [leex: Phoenix.LiveView.Engine] | ||
``` | ||
# lib/my_app_web/router.ex | ||
Next, add the Live View flash plug to your browser pipeline, after `:fetch_flash`: | ||
```elixir | ||
pipeline :browser do | ||
@@ -50,9 +56,18 @@ ... | ||
Then add the following imports to your web file in `lib/app_web.ex`: | ||
Then add the following imports to your web file in `lib/my_app_web.ex`: | ||
```elixir | ||
# lib/my_app_web.ex | ||
def controller do | ||
quote do | ||
... | ||
import Phoenix.LiveView.Controller, only: [live_render: 3] | ||
end | ||
end | ||
def view do | ||
quote do | ||
... | ||
import Phoenix.LiveView, only: [live_render: 2, live_render: 3] | ||
import Phoenix.LiveView, only: [live_render: 2, live_render: 3, live_link: 1, live_link: 2] | ||
end | ||
@@ -72,2 +87,4 @@ end | ||
```elixir | ||
# lib/my_app_web/endpoint.ex | ||
defmodule MyAppWeb.Endpoint do | ||
@@ -82,3 +99,3 @@ use Phoenix.Endpoint | ||
Add LiveView NPM dependencies in your package.json. | ||
Add LiveView NPM dependencies in your `assets/package.json`. | ||
@@ -88,3 +105,3 @@ ```json | ||
"dependencies": { | ||
"phoenix": "../deps/phoenix", | ||
"phoenix": "file:../deps/phoenix", | ||
"phoenix_html": "file:../deps/phoenix_html", | ||
@@ -96,9 +113,68 @@ "phoenix_live_view": "file:../deps/phoenix_live_view" | ||
Enable connecting to a LiveView socket in your app.js file. | ||
Then install the new npm dependency. | ||
```bash | ||
npm install --prefix assets | ||
``` | ||
If you had previously installed phoenix_live_view and want to get the | ||
latest javascript, then force an install. | ||
```bash | ||
(cd assets && npm install --force phoenix_live_view) | ||
``` | ||
Enable connecting to a LiveView socket in your `app.js` file. | ||
```javascript | ||
import LiveSocket from "phoenix_live_view"; | ||
// assets/js/app.js | ||
import LiveSocket from "phoenix_live_view" | ||
let liveSocket = new LiveSocket("/live"); | ||
liveSocket.connect(); | ||
let liveSocket = new LiveSocket("/live") | ||
liveSocket.connect() | ||
``` | ||
Finally, by convention live views are saved in a `lib/my_app_web/live/` | ||
directory. For live page reload support, add the following pattern to | ||
your `config/dev.exs`: | ||
```elixir | ||
# config/dev.exs | ||
config :demo, MyAppWeb.Endpoint, | ||
live_reload: [ | ||
patterns: [ | ||
..., | ||
~r{lib/my_app_web/live/.*(ex)$} | ||
] | ||
] | ||
``` | ||
You can also optionally import the style for the default CSS classes in your `app.css` file. | ||
```css | ||
/* assets/css/app.css */ | ||
@import "../../deps/phoenix_live_view/assets/css/live_view.css"; | ||
``` | ||
## Browser Support | ||
All current Chrome, Safari, Firefox, and MS Edge are supported. | ||
IE11 support is available with the following polyfills: | ||
```console | ||
$ npm install --save --prefix assets mdn-polyfills url-search-params-polyfill formdata-polyfill child-replace-with-polyfill classlist-polyfill | ||
``` | ||
```javascript | ||
// assets/js/app.js | ||
import "mdn-polyfills/NodeList.prototype.forEach" | ||
import "mdn-polyfills/Element.prototype.closest" | ||
import "mdn-polyfills/Element.prototype.matches" | ||
import "child-replace-with-polyfill" | ||
import "url-search-params-polyfill" | ||
import "formdata-polyfill" | ||
import "classlist-polyfill" | ||
import LiveSocket from "phoenix_live_view" | ||
... | ||
``` |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
91332
7
961
173
1