unpoly-rails 2.0.0 → 2.2.0

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

Potentially problematic release.


This version of unpoly-rails might be problematic. Click here for more details.

Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/README.md +472 -50
  4. data/{dist → assets/unpoly}/unpoly-bootstrap3.css +1 -0
  5. data/assets/unpoly/unpoly-bootstrap3.js +54 -0
  6. data/{dist → assets/unpoly}/unpoly-bootstrap3.min.css +1 -0
  7. data/assets/unpoly/unpoly-bootstrap3.min.js +1 -0
  8. data/{dist → assets/unpoly}/unpoly-bootstrap4.css +1 -0
  9. data/assets/unpoly/unpoly-bootstrap4.js +54 -0
  10. data/{dist → assets/unpoly}/unpoly-bootstrap4.min.css +1 -0
  11. data/assets/unpoly/unpoly-bootstrap4.min.js +1 -0
  12. data/{dist → assets/unpoly}/unpoly-bootstrap5.css +1 -0
  13. data/assets/unpoly/unpoly-bootstrap5.js +56 -0
  14. data/{dist → assets/unpoly}/unpoly-bootstrap5.min.css +1 -0
  15. data/assets/unpoly/unpoly-bootstrap5.min.js +1 -0
  16. data/assets/unpoly/unpoly-migrate.js +1281 -0
  17. data/assets/unpoly/unpoly-migrate.min.js +1 -0
  18. data/{dist → assets/unpoly}/unpoly.css +23 -6
  19. data/assets/unpoly/unpoly.es5.js +23195 -0
  20. data/assets/unpoly/unpoly.es5.min.js +1 -0
  21. data/assets/unpoly/unpoly.js +21457 -0
  22. data/assets/unpoly/unpoly.min.css +10 -0
  23. data/assets/unpoly/unpoly.min.js +1 -0
  24. data/lib/unpoly-rails.rb +12 -12
  25. data/lib/unpoly/rails/controller.rb +1 -1
  26. data/lib/unpoly/rails/engine.rb +13 -20
  27. data/lib/unpoly/rails/request_echo_headers.rb +1 -1
  28. data/lib/unpoly/rails/version.rb +1 -1
  29. metadata +52 -26
  30. data/CHANGELOG.md +0 -2345
  31. data/README_RAILS.md +0 -418
  32. data/dist/unpoly-bootstrap3.js +0 -16
  33. data/dist/unpoly-bootstrap3.min.js +0 -1
  34. data/dist/unpoly-bootstrap4.js +0 -16
  35. data/dist/unpoly-bootstrap4.min.js +0 -1
  36. data/dist/unpoly-bootstrap5.js +0 -14
  37. data/dist/unpoly-bootstrap5.min.js +0 -1
  38. data/dist/unpoly-migrate.js +0 -1306
  39. data/dist/unpoly-migrate.min.js +0 -1
  40. data/dist/unpoly.js +0 -22134
  41. data/dist/unpoly.min.css +0 -1
  42. data/dist/unpoly.min.js +0 -6
  43. data/lib/unpoly/tasks.rb +0 -55
@@ -0,0 +1,10 @@
1
+ up-wrapper{display:inline-block}
2
+
3
+ up-bounds{position:absolute}.up-focusable-content:focus,.up-focusable-content:focus-visible{outline:0}
4
+
5
+ .up-request-loader{display:none}up-progress-bar{position:fixed;top:0;left:0;z-index:999999999;height:3px;background-color:#007bff}
6
+
7
+ up-focus-trap{position:fixed;top:0;left:0;width:0;height:0}up-modal,up-drawer,up-cover,up-modal-backdrop,up-drawer-backdrop,up-modal-viewport,up-drawer-viewport,up-cover-viewport{top:0;left:0;bottom:0;right:0}up-modal-box,up-drawer-box{box-shadow:0 0 10px 1px rgba(0,0,0,0.3)}up-popup{box-shadow:0 0 4px rgba(0,0,0,0.3)}up-modal:focus,up-drawer:focus,up-cover:focus,up-modal-box:focus,up-drawer-box:focus,up-cover-box:focus,up-popup:focus,up-modal:focus-visible,up-drawer:focus-visible,up-cover:focus-visible,up-modal-box:focus-visible,up-drawer-box:focus-visible,up-cover-box:focus-visible,up-popup:focus-visible{outline:none}up-modal,up-drawer,up-cover{z-index:2000;position:fixed}up-modal-backdrop,up-drawer-backdrop{position:absolute;background:rgba(0,0,0,0.4)}up-modal-viewport,up-drawer-viewport,up-cover-viewport{position:absolute;overflow-y:scroll;overflow-x:hidden;overscroll-behavior:contain;text-align:center}up-modal-box,up-drawer-box,up-cover-box,up-popup{display:inline-block;text-align:left;position:relative;box-sizing:border-box;max-width:100%;background-color:#fff;padding:20px;overflow-x:hidden}up-modal-content,up-drawer-content,up-cover-content,up-popup-content{display:block}up-popup{z-index:1000}up-modal-dismiss,up-drawer-dismiss,up-cover-dismiss,up-popup-dismiss{color:#888;position:absolute;top:10px;right:10px;font-size:1.7rem;line-height:0.5}up-modal-viewport{justify-content:center}up-modal[nesting="0"] up-modal-viewport{padding:25px 15px}up-modal[nesting="1"] up-modal-viewport{padding:50px 30px}up-modal[nesting="2"] up-modal-viewport{padding:75px 45px}up-modal[nesting="3"] up-modal-viewport{padding:100px 60px}up-modal[nesting="4"] up-modal-viewport{padding:125px 75px}up-modal[size=small] up-modal-box{width:350px}up-modal[size=medium] up-modal-box{width:650px}up-modal[size=large] up-modal-box{width:1000px}up-modal[size=grow] up-modal-box{width:auto}up-modal[size=full] up-modal-box{width:100%}up-drawer-viewport{text-align:left}up-drawer[position=right] up-drawer-viewport{text-align:right}up-drawer-box{min-height:100vh}up-drawer[size=small] up-drawer-box{width:150px}up-drawer[size=medium] up-drawer-box{width:340px}up-drawer[size=large] up-drawer-box{width:600px}up-drawer[size=grow] up-drawer-box{width:auto}up-drawer[size=full] up-drawer-box{width:100%}up-cover-box{width:100%;min-height:100vh;padding:0}up-popup{padding:15px}up-popup[size=small]{width:180px}up-popup[size=medium]{width:300px}up-popup[size=large]{width:550px}up-popup[size=grow] up-popup{width:auto}up-popup[size=full] up-popup{width:100%}
8
+
9
+ a[up-content],a[up-fragment],a[up-document],[up-href],[up-clickable],[up-accept],[up-dismiss]{cursor:pointer}
10
+
@@ -0,0 +1 @@
1
+ (()=>{var t={8711:()=>{},4432:()=>{},2065:()=>{},35:()=>{},5074:()=>{},2811:()=>{up.browser=function(){const t=up.util;function e(){return"ActiveXObject"in window}function n(){return!!window.jQuery}function r(){return window.Promise?"BackCompat"===document.compatMode?"Browser is in quirks mode (missing DOCTYPE?)":void 0:"Browser doesn't support promises"}return{loadPage:function(t){new up.Request(t).loadPage()},submitForm:function(t){t.submit()},canPushState:function(){return history.pushState&&"GET"===up.protocol.initialRequestMethod()},canFormatLog:t.negate(e),canPassiveEventListener:t.negate(e),canJQuery:n,assertConfirmed:function(t){if(t.confirm&&!window.confirm(t.confirm))throw up.error.aborted("User canceled action");return!0},isSupported:function(){return!r()},supportIssue:r,popCookie:function(t){let e=document.cookie.match(new RegExp(t+"=(\\w+)"))?.[1];if(e)return document.cookie=t+"=;Max-Age=0;Path=/",e},get jQuery(){return n()||up.fail("jQuery must be published as window.jQuery"),jQuery},isIE11:e}}()},6346:()=>{const t=up.element;up.BodyShifter=class{constructor(){this.unshiftFns=[],this.reset()}reset(){this.unshiftNow(),this.shiftCount=0}shift(){if(this.shiftCount++,this.shiftCount>1)return;const e=up.viewport.rootHasReducedWidthFromScrollbar(),n=up.viewport.rootOverflowElement();if(this.changeStyle(n,{overflowY:"hidden"}),!e)return;const{body:r}=document,s=up.viewport.scrollbarWidth(),i=s+t.styleNumber(r,"paddingRight");this.changeStyle(r,{paddingRight:i});for(let e of up.viewport.anchoredRight()){const n=s+t.styleNumber(e,"right");this.changeStyle(e,{right:n})}}changeStyle(e,n){this.unshiftFns.push(t.setTemporaryStyle(e,n))}unshift(){this.shiftCount--,0==this.shiftCount&&this.unshiftNow()}unshiftNow(){let t;for(;t=this.unshiftFns.pop();)t()}}},3115:()=>{const t=up.util;up.Cache=class{constructor(t={}){this.config=t,this.store=this.config.store||new up.store.Memory}size(){return this.store.size()}maxSize(){return t.evalOption(this.config.size)}expiryMillis(){return t.evalOption(this.config.expiry)}normalizeStoreKey(t){return this.config.key?this.config.key(t):t.toString()}isEnabled(){return 0!==this.maxSize()&&0!==this.expiryMillis()}clear(){this.store.clear()}log(...t){this.config.logPrefix&&(t[0]=`[${this.config.logPrefix}] ${t[0]}`,up.puts("up.Cache",...t))}keys(){return this.store.keys()}each(e){t.each(this.keys(),(t=>{const n=this.store.get(t);e(t,n.value,n.timestamp)}))}makeRoomForAnotherEntry(){if(this.hasRoomForAnotherEntry())return;let t,e;this.each((function(n,r,s){(!e||e>s)&&(t=n,e=s)})),t&&this.store.remove(t)}hasRoomForAnotherEntry(){const t=this.maxSize();return!t||this.size()<t}alias(e,n){const r=this.get(e,{silent:!0});t.isDefined(r)&&this.set(n,r)}timestamp(){return(new Date).valueOf()}set(t,e){if(this.isEnabled()){this.makeRoomForAnotherEntry();const n=this.normalizeStoreKey(t),r={timestamp:this.timestamp(),value:e};this.store.set(n,r)}}remove(t){const e=this.normalizeStoreKey(t);this.store.remove(e)}isFresh(t){const e=this.expiryMillis();return!e||this.timestamp()-t.timestamp<e}get(t,e={}){const n=this.normalizeStoreKey(t);let r=this.store.get(n);if(r){if(this.isFresh(r))return e.silent||this.log("Cache hit for '%s'",t),r.value;e.silent||this.log("Discarding stale cache entry for '%s'",t),this.remove(t)}else e.silent||this.log("Cache miss for '%s'",t)}}},7948:()=>{const t=up.util,e=up.element;up.Change.Addition=class extends up.Change{constructor(t){super(t),this.responseDoc=t.responseDoc,this.acceptLayer=t.acceptLayer,this.dismissLayer=t.dismissLayer,this.eventPlans=t.eventPlans||[]}handleLayerChangeRequests(){this.layer.isOverlay()&&(this.tryAcceptLayerFromServer(),this.abortWhenLayerClosed(),this.layer.tryAcceptForLocation(),this.abortWhenLayerClosed(),this.tryDismissLayerFromServer(),this.abortWhenLayerClosed(),this.layer.tryDismissForLocation(),this.abortWhenLayerClosed()),this.layer.asCurrent((()=>{for(let t of this.eventPlans)up.emit(t),this.abortWhenLayerClosed()}))}tryAcceptLayerFromServer(){t.isDefined(this.acceptLayer)&&this.layer.isOverlay()&&this.layer.accept(this.acceptLayer)}tryDismissLayerFromServer(){t.isDefined(this.dismissLayer)&&this.layer.isOverlay()&&this.layer.dismiss(this.dismissLayer)}abortWhenLayerClosed(){if(this.layer.isClosed())throw up.error.aborted("Layer was closed")}setSource({oldElement:n,newElement:r,source:s}){"keep"===s&&(s=n&&up.fragment.source(n)),s&&e.setMissingAttr(r,"up-source",t.normalizeURL(s))}}},3030:()=>{const t=up.util;up.Change=class{constructor(t){this.options=t}notApplicable(t){return up.error.notApplicable(this,t)}execute(){throw up.error.notImplemented()}onFinished(){return this.options.onFinished?.()}improveHistoryValue(e,n){return!1===e||t.isString(e)?e:n}}},7422:()=>{const t=up.util;up.element,up.Change.CloseLayer=class extends up.Change.Removal{constructor(t){super(t),this.verb=t.verb,this.layer=up.layer.get(t),this.origin=t.origin,this.value=t.value,this.preventable=t.preventable??!0}execute(){if(!this.layer.isOpen())return Promise.resolve();if(up.browser.assertConfirmed(this.options),up.network.abort((t=>t.layer===this.layer)),this.emitCloseEvent().defaultPrevented&&this.preventable)throw up.error.aborted("Close event was prevented");const{parent:t}=this.layer;this.layer.peel(),this.layer.stack.remove(this.layer),t.restoreHistory(),this.handleFocus(t),this.layer.teardownHandlers(),this.layer.destroyElements(this.options),this.emitClosedEvent(t)}emitCloseEvent(){return this.layer.emit(this.buildEvent(`up:layer:${this.verb}`),{callback:this.layer.callback(`on${t.upperCaseFirst(this.verb)}`),log:`Will ${this.verb} ${this.layer}`})}emitClosedEvent(e){const n=`${this.verb}ed`,r=t.upperCaseFirst(n);return this.layer.emit(this.buildEvent(`up:layer:${n}`),{baseLayer:e,callback:this.layer.callback(`on${r}`),ensureBubbles:!0,log:`${r} ${this.layer}`})}buildEvent(t){return up.event.build(t,{layer:this.layer,value:this.value,origin:this.origin})}handleFocus(t){this.layer.overlayFocus.teardown(),t.overlayFocus?.moveToFront(),(this.layer.origin||t.element).focus({preventScroll:!0})}}},8228:()=>{const t=up.element;up.Change.DestroyFragment=class extends up.Change.Removal{constructor(t){super(t),this.layer=up.layer.get(t)||up.layer.current,this.element=this.options.element,this.animation=this.options.animation,this.log=this.options.log}async execute(){this.parent=this.element.parentNode,up.fragment.markAsDestroying(this.element),up.motion.willAnimate(this.element,this.animation,this.options)?(this.emitDestroyed(),await this.animate(),this.wipe(),this.onFinished()):(this.wipe(),this.emitDestroyed(),this.onFinished())}animate(){return up.motion.animate(this.element,this.animation,this.options)}wipe(){this.layer.asCurrent((()=>{up.syntax.clean(this.element,{layer:this.layer}),up.browser.canJQuery()?jQuery(this.element).remove():t.remove(this.element)}))}emitDestroyed(){up.fragment.emitDestroyed(this.element,{parent:this.parent,log:this.log})}}},9005:()=>{const t=up.util;up.element,up.Change.FromContent=class extends up.Change{constructor(e){super(e),this.layers=t.filter(up.layer.getAll(this.options),this.isRenderableLayer),this.origin=this.options.origin,this.preview=this.options.preview,this.mode=this.options.mode,this.origin&&(this.originLayer=up.layer.get(this.origin))}isRenderableLayer(t){return"new"===t||t.isOpen()}getPlans(){return this.plans||(this.plans=[],this.options.fragment&&(this.options.target=this.getResponseDoc().rootSelector()),this.expandIntoPlans(this.layers,this.options.target),this.expandIntoPlans(this.layers,this.options.fallback)),this.plans}expandIntoPlans(t,e){for(let n of t)for(let t of this.expandTargets(e,n)){const e={...this.options,target:t,layer:n,placement:this.defaultPlacement()},r="new"===n?new up.Change.OpenLayer(e):new up.Change.UpdateLayer(e);this.plans.push(r)}}expandTargets(t,e){return up.fragment.expandTargets(t,{layer:e,mode:this.mode,origin:this.origin})}execute(){return this.options.preload?Promise.resolve():this.seekPlan((t=>t.execute(this.getResponseDoc())))||this.postflightTargetNotApplicable()}getResponseDoc(){if(!this.preview&&!this.responseDoc){const e=t.pick(this.options,["target","content","fragment","document","html"]);up.migrate.handleResponseDocOptions?.(e),"content"===this.defaultPlacement()&&(e.target=this.firstExpandedTarget(e.target)),this.responseDoc=new up.ResponseDoc(e)}return this.responseDoc}defaultPlacement(){if(!this.options.document&&!this.options.fragment)return"content"}firstExpandedTarget(t){return this.expandTargets(t||":main",this.layers[0])[0]}preflightProps(t={}){return this.seekPlan((t=>t.preflightProps()))||t.optional||this.preflightTargetNotApplicable()}preflightTargetNotApplicable(){this.targetNotApplicable("Could not find target in current page")}postflightTargetNotApplicable(){this.targetNotApplicable("Could not find common target in current page and response")}targetNotApplicable(e){if(this.getPlans().length){const n=t.uniq(t.map(this.getPlans(),"target")),r=up.layer.optionToString(this.options.layer);up.fail(e+" (tried selectors %o in %s)",n,r)}else this.layers.length?up.fail("No target selector given"):up.fail("Layer %o does not exist",this.options.layer)}seekPlan(t){for(let e of this.getPlans())try{return t(e)}catch(t){if(!up.error.notApplicable.is(t))throw t}}}},2200:()=>{const t=up.util;up.Change.FromURL=class extends up.Change{constructor(t){super(t),this.options.layer=up.layer.getAll(this.options),this.options.normalizeLayerOptions=!1,this.successOptions=this.options,this.failOptions=up.RenderOptions.deriveFailOptions(this.successOptions)}execute(){let e=this.newPageReason();if(e)return up.puts("up.render()",e),up.browser.loadPage(this.options),t.unresolvablePromise();const n=this.makeRequest();return this.options.preload?n:t.always(n,(t=>this.onRequestSettled(t)))}newPageReason(){return t.isCrossOrigin(this.options.url)?"Loading cross-origin content in new page":up.browser.canPushState()?void 0:"Loading content in new page to restore history support"}makeRequest(){const e=this.preflightPropsForRenderOptions(this.successOptions),n=this.preflightPropsForRenderOptions(this.failOptions,{optional:!0}),r=t.merge(this.successOptions,e,t.renameKeys(n,up.fragment.failKey));return this.request=up.request(r),this.request}preflightPropsForRenderOptions(t,e){return new up.Change.FromContent({...t,preview:!0}).preflightProps(e)}onRequestSettled(t){if(this.response=t,t instanceof up.Response){if(this.isSuccessfulResponse())return this.updateContentFromResponse(["Loaded fragment from successful response to %s",this.request.description],this.successOptions);{const t=["Loaded fragment from failed response to %s (HTTP %d)",this.request.description,this.response.status];throw this.updateContentFromResponse(t,this.failOptions)}}throw t}isSuccessfulResponse(){return!1===this.successOptions.fail||this.response.ok}buildEvent(e,n){const r={request:this.request,response:this.response,renderOptions:this.options};return up.event.build(e,t.merge(r,n))}updateContentFromResponse(t,e){const n=this.buildEvent("up:fragment:loaded",{renderOptions:e});return this.request.assertEmitted(n,{log:t,callback:this.options.onLoaded}),this.augmentOptionsFromResponse(e),new up.Change.FromContent(e).execute()}augmentOptionsFromResponse(e){const n=this.response.url;let r=n,s=this.request.hash;s&&(e.hash=s,r+=s),"GET"===this.response.method?e.source=this.improveHistoryValue(e.source,n):(e.source=this.improveHistoryValue(e.source,"keep"),e.history=!!e.location),e.location=this.improveHistoryValue(e.location,r),e.title=this.improveHistoryValue(e.title,this.response.title),e.eventPlans=this.response.eventPlans;let i=this.response.target;i&&(e.target=i),e.document=this.response.text,e.acceptLayer=this.response.acceptLayer,e.dismissLayer=this.response.dismissLayer,e.document||!t.isDefined(e.acceptLayer)&&!t.isDefined(e.dismissLayer)||(e.target=":none"),e.context=t.merge(e.context,this.response.context)}}},7050:()=>{up.util,up.Change.OpenLayer=class extends up.Change.Addition{constructor(t){super(t),this.target=t.target,this.origin=t.origin,this.baseLayer=t.baseLayer}preflightProps(){return{layer:this.baseLayer,mode:this.options.mode,context:this.buildLayer().context,target:this.target}}bestPreflightSelector(){return this.target}execute(t){if(":none"===this.target?this.content=document.createElement("up-none"):this.content=t.select(this.target),!this.content||this.baseLayer.isClosed())throw this.notApplicable();if(up.puts("up.render()",`Opening element "${this.target}" in new overlay`),this.options.title=this.improveHistoryValue(this.options.title,t.getTitle()),this.emitOpenEvent().defaultPrevented)throw up.error.aborted("Open event was prevented");return this.baseLayer.peel(),this.layer=this.buildLayer(),up.layer.stack.push(this.layer),this.layer.createElements(this.content),this.layer.setupHandlers(),this.handleHistory(),this.setSource({newElement:this.content,source:this.options.source}),t.finalizeElement(this.content),up.hello(this.layer.element,{layer:this.layer,origin:this.origin}),this.handleLayerChangeRequests(),this.handleScroll(),this.layer.startOpenAnimation().then((()=>{this.layer.isOpen()&&this.handleFocus(),this.onFinished()})),this.layer.opening=!1,this.emitOpenedEvent(),this.abortWhenLayerClosed(),new up.RenderResult({layer:this.layer,fragments:[this.content]})}buildLayer(){const t={...this.options,opening:!0};return up.layer.build(t,(t=>this.options=up.RenderOptions.finalize(t)))}handleHistory(){"auto"===this.layer.history&&(this.layer.history=up.fragment.hasAutoHistory(this.content)),this.layer.parent.saveHistory(),this.layer.updateHistory(this.options)}handleFocus(){this.baseLayer.overlayFocus?.moveToBack(),this.layer.overlayFocus.moveToFront(),new up.FragmentFocus({fragment:this.content,layer:this.layer,autoMeans:["autofocus","layer"]}).process(this.options.focus)}handleScroll(){const t={...this.options,fragment:this.content,layer:this.layer,autoMeans:["hash","layer"]};new up.FragmentScrolling(t).process(this.options.scroll)}emitOpenEvent(){return up.emit("up:layer:open",{origin:this.origin,baseLayer:this.baseLayer,layerOptions:this.options,log:"Opening new overlay"})}emitOpenedEvent(){return this.layer.emit("up:layer:opened",{origin:this.origin,callback:this.layer.callback("onOpened"),log:`Opened new ${this.layer}`})}}},1752:()=>{up.Change.Removal=class extends up.Change{}},9441:()=>{const t=up.util,e=up.element;up.Change.UpdateLayer=class extends up.Change.Addition{constructor(t){super(t=up.RenderOptions.finalize(t)),this.layer=t.layer,this.target=t.target,this.placement=t.placement,this.context=t.context,this.parseSteps()}preflightProps(){return this.matchPreflight(),{layer:this.layer,mode:this.layer.mode,context:t.merge(this.layer.context,this.context),target:this.bestPreflightSelector()}}bestPreflightSelector(){return this.matchPreflight(),t.map(this.steps,"selector").join(", ")||":none"}execute(e){this.responseDoc=e,this.matchPostflight(),up.puts("up.render()",`Updating "${this.bestPreflightSelector()}" in ${this.layer}`),this.options.title=this.improveHistoryValue(this.options.title,this.responseDoc.getTitle()),this.setScrollAndFocusOptions(),this.options.saveScroll&&up.viewport.saveScroll({layer:this.layer}),this.options.peel&&this.layer.peel(),t.assign(this.layer.context,this.context),"auto"===this.options.history&&(this.options.history=this.hasAutoHistory()),this.options.history&&this.layer.updateHistory(this.options),this.handleLayerChangeRequests();const n=this.steps.map((t=>this.executeStep(t)));return Promise.all(n).then((()=>(this.abortWhenLayerClosed(),this.onFinished()))),new up.RenderResult({layer:this.layer,fragments:t.map(this.steps,"newElement")})}async executeStep(t){switch(this.setSource(t),t.placement){case"swap":let n=this.findKeepPlan(t);if(n)up.fragment.emitKept(n),this.handleFocus(t.oldElement,t),await this.handleScroll(t.oldElement,t);else{this.transferKeepableElements(t);const n=t.oldElement.parentNode,r={...t,beforeStart(){up.fragment.markAsDestroying(t.oldElement)},afterInsert:()=>{this.responseDoc.finalizeElement(t.newElement),up.hello(t.newElement,t)},beforeDetach:()=>{up.syntax.clean(t.oldElement,{layer:this.layer})},afterDetach(){e.remove(t.oldElement),up.fragment.emitDestroyed(t.oldElement,{parent:n,log:!1})},scrollNew:()=>(this.handleFocus(t.newElement,t),this.handleScroll(t.newElement,t))};await up.morph(t.oldElement,t.newElement,t.transition,r)}break;case"content":let r=e.wrapChildren(t.oldElement),s=e.wrapChildren(t.newElement),i={...t,placement:"swap",oldElement:r,newElement:s,focus:!1};await this.executeStep(i),e.unwrap(s),await this.handleFocus(t.oldElement,t);break;case"before":case"after":let o=e.wrapChildren(t.newElement),a="before"===t.placement?"afterbegin":"beforeend";t.oldElement.insertAdjacentElement(a,o),this.responseDoc.finalizeElement(o),up.hello(o,t),this.handleFocus(o,t),await this.handleScroll(o,t),await up.animate(o,t.transition,t),await e.unwrap(o);break;default:up.fail("Unknown placement: %o",t.placement)}}findKeepPlan(t){if(!t.keep)return;const{oldElement:n,newElement:r}=t;let s=e.booleanOrStringAttr(n,"up-keep");if(s){!0===s&&(s="&");const i={layer:this.layer,origin:n};let o;if(o=t.descendantsOnly?up.fragment.get(r,s,i):up.fragment.subtree(r,s,i)[0],o&&e.matches(o,"[up-keep]")){const t={oldElement:n,newElement:o,newData:up.syntax.data(o)};if(!up.fragment.emitKeep(t).defaultPrevented)return t}}}transferKeepableElements(t){const n=[];if(t.keep)for(let r of t.oldElement.querySelectorAll("[up-keep]")){let s=this.findKeepPlan({...t,oldElement:r,descendantsOnly:!0});if(s){const t=r.cloneNode(!0);e.replace(r,t),e.replace(s.newElement,r),n.push(s)}}t.keepPlans=n}parseSteps(){this.steps=[];for(let e of t.splitValues(this.target,","))if(":none"!==e){const t=e.match(/^(.+?)(?:\:(before|after))?$/);if(!t)throw up.error.invalidSelector(e);const n={...this.options,selector:t[1],placement:t[2]||this.placement||"swap"};this.steps.push(n)}}matchPreflight(){if(!this.matchedPreflight){for(let t of this.steps){const e=new up.FragmentFinder(t);if(t.oldElement||(t.oldElement=e.find()),!t.oldElement)throw this.notApplicable(`Could not find element "${this.target}" in current page`)}this.resolveOldNesting(),this.matchedPreflight=!0}}matchPostflight(){if(!this.matchedPostflight){this.matchPreflight();for(let t of this.steps){let e=this.responseDoc.select(t.selector);if(!e)throw this.notApplicable(`Could not find element "${this.target}" in server response`);t.newElement=e}this.options.hungry&&this.addHungrySteps(),this.resolveOldNesting(),this.matchedPostflight=!0}}addHungrySteps(){const t=up.fragment.all(up.radio.hungrySelector(),this.options);for(let n of t){const t=up.fragment.toTarget(n),r=this.responseDoc.select(t);if(r){const s={selector:t,oldElement:n,newElement:r,transition:e.booleanOrStringAttr(n,"transition"),placement:"swap"};this.steps.push(s)}}}containedByRivalStep(e,n){return t.some(e,(function(t){return t!==n&&("swap"===t.placement||"content"===t.placement)&&t.oldElement.contains(n.oldElement)}))}resolveOldNesting(){let e=t.uniqBy(this.steps,"oldElement");e=t.reject(e,(t=>this.containedByRivalStep(e,t))),this.steps=e}setScrollAndFocusOptions(){this.steps.forEach(((t,e)=>{e>0&&(t.scroll=!1,t.focus=!1),"swap"!==t.placement&&"content"!==t.placement||(t.scrollBehavior="auto",this.focusCapsule||(this.focusCapsule=up.FocusCapsule.preserveWithin(t.oldElement)))}))}handleFocus(t,e){return new up.FragmentFocus({...e,fragment:t,layer:this.layer,focusCapsule:this.focusCapsule,autoMeans:up.fragment.config.autoFocus}).process(e.focus)}handleScroll(t,e){return new up.FragmentScrolling({...e,fragment:t,layer:this.layer,autoMeans:up.fragment.config.autoScroll}).process(e.scroll)}hasAutoHistory(){const e=t.map(this.steps,"oldElement");return t.some(e,(t=>up.fragment.hasAutoHistory(t)))}}},1569:()=>{const t=up.util,e=up.element;up.CompilerPass=class{constructor(t,e,n={}){this.root=t,this.compilers=e,this.skipSubtrees=n.skip,this.skipSubtrees.length&&this.root.querySelector("[up-keep]")||(this.skipSubtrees=void 0),this.layer=n.layer||up.layer.get(this.root)||up.layer.current,this.errors=[]}run(){if(up.puts("up.hello()","Compiling fragment %o",this.root),this.layer.asCurrent((()=>{for(let t of this.compilers)this.runCompiler(t)})),this.errors.length)throw up.error.failed("Errors while compiling",{errors:this.errors})}runCompiler(t){const e=this.select(t.selector);if(e.length){if(t.isDefault||up.puts("up.hello()",'Compiling "%s" on %d element(s)',t.selector,e.length),t.batch)this.compileBatch(t,e);else for(let n of e)this.compileOneElement(t,n);return up.migrate.postCompile?.(e,t)}}compileOneElement(t,e){const n=[t.jQuery?up.browser.jQuery(e):e];if(1!==t.length){const t=up.syntax.data(e);n.push(t)}const r=this.applyCompilerFunction(t,e,n);let s=this.destructorPresence(r);s&&up.destructor(e,s)}compileBatch(e,n){const r=[e.jQuery?up.browser.jQuery(n):n];if(1!==e.length){const e=t.map(n,up.syntax.data);r.push(e)}const s=this.applyCompilerFunction(e,n,r);this.destructorPresence(s)&&up.fail("Compilers with { batch: true } cannot return destructors")}applyCompilerFunction(t,e,n){try{return t.apply(e,n)}catch(t){this.errors.push(t),up.log.error("up.hello()","While compiling %o: %o",e,t),up.error.emitGlobal(t)}}destructorPresence(e){if(t.isFunction(e)||t.isArray(e)&&t.every(e,t.isFunction))return e}select(n){let r=e.subtree(this.root,t.evalOption(n));return this.skipSubtrees&&(r=t.reject(r,(t=>this.isInSkippedSubtree(t)))),r}isInSkippedSubtree(e){let n;return!!t.contains(this.skipSubtrees,e)||!!(n=e.parentElement)&&this.isInSkippedSubtree(n)}}},3742:()=>{const t=up.util;up.Config=class{constructor(t=(()=>({}))){this.blueprintFn=t,this.reset()}reset(){t.assign(this,this.blueprintFn())}}},2737:()=>{const t=up.util,e=up.element;up.CSSTransition=class{constructor(e,n,r){this.element=e,this.lastFrameKebab=n,this.lastFrameKeysKebab=Object.keys(this.lastFrameKebab),t.some(this.lastFrameKeysKebab,(t=>t.match(/A-Z/)))&&up.fail("Animation keys must be kebab-case"),this.finishEvent=r.finishEvent,this.duration=r.duration,this.easing=r.easing,this.finished=!1}start(){return 0===this.lastFrameKeysKebab.length?(this.finished=!0,Promise.resolve()):(this.deferred=t.newDeferred(),this.pauseOldTransition(),this.startTime=new Date,this.startFallbackTimer(),this.listenToFinishEvent(),this.listenToTransitionEnd(),this.startMotion(),this.deferred.promise())}listenToFinishEvent(){this.finishEvent&&(this.stopListenToFinishEvent=up.on(this.element,this.finishEvent,this.onFinishEvent.bind(this)))}onFinishEvent(t){t.stopPropagation(),this.finish()}startFallbackTimer(){this.fallbackTimer=t.timer(this.duration+100,(()=>{this.finish()}))}stopFallbackTimer(){clearTimeout(this.fallbackTimer)}listenToTransitionEnd(){this.stopListenToTransitionEnd=up.on(this.element,"transitionend",this.onTransitionEnd.bind(this))}onTransitionEnd(e){if(e.target!==this.element)return;if(new Date-this.startTime<=.25*this.duration)return;const n=e.propertyName;t.contains(this.lastFrameKeysKebab,n)&&this.finish()}finish(){this.finished||(this.finished=!0,this.stopFallbackTimer(),this.stopListenToFinishEvent?.(),this.stopListenToTransitionEnd?.(),e.concludeCSSTransition(this.element),this.resumeOldTransition(),this.deferred.resolve())}pauseOldTransition(){const t=e.style(this.element,["transitionProperty","transitionDuration","transitionDelay","transitionTimingFunction"]);if(e.hasCSSTransition(t)){if("all"!==t.transitionProperty){const n=t.transitionProperty.split(/\s*,\s*/),r=e.style(this.element,n);this.setOldTransitionTargetFrame=e.setTemporaryStyle(this.element,r)}this.setOldTransition=e.concludeCSSTransition(this.element)}}resumeOldTransition(){this.setOldTransitionTargetFrame?.(),this.setOldTransition?.()}startMotion(){e.setStyle(this.element,{transitionProperty:Object.keys(this.lastFrameKebab).join(", "),transitionDuration:`${this.duration}ms`,transitionTimingFunction:this.easing}),e.setStyle(this.element,this.lastFrameKebab)}}},3635:()=>{const t=up.util;up.element,up.DestructorPass=class{constructor(t,e){this.fragment=t,this.options=e,this.errors=[]}run(){for(let e of this.selectCleanables()){let n=t.pluckKey(e,"upDestructors");if(n)for(let t of n)this.applyDestructorFunction(t,e);e.classList.remove("up-can-clean")}if(this.errors.length)throw up.error.failed("Errors while destroying",{errors:this.errors})}selectCleanables(){const t={...this.options,destroying:!0};return up.fragment.subtree(this.fragment,".up-can-clean",t)}applyDestructorFunction(t,e){try{t()}catch(t){this.errors.push(t),up.log.error("up.destroy()","While destroying %o: %o",e,t),up.error.emitGlobal(t)}}}},1906:()=>{const t=up.util,e=up.element;up.EventEmitter=class extends up.Record{keys(){return["target","event","baseLayer","callback","log","ensureBubbles"]}emit(){return this.logEmission(),this.baseLayer?this.baseLayer.asCurrent((()=>this.dispatchEvent())):this.dispatchEvent(),this.event}dispatchEvent(){this.target.dispatchEvent(this.event),this.ensureBubbles&&e.isDetached(this.target)&&document.dispatchEvent(this.event),this.callback?.(this.event)}assertEmitted(){const t=this.emit();if(t.defaultPrevented)throw up.error.aborted(`Event ${t.type} was prevented`)}logEmission(){if(!up.log.isEnabled())return;let e,n=this.log;t.isArray(n)?[n,...e]=n:e=[];const{type:r}=this.event;t.isString(n)?up.puts(r,n,...e):!1!==n&&up.puts(r,`Event ${r}`)}static fromEmitArgs(n,r={}){let s,i=t.extractOptions(n);return i=t.merge(r,i),t.isElementish(n[0])?i.target=e.get(n.shift()):n[0]instanceof up.Layer&&(i.layer=n.shift()),i.layer&&(s=up.layer.get(i.layer),null==i.target&&(i.target=s.element),null==i.baseLayer&&(i.baseLayer=s)),i.baseLayer&&(i.baseLayer=up.layer.get(i.baseLayer)),t.isString(i.target)?i.target=up.fragment.get(i.target,{layer:i.layer}):i.target||(i.target=document),n[0]?.preventDefault?(i.event=n[0],null==i.log&&(i.log=n[0].log)):t.isString(n[0])?i.event=up.event.build(n[0],i):i.event=up.event.build(i),new this(i)}}},4158:()=>{const t=up.util,e=up.element;up.EventListener=class extends up.Record{keys(){return["element","eventType","selector","callback","jQuery","guard","baseLayer","passive","once"]}constructor(t){super(t),this.key=this.constructor.buildKey(t),this.isDefault=up.framework.booting,this.nativeCallback=this.nativeCallback.bind(this)}bind(){var t;const e=(t=this.element).upEventListeners||(t.upEventListeners={});e[this.key]&&up.fail("up.on(): The %o callback %o cannot be registered more than once",this.eventType,this.callback),e[this.key]=this,this.element.addEventListener(...this.addListenerArgs())}addListenerArgs(){const t=[this.eventType,this.nativeCallback];return this.passive&&up.browser.canPassiveEventListener()&&t.push({passive:!0}),t}unbind(){let t=this.element.upEventListeners;t&&delete t[this.key],this.element.removeEventListener(...this.addListenerArgs())}nativeCallback(n){this.once&&this.unbind();let r=n.target;if(this.selector&&(r=e.closest(r,t.evalOption(this.selector))),(!this.guard||this.guard(n))&&r){const t=[n,this.jQuery?up.browser.jQuery(r):r],e=this.callback.length;if(1!==e&&2!==e){const e=up.syntax.data(r);t.push(e)}const s=this.callback.bind(r,...t);this.baseLayer?this.baseLayer.asCurrent(s):s()}}static fromElement(t){let e=t.element.upEventListeners;if(e)return e[this.buildKey(t)]}static buildKey(e){var n;return(n=e.callback).upUid||(n.upUid=t.uid()),[e.eventType,e.selector,e.callback.upUid].join("|")}static allNonDefault(e){let n=e.upEventListeners;if(n){const e=t.values(n);return t.reject(e,"isDefault")}return[]}}},3139:()=>{const t=up.util;up.EventListenerGroup=class extends up.Record{keys(){return["elements","eventTypes","selector","callback","jQuery","guard","baseLayer","passive","once"]}bind(){const e=[];return this.eachListenerAttributes((function(t){const n=new up.EventListener(t);return n.bind(),e.push(n.unbind.bind(n))})),t.sequence(e)}eachListenerAttributes(t){for(let e of this.elements)for(let n of this.eventTypes)t(this.listenerAttributes(e,n))}listenerAttributes(t,e){return{...this.attributes(),element:t,eventType:e}}unbind(){this.eachListenerAttributes((function(t){let e=up.EventListener.fromElement(t);e&&e.unbind()}))}static fromBindArgs(e,n){const r=(e=t.copy(e)).pop();let s;s=e[0].addEventListener?[e.shift()]:t.isJQuery(e[0])||t.isList(e[0])&&e[0][0].addEventListener?e.shift():[document];let i=t.splitValues(e.shift()),o=up.migrate.fixEventTypes;o&&(i=o(i));const a=t.extractOptions(e);return new this({elements:s,eventTypes:i,selector:e[0],callback:r,...a,...n})}}},6866:()=>{const t=up.util,e=up.element;up.FieldObserver=class{constructor(t,n,r){this.scheduleValues=this.scheduleValues.bind(this),this.isNewValues=this.isNewValues.bind(this),this.callback=r,this.fields=e.list(t),this.delay=n.delay,this.batch=n.batch}start(){this.scheduledValues=null,this.processedValues=this.readFieldValues(),this.currentTimer=void 0,this.callbackRunning=!1,this.unbind=up.on(this.fields,"input change",(()=>this.check()))}stop(){this.unbind(),this.cancelTimer()}cancelTimer(){clearTimeout(this.currentTimer),this.currentTimer=void 0}scheduleTimer(){this.cancelTimer(),this.currentTimer=t.timer(this.delay,(()=>{this.currentTimer=void 0,this.requestCallback()}))}scheduleValues(t){this.scheduledValues=t,this.scheduleTimer()}isNewValues(e){return!t.isEqual(e,this.processedValues)&&!t.isEqual(this.scheduledValues,e)}async requestCallback(){if(null!==this.scheduledValues&&!this.currentTimer&&!this.callbackRunning){const e=this.changedValues(this.processedValues,this.scheduledValues);this.processedValues=this.scheduledValues,this.scheduledValues=null,this.callbackRunning=!0;const n=[];if(this.batch)n.push(this.callback(e));else for(let t in e){const r=e[t];n.push(this.callback(r,t))}await t.allSettled(n),this.callbackRunning=!1,this.requestCallback()}}changedValues(e,n){const r={};let s=Object.keys(e);s=s.concat(Object.keys(n)),s=t.uniq(s);for(let i of s){const s=e[i],o=n[i];t.isEqual(s,o)||(r[i]=o)}return r}readFieldValues(){return up.Params.fromFields(this.fields).toObject()}check(){const t=this.readFieldValues();this.isNewValues(t)&&this.scheduleValues(t)}}},665:()=>{up.util;const t=up.element,e=["selectionStart","selectionEnd","scrollLeft","scrollTop"];function n(t,n){for(let r of e)try{n[r]=t[r]}catch(t){}}function r(e){const n=document.activeElement;if(t.isInSubtree(e,n))return n}up.FocusCapsule=class extends up.Record{keys(){return["selector","oldElement"].concat(e)}restore(e,r){if(!this.wasLost())return;let s=t.get(e,this.selector);return s?(n(this,s),up.focus(s,r),!0):void 0}static preserveWithin(t){let e=r(t);if(e){const r={oldElement:t,selector:up.fragment.toTarget(e)};return n(e,r),new this(r)}}wasLost(){return!r(this.oldElement)}}},2587:()=>{const t=/^([^ >+(]+) (.+)$/;up.FragmentFinder=class{constructor(t){this.options=t,this.origin=this.options.origin,this.selector=this.options.selector,this.layer=this.options.layer}find(){return this.findAroundOrigin()||this.findInLayer()}findAroundOrigin(){if(this.origin&&up.fragment.config.matchAroundOrigin&&!up.element.isDetached(this.origin))return this.findClosest()||this.findInVicinity()}findClosest(){return up.fragment.closest(this.origin,this.selector,this.options)}findInVicinity(){let e=this.selector.match(t);if(e){let t=up.fragment.closest(this.origin,e[1],this.options);if(t)return up.fragment.getDumb(t,e[2])}}findInLayer(){return up.fragment.getDumb(this.selector,this.options)}}},7031:()=>{const t=up.util,e=up.element,n={preventScroll:!0};up.FragmentFocus=class extends up.FragmentProcessor{keys(){return super.keys().concat(["hash","focusCapsule"])}processPrimitive(e){switch(e){case"keep":return this.restoreFocus();case"target":case!0:return this.focusElement(this.fragment);case"layer":return this.focusElement(this.layer.getFocusElement());case"main":return this.focusSelector(":main");case"hash":return this.focusHash();case"autofocus":return this.autofocus();default:if(t.isString(e))return this.focusSelector(e)}}processElement(t){return this.focusElement(t)}resolveCondition(t){return"lost"===t?this.wasFocusLost():super.resolveCondition(t)}focusSelector(t){let e=this.findSelector(t);if(e)return this.focusElement(e)}restoreFocus(){return this.focusCapsule?.restore(this.fragment,n)}autofocus(){let t=e.subtree(this.fragment,"[autofocus]")[0];if(t)return up.focus(t,n),!0}focusElement(t){return up.viewport.makeFocusable(t),up.focus(t,n),!0}focusHash(){let t=up.viewport.firstHashTarget(this.hash,{layer:this.layer});if(t)return this.focusElement(t)}wasFocusLost(){return this.focusCapsule?.wasLost()}}},2828:()=>{const t=up.util;up.FragmentProcessor=class extends up.Record{keys(){return["fragment","autoMeans","origin","layer"]}process(t){return this.tryProcess(t)}tryProcess(e){if(t.isArray(e))return t.find(e,(t=>this.tryProcess(t)));if(t.isFunction(e))return this.tryProcess(e(this.fragment,this.attributes()));if(t.isElement(e))return this.processElement();if(t.isString(e)){if("auto"===e)return this.tryProcess(this.autoMeans);let t=e.match(/^(.+?)-if-(.+?)$/);if(t)return this.resolveCondition(t[2])&&this.process(t[1])}return this.processPrimitive(e)}resolveCondition(t){if("main"===t)return up.fragment.contains(this.fragment,":main")}findSelector(t){const e={layer:this.layer,origin:this.origin};let n=up.fragment.get(this.fragment,t,e)||up.fragment.get(t,e);if(n)return n;up.warn("up.render()",'Could not find an element matching "%s"',t)}}},4850:()=>{const t=up.util;up.element,up.FragmentScrolling=class extends up.FragmentProcessor{keys(){return super.keys().concat(["hash","mode","revealTop","revealMax","revealSnap","scrollBehavior","scrollSpeed"])}constructor(t){up.migrate.handleScrollOptions?.(t),super(t)}process(t){return super.process(t)||Promise.resolve()}processPrimitive(e){switch(e){case"reset":return this.reset();case"layer":return this.revealLayer();case"main":return this.revealSelector(":main");case"restore":return this.restore();case"hash":return this.hash&&up.viewport.revealHash(this.hash,this.attributes());case"target":case"reveal":case!0:return this.revealElement(this.fragment);default:if(t.isString(e))return this.revealSelector(e)}}processElement(t){return this.revealElement(t)}revealElement(t){return up.reveal(t,this.attributes())}revealSelector(t){let e=this.findSelector(t);if(e)return this.revealElement(e)}revealLayer(){return this.revealElement(this.layer.getBoxElement())}reset(){return up.viewport.resetScroll({...this.attributes(),around:this.fragment})}restore(){return up.viewport.restoreScroll({...this.attributes(),around:this.fragment})}}},6267:()=>{const t=up.util,e=up.element;up.HTMLWrapper=class{constructor(t,e={}){this.tagName=t;const n=`<${this.tagName}[^>]*>`,r=`</${this.tagName}>`;this.pattern=new RegExp(n+"(.|\\s)*?"+r,"ig"),this.attrName=`up-wrapped-${this.tagName}`}strip(t){return t.replace(this.pattern,"")}wrap(t){return t.replace(this.pattern,this.wrapMatch.bind(this))}wrapMatch(e){return this.didWrap=!0,'<meta name="'+this.attrName+'" value="'+t.escapeHTML(e)+'">'}unwrap(t){if(this.didWrap)for(let n of t.querySelectorAll(`meta[name='${this.attrName}']`)){const t=n.getAttribute("value"),r=e.createFromHTML(t);e.replace(n,r)}}}},7956:()=>{const t=up.element,e=up.util;up.Layer=class extends up.Record{keys(){return["element","stack","history","mode","context","lastScrollTops"]}defaults(){return{context:{},lastScrollTops:new up.Cache({size:30,key:up.history.normalizeURL})}}constructor(t={}){if(super(t),!this.mode)throw"missing { mode } option"}setupHandlers(){up.link.convertClicks(this)}teardownHandlers(){}mainTargets(){return up.layer.mainTargets(this.mode)}sync(){}accept(){throw up.error.notImplemented()}dismiss(){throw up.error.notImplemented()}peel(t){this.stack.peel(this,t)}evalOption(t){return e.evalOption(t,this)}isCurrent(){return this.stack.isCurrent(this)}isFront(){return this.stack.isFront(this)}isRoot(){return this.stack.isRoot(this)}isOverlay(){return this.stack.isOverlay(this)}isOpen(){return this.stack.isOpen(this)}isClosed(){return this.stack.isClosed(this)}get parent(){return this.stack.parentOf(this)}get child(){return this.stack.childOf(this)}get ancestors(){return this.stack.ancestorsOf(this)}get descendants(){return this.stack.descendantsOf(this)}get index(){return this.stack.indexOf(this)}getContentElement(){return this.contentElement||this.element}getBoxElement(){return this.boxElement||this.element}getFocusElement(){return this.getBoxElement()}getFirstSwappableElement(){throw up.error.notImplemented()}contains(e){return t.closest(e,up.layer.anySelector())===this.element}on(...t){return this.buildEventListenerGroup(t).bind()}off(...t){return this.buildEventListenerGroup(t).unbind()}buildEventListenerGroup(t){return up.EventListenerGroup.fromBindArgs(t,{guard:t=>this.containsEventTarget(t),elements:[this.element],baseLayer:this})}containsEventTarget(t){return this.contains(t.target)}wasHitByMouseEvent(t){const e=document.elementFromPoint(t.clientX,t.clientY);return!e||this.contains(e)}buildEventEmitter(t){return up.EventEmitter.fromEmitArgs(t,{layer:this})}emit(...t){return this.buildEventEmitter(t).emit()}isDetached(){return t.isDetached(this.element)}saveHistory(){this.isHistoryVisible()&&(this.savedTitle=document.title,this.savedLocation=up.history.location)}restoreHistory(){this.savedLocation&&(up.history.push(this.savedLocation),this.savedLocation=null),this.savedTitle&&(document.title=this.savedTitle,this.savedTitle=null)}asCurrent(t){return this.stack.asCurrent(this,t)}updateHistory(t){e.isString(t.title)&&(this.title=t.title),e.isString(t.location)&&(this.location=t.location)}isHistoryVisible(){return this.history&&(this.isRoot()||this.parent.isHistoryVisible())}showsLiveHistory(){return this.isHistoryVisible()&&this.isFront()&&(up.history.config.enabled||this.isRoot())}get title(){return this.showsLiveHistory()?document.title:this.savedTitle}set title(t){this.savedTitle=t,this.showsLiveHistory()&&(document.title=t)}get location(){return this.showsLiveHistory()?up.history.location:this.savedLocation}set location(t){this.savedLocation!==(t=up.history.normalizeURL(t))&&(this.savedLocation=t,this.emit("up:layer:location:changed",{location:t,log:!1}),this.showsLiveHistory()&&up.history.push(t))}selector(t){return this.constructor.selector(t)}static selector(t){throw up.error.notImplemented()}toString(){throw up.error.notImplemented()}affix(...e){return t.affix(this.getFirstSwappableElement(),...e)}[e.isEqual.key](t){return this.constructor===t.constructor&&this.element===t.element}}},7101:()=>{var t;up.Layer.Cover=((t=class extends up.Layer.OverlayWithViewport{}).mode="cover",t)},5580:()=>{var t;up.Layer.Drawer=((t=class extends up.Layer.OverlayWithViewport{}).mode="drawer",t)},86:()=>{var t;up.Layer.Modal=((t=class extends up.Layer.OverlayWithViewport{}).mode="modal",t)},7403:()=>{const t=up.element,e=up.util;up.Layer.Overlay=class extends up.Layer{keys(){return super.keys().concat(["position","align","size","origin","class","backdrop","openAnimation","closeAnimation","openDuration","closeDuration","openEasing","closeEasing","backdropOpenAnimation","backdropCloseAnimation","dismissable","dismissLabel","dismissAriaLabel","onOpened","onAccept","onAccepted","onDismiss","onDismissed","acceptEvent","dismissEvent","acceptLocation","dismissLocation","opening"])}constructor(t){super(t),!0===this.dismissable?this.dismissable=["button","key","outside"]:!1===this.dismissable?this.dismissable=[]:this.dismissable=e.splitValues(this.dismissable),this.acceptLocation&&(this.acceptLocation=new up.URLPattern(this.acceptLocation)),this.dismissLocation&&(this.dismissLocation=new up.URLPattern(this.dismissLocation))}callback(t){let e=this[t];if(e)return e.bind(this)}createElement(t){this.nesting||(this.nesting=this.suggestVisualNesting());const n=e.compactObject(e.pick(this,["align","position","size","class","nesting"]));this.element=this.affixPart(t,null,n)}createBackdropElement(t){this.backdropElement=this.affixPart(t,"backdrop")}createViewportElement(t){this.viewportElement=this.affixPart(t,"viewport",{"up-viewport":""})}createBoxElement(t){this.boxElement=this.affixPart(t,"box")}createContentElement(t,e){this.contentElement=this.affixPart(t,"content"),this.contentElement.appendChild(e)}createDismissElement(e){return this.dismissElement=this.affixPart(e,"dismiss",{"up-dismiss":'":button"',"aria-label":this.dismissAriaLabel}),t.affix(this.dismissElement,'span[aria-hidden="true"]',{text:this.dismissLabel})}affixPart(e,n,r={}){return t.affix(e,this.selector(n),r)}static selector(t){return e.compact(["up",this.mode,t]).join("-")}suggestVisualNesting(){const{parent:t}=this;return this.mode===t.mode?1+t.suggestVisualNesting():0}setupHandlers(){super.setupHandlers(),this.overlayFocus=new up.OverlayFocus(this),this.supportsDismissMethod("button")&&this.createDismissElement(this.getBoxElement()),this.supportsDismissMethod("outside")&&(this.unbindParentClicked=this.parent.on("up:click",((t,e)=>{const n=this.origin&&this.origin.contains(e);this.onOutsideClicked(t,n)})),this.viewportElement&&up.on(this.viewportElement,"up:click",(t=>{t.target===this.viewportElement&&this.onOutsideClicked(t,!0)}))),this.supportsDismissMethod("key")&&(this.unbindEscapePressed=up.event.onEscape((t=>this.onEscapePressed(t)))),this.registerClickCloser("up-accept",((t,e)=>{this.accept(t,e)})),this.registerClickCloser("up-dismiss",((t,e)=>{this.dismiss(t,e)})),up.migrate.registerLayerCloser?.(this),this.registerEventCloser(this.acceptEvent,this.accept),this.registerEventCloser(this.dismissEvent,this.dismiss)}onOutsideClicked(t,e){e&&up.event.halt(t),this.dismiss(":outside")}onEscapePressed(t){if(this.isFront()){let e=up.form.focusedField();e?e.blur():this.supportsDismissMethod("key")&&(up.event.halt(t),this.dismiss(":key"))}}registerClickCloser(e,n){this.on("up:click",`[${e}]`,(function(r){up.event.halt(r);const s=r.target,i=t.jsonAttr(s,e),o={origin:s},a=new up.OptionsParser(o,s);a.booleanOrString("animation"),a.string("easing"),a.number("duration"),a.string("confirm"),n(i,o)}))}registerEventCloser(t,e){if(t)return this.on(t,(t=>{t.preventDefault(),e.call(this,t)}))}tryAcceptForLocation(){this.tryCloseForLocation(this.acceptLocation,this.accept)}tryDismissForLocation(){this.tryCloseForLocation(this.dismissLocation,this.dismiss)}tryCloseForLocation(t,e){let n,r;if(t&&(n=this.location)&&(r=t.recognize(n))){const t={...r,location:n};e.call(this,t)}}teardownHandlers(){super.teardownHandlers(),this.unbindParentClicked?.(),this.unbindEscapePressed?.(),this.overlayFocus.teardown()}destroyElements(t){const e={...t,animation:()=>this.startCloseAnimation(t),onFinished:()=>{this.onElementsRemoved(),t.onFinished?.()},log:!1};up.destroy(this.element,e)}onElementsRemoved(){}startAnimation(t={}){const e=up.animate(this.getBoxElement(),t.boxAnimation,t);let n;return this.backdrop&&!up.motion.isNone(t.boxAnimation)&&(n=up.animate(this.backdropElement,t.backdropAnimation,t)),Promise.all([e,n])}startOpenAnimation(t={}){return this.startAnimation({boxAnimation:t.animation??this.evalOption(this.openAnimation),backdropAnimation:"fade-in",easing:t.easing||this.openEasing,duration:t.duration||this.openDuration}).then((()=>this.wasEverVisible=!0))}startCloseAnimation(t={}){const e=this.wasEverVisible&&(t.animation??this.evalOption(this.closeAnimation));return this.startAnimation({boxAnimation:e,backdropAnimation:"fade-out",easing:t.easing||this.closeEasing,duration:t.duration||this.closeDuration})}accept(t=null,e={}){return this.executeCloseChange("accept",t,e)}dismiss(t=null,e={}){return this.executeCloseChange("dismiss",t,e)}supportsDismissMethod(t){return e.contains(this.dismissable,t)}executeCloseChange(t,e,n){return n={...n,verb:t,value:e,layer:this},new up.Change.CloseLayer(n).execute()}getFirstSwappableElement(){return this.getContentElement().children[0]}toString(){return`${this.mode} overlay`}}},6412:()=>{up.element,up.Layer.OverlayWithTether=class extends up.Layer.Overlay{createElements(t){this.origin||up.fail("Missing { origin } option"),this.tether=new up.Tether({anchor:this.origin,align:this.align,position:this.position}),this.createElement(this.tether.parent),this.createContentElement(this.element,t),this.tether.start(this.element)}onElementsRemoved(){this.tether.stop()}sync(){this.isOpen()&&(this.isDetached()||this.tether.isDetached()?this.dismiss(":detached",{animation:!1,preventable:!1}):this.tether.sync())}}},7965:()=>{var t;up.element,up.Layer.OverlayWithViewport=((t=class extends up.Layer.Overlay{static getParentElement(){return document.body}createElements(t){this.shiftBody(),this.createElement(this.constructor.getParentElement()),this.backdrop&&this.createBackdropElement(this.element),this.createViewportElement(this.element),this.createBoxElement(this.viewportElement),this.createContentElement(this.boxElement,t)}onElementsRemoved(){this.unshiftBody()}shiftBody(){this.constructor.bodyShifter.shift()}unshiftBody(){this.constructor.bodyShifter.unshift()}sync(){this.isDetached()&&this.isOpen()&&this.constructor.getParentElement().appendChild(this.element)}}).bodyShifter=new up.BodyShifter,t)},4552:()=>{var t;up.Layer.Popup=((t=class extends up.Layer.OverlayWithTether{}).mode="popup",t)},7771:()=>{var t;const e=up.util,n=up.element;up.Layer.Root=((t=class extends up.Layer{constructor(t){super(t),this.setupHandlers()}get element(){return n.root}getFirstSwappableElement(){return document.body}static selector(){return"html"}setupHandlers(){this.element.upHandlersApplied||(this.element.upHandlersApplied=!0,super.setupHandlers())}sync(){this.setupHandlers()}accept(){this.cannotCloseRoot()}dismiss(){this.cannotCloseRoot()}cannotCloseRoot(){throw up.error.failed("Cannot close the root layer")}reset(){e.assign(this,this.defaults())}toString(){return"root layer"}}).mode="root",t)},6066:()=>{const t=up.util,e=up.element;up.LayerLookup=class{constructor(e,...n){this.stack=e;const r=t.parseArgIntoOptions(n,"layer");if(!1!==r.normalizeLayerOptions&&up.layer.normalizeOptions(r),this.values=t.splitValues(r.layer),this.origin=r.origin,this.baseLayer=r.baseLayer||this.stack.current,t.isString(this.baseLayer)){const t={...r,baseLayer:this.stack.current,normalizeLayerOptions:!1};this.baseLayer=new this.constructor(this.stack,this.baseLayer,t).first()}}originLayer(){if(this.origin)return this.forElement(this.origin)}first(){return this.all()[0]}all(){let e=t.flatMap(this.values,(t=>this.resolveValue(t)));return e=t.compact(e),e=t.uniq(e),e}forElement(n){return n=e.get(n),t.find(this.stack.reversed(),(t=>t.contains(n)))}forIndex(t){return this.stack[t]}resolveValue(e){if(e instanceof up.Layer)return e;if(t.isNumber(e))return this.forIndex(e);if(/^\d+$/.test(e))return this.forIndex(Number(e));if(t.isElementish(e))return this.forElement(e);switch(e){case"any":return[this.baseLayer,...this.stack.reversed()];case"current":return this.baseLayer;case"closest":return this.stack.selfAndAncestorsOf(this.baseLayer);case"parent":return this.baseLayer.parent;case"ancestor":case"ancestors":return this.baseLayer.ancestors;case"child":return this.baseLayer.child;case"descendant":case"descendants":return this.baseLayer.descendants;case"new":return"new";case"root":return this.stack.root;case"overlay":case"overlays":return t.reverse(this.stack.overlays);case"front":return this.stack.front;case"origin":return this.originLayer();default:return up.fail("Unknown { layer } option: %o",e)}}}},6387:()=>{const t=up.util;up.element,up.LayerStack=class extends Array{constructor(){super(),Object.setPrototypeOf(this,up.LayerStack.prototype),this.currentOverrides=[],this.push(this.buildRoot())}buildRoot(){return up.layer.build({mode:"root",stack:this})}remove(e){t.remove(this,e)}peel(e,n){const r=t.reverse(e.descendants),s={...n,preventable:!1};for(let t of r)t.dismiss(":peel",s)}reset(){this.peel(this.root,{animation:!1}),this.currentOverrides=[],this.root.reset()}isOpen(t){return t.index>=0}isClosed(t){return!this.isOpen(t)}parentOf(t){return this[t.index-1]}childOf(t){return this[t.index+1]}ancestorsOf(e){return t.reverse(this.slice(0,e.index))}selfAndAncestorsOf(t){return[t,...t.ancestors]}descendantsOf(t){return this.slice(t.index+1)}isRoot(t){return this[0]===t}isOverlay(t){return!this.isRoot(t)}isCurrent(t){return this.current===t}isFront(t){return this.front===t}get(...t){return this.getAll(...t)[0]}getAll(...t){return new up.LayerLookup(this,...t).all()}sync(){for(let t of this)t.sync()}asCurrent(t,e){try{return this.currentOverrides.push(t),e()}finally{this.currentOverrides.pop()}}reversed(){return t.reverse(this)}dismissOverlays(e=null,n={}){n.dismissable=!1;for(let r of t.reverse(this.overlays))r.dismiss(e,n)}[t.copy.key](){return t.copyArrayLike(this)}get count(){return this.length}get root(){return this[0]}get overlays(){return this.root.descendants}get current(){return t.last(this.currentOverrides)||this.front}get front(){return t.last(this)}}},5390:()=>{up.util,up.LinkFeedbackURLs=class{constructor(t){const e=up.feedback.normalizeURL;if(this.isSafe=up.link.isSafe(t),this.isSafe){const n=t.getAttribute("href");n&&"#"!==n&&(this.href=e(n));const r=t.getAttribute("up-href");r&&(this.upHREF=e(r));const s=t.getAttribute("up-alias");s&&(this.aliasPattern=new up.URLPattern(s,e))}}isCurrent(t){return this.isSafe&&!!(this.href&&this.href===t||this.upHREF&&this.upHREF===t||this.aliasPattern&&this.aliasPattern.test(t,!1))}}},2618:()=>{const t=up.util,e=up.element;up.LinkPreloader=class{constructor(){this.considerPreload=this.considerPreload.bind(this)}observeLink(t){up.link.isSafe(t)&&(this.on(t,"mouseenter",(t=>this.considerPreload(t,!0))),this.on(t,"mousedown touchstart",(t=>this.considerPreload(t))),this.on(t,"mouseleave",(t=>this.stopPreload(t))))}on(t,e,n){up.on(t,e,{passive:!0},n)}considerPreload(t,e){const n=t.target;n!==this.currentLink&&(this.reset(),this.currentLink=n,up.link.shouldFollowEvent(t,n)&&(e?this.preloadAfterDelay(n):this.preloadNow(n)))}stopPreload(t){if(t.target===this.currentLink)return this.reset()}reset(){this.currentLink&&(clearTimeout(this.timer),this.currentRequest?.preload&&this.currentRequest.abort(),this.currentLink=void 0,this.currentRequest=void 0)}preloadAfterDelay(n){const r=e.numberAttr(n,"up-delay")??up.link.config.preloadDelay;this.timer=t.timer(r,(()=>this.preloadNow(n)))}preloadNow(t){e.isDetached(t)?this.reset():(up.log.muteUncriticalRejection(up.link.preload(t,{onQueued:t=>this.currentRequest=t})),this.queued=!0)}}},7792:()=>{const t=up.util,e=up.element;up.MotionController=class{constructor(t){this.activeClass=`up-${t}`,this.dataKey=`up-${t}-finished`,this.selector=`.${this.activeClass}`,this.finishEvent=`up:${t}:finish`,this.finishCount=0,this.clusterCount=0}async startFunction(n,r,s={}){n=e.list(n);const i=()=>up.log.muteUncriticalRejection(r());if(s.trackMotion=s.trackMotion??up.motion.isEnabled(),!1!==s.trackMotion){s.trackMotion=!1,await this.finish(n);let t=this.whileForwardingFinishEvent(n,i);return this.markCluster(n,t),t=t.then((()=>this.unmarkCluster(n))),await t}await t.microtask(i)}startMotion(t,e,n={}){const r=up.on(t,this.finishEvent,(()=>e.finish()));let s=this.startFunction(t,(()=>e.start()),n);return s=s.then(r),s}finish(e){if(this.finishCount++,0===this.clusterCount||!up.motion.isEnabled())return Promise.resolve();e=this.expandFinishRequest(e);const n=t.map(e,this.finishOneElement.bind(this));return Promise.all(n)}expandFinishRequest(n){return n?t.flatMap(n,(t=>e.list(e.closest(t,this.selector),e.all(t,this.selector)))):e.all(this.selector)}isActive(t){return t.classList.contains(this.activeClass)}finishOneElement(t){return this.emitFinishEvent(t),this.whenElementFinished(t)}emitFinishEvent(t,e={}){return e={target:t,log:!1,...e},up.emit(this.finishEvent,e)}whenElementFinished(t){return t[this.dataKey]||Promise.resolve()}markCluster(t,e){this.clusterCount++;for(let n of t)n.classList.add(this.activeClass),n[this.dataKey]=e}unmarkCluster(t){this.clusterCount--;for(let e of t)e.classList.remove(this.activeClass),delete e[this.dataKey]}whileForwardingFinishEvent(t,e){if(t.length<2)return e();const n=up.on(t,this.finishEvent,(e=>{if(!e.forwarded)for(let n of t)n!==e.target&&this.isActive(n)&&this.emitFinishEvent(n,{forwarded:!0})}));return e().then(n)}async reset(){await this.finish(),this.finishCount=0,this.clusterCount=0}}},1104:()=>{const t=up.util,e=up.element;up.OptionsParser=class{constructor(t,e,n){this.options=t,this.element=e,this.fail=n?.fail}string(t,n){this.parse(e.attr,t,n)}boolean(t,n){this.parse(e.booleanAttr,t,n)}number(t,n){this.parse(e.numberAttr,t,n)}booleanOrString(t,n){this.parse(e.booleanOrStringAttr,t,n)}json(t,n){this.parse(e.jsonAttr,t,n)}parse(e,n,r={}){const s=t.wrapList(r.attr??this.attrNameForKey(n));let i=this.options[n];if(this.element)for(let t of s)i??(i=e(this.element,t));i??(i=r.default);let o,a=r.normalize;if(a&&(i=a(i)),t.isDefined(i)&&(this.options[n]=i),(r.fail||this.fail)&&(o=up.fragment.failKey(n))){const n=t.compact(t.map(s,this.deriveFailAttrName)),i={...r,attr:n,fail:!1};this.parse(e,o,i)}}deriveFailAttrName(t){if(0===t.indexOf("up-"))return`up-fail-${t.slice(3)}`}attrNameForKey(e){return`up-${t.camelToKebabCase(e)}`}}},8665:()=>{const t=up.element,e=up.util;up.OverlayFocus=class{constructor(t){this.layer=t,this.focusElement=this.layer.getFocusElement()}moveToFront(){this.enabled||(this.enabled=!0,this.untrapFocus=up.on("focusin",(t=>this.onFocus(t))),this.unsetAttrs=t.setTemporaryAttrs(this.focusElement,{tabindex:"0",role:"dialog","aria-modal":"true"}),this.focusTrapBefore=t.affix(this.focusElement,"beforebegin","up-focus-trap[tabindex=0]"),this.focusTrapAfter=t.affix(this.focusElement,"afterend","up-focus-trap[tabindex=0]"))}moveToBack(){this.teardown()}teardown(){this.enabled&&(this.enabled=!1,this.untrapFocus(),this.unsetAttrs(),t.remove(this.focusTrapBefore),t.remove(this.focusTrapAfter))}onFocus(t){const{target:e}=t;this.processingFocusEvent||(this.processingFocusEvent=!0,e===this.focusTrapBefore?this.focusEnd():e!==this.focusTrapAfter&&this.layer.contains(e)||this.focusStart(),this.processingFocusEvent=!1)}focusStart(t){up.focus(this.focusElement,t)}focusEnd(){this.focusLastDescendant(this.layer.getBoxElement())||this.focusStart()}focusLastDescendant(t){for(let n of e.reverse(t.children))if(up.viewport.tryFocus(n)||this.focusLastDescendant(n))return!0}}},3645:()=>{const t=up.util,e=up.element;up.Params=class{constructor(t){this.clear(),this.addAll(t)}clear(){this.entries=[]}[t.copy.key](){return new up.Params(this)}toObject(){const e={};for(let n of this.entries){const{name:r,value:s}=n;t.isBasicObjectProperty(r)||(this.isArrayKey(r)?(e[r]||(e[r]=[]),e[r].push(s)):e[r]=s)}return e}toArray(){return this.entries}toFormData(){const t=new FormData;for(let e of this.entries)t.append(e.name,e.value);return t.entries||(t.originalArray=this.entries),t}toQuery(){let e=t.map(this.entries,this.arrayEntryToQuery.bind(this));return e=t.compact(e),e.join("&")}arrayEntryToQuery(e){const{value:n}=e;if(this.isBinaryValue(n))return;let r=encodeURIComponent(e.name);return t.isGiven(n)&&(r+="=",r+=encodeURIComponent(n)),r}isBinaryValue(t){return t instanceof Blob}hasBinaryValues(){const e=t.map(this.entries,"value");return t.some(e,this.isBinaryValue)}toURL(e){let n=[e,this.toQuery()];n=t.filter(n,t.isPresent);const r=t.contains(e,"?")?"&":"?";return n.join(r)}add(t,e){this.entries.push({name:t,value:e})}addAll(e){t.isMissing(e)||(e instanceof this.constructor?this.entries.push(...e.entries):t.isArray(e)?this.entries.push(...e):t.isString(e)?this.addAllFromQuery(e):t.isFormData(e)?this.addAllFromFormData(e):t.isObject(e)?this.addAllFromObject(e):up.fail("Unsupport params type: %o",e))}addAllFromObject(e){for(let n in e){const r=e[n],s=t.isArray(r)?r:[r];for(let t of s)this.add(n,t)}}addAllFromQuery(e){for(let n of e.split("&"))if(n){let[e,r]=n.split("=");e=decodeURIComponent(e),r=t.isGiven(r)?decodeURIComponent(r):null,this.add(e,r)}}addAllFromFormData(e){t.eachIterator(e.entries(),(t=>{this.add(...t)}))}set(t,e){this.delete(t),this.add(t,e)}delete(e){this.entries=t.reject(this.entries,this.matchEntryFn(e))}matchEntryFn(t){return e=>e.name===t}get(t){return this.isArrayKey(t)?this.getAll(t):this.getFirst(t)}getFirst(e){return t.find(this.entries,this.matchEntryFn(e))?.value}getAll(e){if(this.isArrayKey(e))return this.getAll(e);{const n=t.map(this.entries,this.matchEntryFn(e));return t.map(n,"value")}}isArrayKey(e){return t.endsWith(e,"[]")}[t.isBlank.key](){return 0===this.entries.length}static fromForm(t){return t=up.fragment.get(t),this.fromFields(up.form.fields(t))}static fromFields(e){const n=new this;for(let r of t.wrapList(e))n.addField(r);return n}addField(t){let n=(t=e.get(t)).name;if(n&&!t.disabled){const{tagName:e}=t,{type:r}=t;if("SELECT"===e)for(let e of t.querySelectorAll("option"))e.selected&&this.add(n,e.value);else if("checkbox"===r||"radio"===r)t.checked&&this.add(n,t.value);else{if("file"!==r)return this.add(n,t.value);for(let e of t.files)this.add(n,e)}}}[t.isEqual.key](e){return this.constructor===e.constructor&&t.isEqual(this.entries,e.entries)}static fromURL(e){const n=new this;let r=t.parseURL(e).search;return r&&(r=r.replace(/^\?/,""),n.addAll(r)),n}static stripURL(e){return t.normalizeURL(e,{search:!1})}}},7782:()=>{const t=up.element;up.ProgressBar=class{constructor(){this.step=0,this.element=t.affix(document.body,"up-progress-bar"),this.element.style.transition="width 300ms ease-out",this.moveTo(0),up.element.paint(this.element),this.width=31,this.nextStep()}nextStep(){let t;t=this.width<80?Math.random()<.15?7+5*Math.random():1.5+.5*Math.random():.13*(100-width)*Math.random(),this.moveTo(this.width+t),this.step++;const e=300+40*this.step;this.timeout=setTimeout(this.nextStep.bind(this),e)}moveTo(t){this.width=t,this.element.style.width=`${t}vw`}destroy(){clearTimeout(this.timeout),t.remove(this.element)}conclude(){clearTimeout(this.timeout),this.moveTo(100),setTimeout(this.destroy.bind(this),300)}}},2406:()=>{const t=up.util;up.Record=class{keys(){throw"Return an array of keys"}defaults(t){return{}}constructor(e){t.assign(this,this.defaults(e),this.attributes(e))}attributes(e=this){return t.pick(e,this.keys())}[t.copy.key](){return this.variant()}variant(e={}){return new this.constructor(t.merge(this.attributes(),e))}[t.isEqual.key](e){return this.constructor===e.constructor&&t.isEqual(this.attributes(),e.attributes())}}},1279:()=>{up.util,up.Rect=class extends up.Record{keys(){return["left","top","width","height"]}get bottom(){return this.top+this.height}get right(){return this.left+this.width}static fromElement(t){return new this(t.getBoundingClientRect())}}},2705:()=>{const t=up.util;up.RenderOptions=function(){const e={hungry:!0,keep:!0,source:!0,saveScroll:!0,fail:"auto"},n={solo:!1,confirm:!1,feedback:!1},r=["url","method","origin","headers","params","cache","clearCache","fallback","solo","confirm","feedback","origin","baseLayer","fail"].concat(["keep","hungry","history","source","saveScroll","navigate"]),s=["url","content","fragment","document"],i=["history","focus","scroll"];return{preprocess:function(r){up.migrate.preprocessRenderOptions?.(r);const s=t.merge(e,function(t){if(t.navigate)return up.fragment.config.navigateOptions}(r));return t.merge(t.omit(s,i),{defaults:s},r,function(t){if(t.preload)return n}(r))},finalize:function(e,n){return t.merge(e.defaults,n,e)},assertContentGiven:function(e){t.some(s,(n=>t.isGiven(e[n])))||(e.defaultToEmptyContent?e.content="":up.fail("up.render() needs either { "+s.join(", ")+" } option"))},deriveFailOptions:function(e){return t.merge(e.defaults,t.pick(e,r),function(t){const e={};for(let n in t){const r=t[n];let s=up.fragment.successKey(n);s&&(e[s]=r)}return e}(e))}}}()},606:()=>{up.RenderResult=class extends up.Record{keys(){return["fragments","layer"]}}},5437:()=>{const t=up.util;up.element,up.Request=class extends up.Record{keys(){return["method","url","hash","params","target","failTarget","headers","timeout","preload","cache","clearCache","layer","mode","context","failLayer","failMode","failContext","origin","solo","queueTime","wrapMethod","contentType","payload","onQueued"]}constructor(e){super(e),this.params=new up.Params(this.params),this.headers||(this.headers={}),this.preload&&(this.cache=!0),null==this.wrapMethod&&(this.wrapMethod=up.network.config.wrapMethod),this.normalizeForCaching(),e.basic||(this.layer=up.layer.get(this.layer),this.failLayer=up.layer.get(this.failLayer||this.layer),this.context||(this.context=this.layer.context||{}),this.failContext||(this.failContext=this.failLayer.context||{}),this.mode||(this.mode=this.layer.mode),this.failMode||(this.failMode=this.failLayer.mode),this.deferred=t.newDeferred(),this.state="new")}followState(e){t.delegate(this,["deferred","state","preload"],(()=>e))}normalizeForCaching(){this.method=t.normalizeMethod(this.method),this.extractHashFromURL(),this.transferParamsToURL(),this.url=t.normalizeURL(this.url)}evictExpensiveAttrs(){t.task((()=>(this.layer=void 0,this.failLayer=void 0,this.origin=void 0)))}extractHashFromURL(){let t=this.url?.match(/^([^#]*)(#.+)$/);if(t)return this.url=t[1],this.hash=t[2]}transferParamsToURL(){!this.url||this.allowsPayload()||t.isBlank(this.params)||(this.url=this.params.toURL(this.url),this.params.clear())}isSafe(){return up.network.isSafeMethod(this.method)}allowsPayload(){return t.methodAllowsPayload(this.method)}will302RedirectWithGET(){return this.isSafe()||"POST"===this.method}willCache(){return"auto"===this.cache?up.network.config.autoCache(this):this.cache}runQueuedCallbacks(){t.always(this,(()=>this.evictExpensiveAttrs())),this.onQueued?.(this)}load(){"new"===this.state&&(this.state="loading",this.xhr=new up.Request.XHRRenderer(this).buildAndSend({onload:()=>this.onXHRLoad(),onerror:()=>this.onXHRError(),ontimeout:()=>this.onXHRTimeout(),onabort:()=>this.onXHRAbort()}))}loadPage(){up.network.abort(),new up.Request.FormRenderer(this).buildAndSubmit()}onXHRLoad(){const t=this.extractResponseFromXHR(),e=["Server responded HTTP %d to %s %s (%d characters)",t.status,this.method,this.url,t.text.length];this.emit("up:request:loaded",{request:t.request,response:t,log:e}),this.respondWith(t)}onXHRError(){const t="Fatal error during request";this.deferred.reject(up.error.failed(t)),this.emit("up:request:fatal",{log:t})}onXHRTimeout(){this.setAbortedState("Requested timed out")}onXHRAbort(){this.setAbortedState()}abort(){this.setAbortedState()&&this.xhr&&this.xhr.abort()}setAbortedState(t=["Request to %s %s was aborted",this.method,this.url]){if("new"===this.state||"loading"===this.state)return this.state="aborted",this.emit("up:request:aborted",{log:t}),this.deferred.reject(up.error.aborted(t)),!0}respondWith(t){if("loading"===this.state)return this.state="loaded",t.ok?this.deferred.resolve(t):this.deferred.reject(t)}csrfHeader(){return up.protocol.csrfHeader()}csrfParam(){return up.protocol.csrfParam()}csrfToken(){if(!this.isSafe()&&!this.isCrossOrigin())return up.protocol.csrfToken()}isCrossOrigin(){return t.isCrossOrigin(this.url)}extractResponseFromXHR(){const e={method:this.method,url:this.url,request:this,xhr:this.xhr,text:this.xhr.responseText,status:this.xhr.status,title:up.protocol.titleFromXHR(this.xhr),target:up.protocol.targetFromXHR(this.xhr),acceptLayer:up.protocol.acceptLayerFromXHR(this.xhr),dismissLayer:up.protocol.dismissLayerFromXHR(this.xhr),eventPlans:up.protocol.eventPlansFromXHR(this.xhr),context:up.protocol.contextFromXHR(this.xhr),clearCache:up.protocol.clearCacheFromXHR(this.xhr)};let n=up.protocol.methodFromXHR(this.xhr),r=up.protocol.locationFromXHR(this.xhr);return r&&(n||t.matchURLs(e.url,r)||(n="GET"),e.url=r),n&&(e.method=n),new up.Response(e)}cacheKey(){return JSON.stringify([this.method,this.url,this.params.toQuery(),this.metaProps()])}metaProps(){const e={};for(let n of t.evalOption(up.network.config.requestMetaKeys,this)){const r=this[n];t.isGiven(r)&&(e[n]=r)}return e}buildEventEmitter(t){return up.EventEmitter.fromEmitArgs(t,{request:this,layer:this.layer})}emit(...t){return this.buildEventEmitter(t).emit()}assertEmitted(...t){this.buildEventEmitter(t).assertEmitted()}get description(){return this.method+" "+this.url}},t.delegate(up.Request.prototype,["then","catch","finally"],(function(){return this.deferred}))},7974:()=>{let t=up.util;up.Request.Cache=class extends up.Cache{maxSize(){return up.network.config.cacheSize}expiryMillis(){return up.network.config.cacheExpiry}normalizeStoreKey(e){return t.wrapValue(up.Request,e).cacheKey()}clear(t){if(t&&"*"!==t&&!0!==t)return t=new up.URLPattern(t),this.each(((e,n)=>{t.test(n.url)&&this.store.remove(e)}));super.clear()}}},5221:()=>{const t=up.util,e=up.element,n=["GET","POST"];up.Request.FormRenderer=class{constructor(t){this.request=t}buildAndSubmit(){this.params=t.copy(this.request.params);let r=this.request.url,{method:s}=this.request;const i=up.Params.fromURL(r);this.params.addAll(i),r=up.Params.stripURL(r),t.contains(n,s)||(s=up.protocol.wrapMethod(s,this.params)),this.form=e.affix(document.body,"form.up-request-loader",{method:s,action:r});let o,a,u=this.request.contentType;u&&this.form.setAttribute("enctype",u),(o=this.request.csrfParam())&&(a=this.request.csrfToken())&&this.params.add(o,a),t.each(this.params.toArray(),this.addField.bind(this)),up.browser.submitForm(this.form)}addField(t){e.affix(this.form,"input[type=hidden]",t)}}},6413:()=>{const t=up.util;up.Request.Queue=class{constructor(t={}){this.concurrency=t.concurrency??(()=>up.network.config.concurrency),this.badResponseTime=t.badResponseTime??(()=>up.network.config.badResponseTime),this.reset()}reset(){this.queuedRequests=[],this.currentRequests=[],clearTimeout(this.checkSlowTimout),this.emittedSlow=!1}get allRequests(){return this.currentRequests.concat(this.queuedRequests)}asap(e){e.runQueuedCallbacks(),t.always(e,(t=>this.onRequestSettled(e,t))),e.queueTime=new Date,this.setSlowTimer(),this.hasConcurrencyLeft()?this.sendRequestNow(e):this.queueRequest(e)}promoteToForeground(t){if(t.preload)return t.preload=!1,this.setSlowTimer()}setSlowTimer(){const e=t.evalOption(this.badResponseTime);this.checkSlowTimout=t.timer(e,(()=>this.checkSlow()))}hasConcurrencyLeft(){const e=t.evalOption(this.concurrency);return-1===e||this.currentRequests.length<e}isBusy(){return this.currentRequests.length>0}queueRequest(t){this.queuedRequests.push(t)}pluckNextRequest(){let e=t.find(this.queuedRequests,(t=>!t.preload));return e||(e=this.queuedRequests[0]),t.remove(this.queuedRequests,e)}sendRequestNow(t){t.emit("up:request:load",{log:["Loading %s %s",t.method,t.url]}).defaultPrevented?t.abort("Prevented by event listener"):(t.normalizeForCaching(),this.currentRequests.push(t),t.load())}onRequestSettled(e,n){t.remove(this.currentRequests,e),n instanceof up.Response&&n.ok&&up.network.registerAliasForRedirect(e,n),this.checkSlow(),t.microtask((()=>this.poke()))}poke(){let t;if(this.hasConcurrencyLeft()&&(t=this.pluckNextRequest()))return this.sendRequestNow(t)}abort(e=!0){for(let n of[this.currentRequests,this.queuedRequests])t.filter(n,(t=>this.requestMatches(t,e))).forEach((function(e){e.abort(),t.remove(n,e)}))}abortExcept(e,n=!0){const r=e.cacheKey();this.abort((e=>e.cacheKey()!==r&&t.evalOption(n,e)))}requestMatches(e,n){return e===n||t.evalOption(n,e)}checkSlow(){const t=this.isSlow();this.emittedSlow!==t&&(this.emittedSlow=t,t?up.emit("up:request:late",{log:"Server is slow to respond"}):up.emit("up:request:recover",{log:"Slow requests were loaded"}))}isSlow(){const e=new Date,n=t.evalOption(this.badResponseTime),r=t.reject(this.allRequests,"preload");return t.some(r,(t=>e-t.queueTime>=n-1))}}},2298:()=>{const t="multipart/form-data",e=up.util;up.Request.XHRRenderer=class{constructor(t){this.request=t}buildAndSend(t){this.xhr=new XMLHttpRequest,this.params=e.copy(this.request.params),this.request.timeout&&(this.xhr.timeout=this.request.timeout),this.xhr.open(this.getMethod(),this.request.url);const n=this.request.metaProps();for(let t in n)this.addHeader(up.protocol.headerize(t),n[t]);for(let t in this.request.headers)this.addHeader(t,this.request.headers[t]);let r,s;(r=this.request.csrfHeader())&&(s=this.request.csrfToken())&&this.addHeader(r,s),this.addHeader(up.protocol.headerize("version"),up.version);let i=this.getContentType();return i&&this.addHeader("Content-Type",i),e.assign(this.xhr,t),this.xhr.send(this.getPayload()),this.xhr}getMethod(){return this.method||(this.method=this.request.method,this.request.wrapMethod&&!this.request.will302RedirectWithGET()&&(this.method=up.protocol.wrapMethod(this.method,this.params))),this.method}getContentType(){return this.finalizePayload(),this.contentType}getPayload(){return this.finalizePayload(),this.payload}addHeader(t,n){(e.isOptions(n)||e.isArray(n))&&(n=JSON.stringify(n)),this.xhr.setRequestHeader(t,n)}finalizePayload(){this.payloadFinalized||(this.payloadFinalized=!0,this.payload=this.request.payload,this.contentType=this.request.contentType,!this.payload&&this.request.allowsPayload()&&(this.contentType||(this.contentType=this.params.hasBinaryValues()?t:"application/x-www-form-urlencoded"),this.contentType===t?(this.contentType=null,this.payload=this.params.toFormData()):this.payload=this.params.toQuery().replace(/%20/g,"+")))}}},4517:()=>{up.Response=class extends up.Record{keys(){return["method","url","text","status","request","xhr","target","title","acceptLayer","dismissLayer","eventPlans","context","clearCache","headers"]}defaults(){return{headers:{}}}get ok(){return this.status&&this.status>=200&&this.status<=299}getHeader(t){return this.headers[t]||this.xhr?.getResponseHeader(t)}get contentType(){return this.getHeader("Content-Type")}get json(){return this.parsedJSON||(this.parsedJSON=JSON.parse(this.text))}}},7241:()=>{const t=up.util,e=up.element;up.ResponseDoc=class{constructor(t){this.noscriptWrapper=new up.HTMLWrapper("noscript"),this.scriptWrapper=new up.HTMLWrapper("script"),this.root=this.parseDocument(t)||this.parseFragment(t)||this.parseContent(t)}parseDocument(t){return this.parse(t.document,e.createDocumentFromHTML)}parseContent(n){let r=n.content||"";const s=n.target||up.fail("must pass a { target } when passing { content }"),i=e.createFromSelector(s);return t.isString(r)?(r=this.wrapHTML(r),i.innerHTML=r):i.appendChild(r),i}parseFragment(t){return this.parse(t.fragment)}parse(n,r=e.createFromHTML){return t.isString(n)&&(n=r(n=this.wrapHTML(n))),n}rootSelector(){return up.fragment.toTarget(this.root)}wrapHTML(t){return t=this.noscriptWrapper.wrap(t),up.fragment.config.runScripts?this.scriptWrapper.wrap(t):this.scriptWrapper.strip(t)}getTitle(){return this.titleParsed||(this.title=this.root.querySelector("head title")?.textContent,this.titleParsed=!0),this.title}select(t){return up.fragment.subtree(this.root,t,{layer:"any"})[0]}finalizeElement(t){this.noscriptWrapper.unwrap(t),this.scriptWrapper.unwrap(t)}}},2723:()=>{const t=up.element,e=up.util;up.RevealMotion=class{constructor(e,n={}){this.element=e,this.options=n;const r=up.viewport.config;this.viewport=t.get(this.options.viewport)||up.viewport.get(this.element),this.obstructionsLayer=up.layer.get(this.viewport),this.snap=this.options.snap??this.options.revealSnap??r.revealSnap,this.padding=this.options.padding??this.options.revealPadding??r.revealPadding,this.top=this.options.top??this.options.revealTop??r.revealTop,this.max=this.options.max??this.options.revealMax??r.revealMax,this.topObstructions=r.fixedTop,this.bottomObstructions=r.fixedBottom}start(){const t=this.getViewportRect(this.viewport),n=up.Rect.fromElement(this.element);if(this.max){const t=e.evalOption(this.max,this.element);n.height=Math.min(n.height,t)}if(this.addPadding(n),this.substractObstructions(t),t.height<0)return up.error.failed.async("Viewport has no visible area");const r=this.viewport.scrollTop;let s=r;return this.top||n.height>t.height?s+=n.top-t.top:n.top<t.top?s-=t.top-n.top:n.bottom>t.bottom&&(s+=n.bottom-t.bottom),e.isNumber(this.snap)&&s<this.snap&&n.top<.5*t.height&&(s=0),s!==r?this.scrollTo(s):Promise.resolve()}scrollTo(t){return this.scrollMotion=new up.ScrollMotion(this.viewport,t,this.options),this.scrollMotion.start()}getViewportRect(){return up.viewport.isRoot(this.viewport)?new up.Rect({left:0,top:0,width:up.viewport.rootWidth(),height:up.viewport.rootHeight()}):up.Rect.fromElement(this.viewport)}addPadding(t){t.top-=this.padding,t.height+=2*this.padding}selectObstructions(t){return up.fragment.all(t.join(","),{layer:this.obstructionsLayer})}substractObstructions(t){for(let e of this.selectObstructions(this.topObstructions)){let n=up.Rect.fromElement(e).bottom-t.top;n>0&&(t.top+=n,t.height-=n)}for(let e of this.selectObstructions(this.bottomObstructions)){let n=up.Rect.fromElement(e),r=t.bottom-n.top;r>0&&(t.height-=r)}}finish(){this.scrollMotion?.finish()}}},6956:()=>{const t=up.util;SPEED_CALIBRATION=.065,up.ScrollMotion=class{constructor(t,e,n={}){this.scrollable=t,this.targetTop=e,this.behavior=n.behavior??n.scrollBehavior??"auto",this.speed=(n.speed??n.scrollSpeed??up.viewport.config.scrollSpeed)*SPEED_CALIBRATION}start(){return new Promise(((t,e)=>{this.resolve=t,this.reject=e,"smooth"===this.behavior&&up.motion.isEnabled()?this.startAnimation():this.finish()}))}startAnimation(){this.startTime=Date.now(),this.startTop=this.scrollable.scrollTop,this.topDiff=this.targetTop-this.startTop,this.duration=Math.sqrt(Math.abs(this.topDiff))/this.speed,requestAnimationFrame((()=>this.animationFrame()))}animationFrame(){if(this.settled)return;this.frameTop&&Math.abs(this.frameTop-this.scrollable.scrollTop)>1.5&&this.abort("Animation aborted due to user intervention");const e=Date.now()-this.startTime,n=Math.min(e/this.duration,1);this.frameTop=this.startTop+t.simpleEase(n)*this.topDiff,Math.abs(this.targetTop-this.frameTop)<.3?this.finish():(this.scrollable.scrollTop=this.frameTop,requestAnimationFrame((()=>this.animationFrame())))}abort(t){this.settled=!0,this.reject(up.error.aborted(t))}finish(){this.settled=!0,this.scrollable.scrollTop=this.targetTop,this.resolve()}}},8720:()=>{const t=up.element,e=up.util;up.Selector=class{constructor(t,e=[]){this.selectors=t,this.filters=e,this.unionSelector=this.selectors.join(",")||"match-none"}matches(e){return t.matches(e,this.unionSelector)&&this.passesFilter(e)}closest(t){let e;return this.matches(t)?t:(e=t.parentElement)?this.closest(e):void 0}passesFilter(t){return e.every(this.filters,(e=>e(t)))}descendants(n){const r=e.flatMap(this.selectors,(e=>t.all(n,e)));return e.filter(r,(t=>this.passesFilter(t)))}subtree(t){const e=[];return this.matches(t)&&e.push(t),e.push(...this.descendants(t)),e}}},104:()=>{const t=up.util;up.store||(up.store={}),up.store.Memory=class{constructor(){this.clear()}clear(){this.data={}}get(t){return this.data[t]}set(t,e){this.data[t]=e}remove(t){delete this.data[t]}keys(){return Object.keys(this.data)}size(){return this.keys().length}values(){return t.values(this.data)}}},5438:()=>{up.store.Session=class extends up.store.Memory{constructor(t){super(),this.rootKey=t,this.loadFromSessionStorage()}clear(){super.clear(),this.saveToSessionStorage()}set(t,e){super.set(t,e),this.saveToSessionStorage()}remove(t){super.remove(t),this.saveToSessionStorage()}loadFromSessionStorage(){try{let t=sessionStorage?.getItem(this.rootKey);t&&(this.data=JSON.parse(t))}catch(t){}}saveToSessionStorage(){const t=JSON.stringify(this.data);try{return sessionStorage?.setItem(this.rootKey,t)}catch(t){}}}},7885:()=>{const t=up.util,e=up.element;up.Tether=class{constructor(t){up.migrate.handleTetherOptions?.(t),this.anchor=t.anchor,this.align=t.align,this.position=t.position,this.alignAxis="top"===this.position||"bottom"===this.position?"horizontal":"vertical",this.viewport=up.viewport.get(this.anchor),this.parent=this.viewport===e.root?document.body:this.viewport,this.syncOnScroll=!this.viewport.contains(this.anchor.offsetParent)}start(t){this.element=t,this.element.style.position="absolute",this.setOffset(0,0),this.sync(),this.changeEventSubscription("on")}stop(){this.changeEventSubscription("off")}changeEventSubscription(t){let e=this.scheduleSync.bind(this);up[t](window,"resize",e),this.syncOnScroll&&up[t](this.viewport,"scroll",e)}scheduleSync(){return clearTimeout(this.syncTimer),this.syncTimer=t.task(this.sync.bind(this))}isDetached(){return e.isDetached(this.parent)||e.isDetached(this.anchor)}sync(){const n=this.element.getBoundingClientRect(),r=e.styleNumber(this.element,"marginTop"),s=e.styleNumber(this.element,"marginRight"),i=e.styleNumber(this.element,"marginBottom"),o=e.styleNumber(this.element,"marginLeft"),a=this.anchor.getBoundingClientRect();let u,l;switch(this.alignAxis){case"horizontal":switch(this.position){case"top":l=a.top-i-n.height;break;case"bottom":l=a.top+a.height+r}switch(this.align){case"left":u=a.left+o;break;case"center":u=a.left+.5*(a.width-n.width);break;case"right":u=a.left+a.width-n.width-s}break;case"vertical":switch(this.align){case"top":l=a.top+r;break;case"center":l=a.top+.5*(a.height-n.height);break;case"bottom":l=a.top+a.height-n.height-i}switch(this.position){case"left":u=a.left-s-n.width;break;case"right":u=a.left+a.width+o}}t.isDefined(u)||t.isDefined(l)?this.moveTo(u,l):up.fail("Invalid tether constraints: %o",this.describeConstraints())}describeConstraints(){return{position:this.position,align:this.align}}moveTo(t,e){const n=this.element.getBoundingClientRect();this.setOffset(t-n.left+this.offsetLeft,e-n.top+this.offsetTop)}setOffset(t,n){this.offsetLeft=t,this.offsetTop=n,e.setStyle(this.element,{left:t,top:n})}}},4818:()=>{const t=up.util;up.URLPattern=class{constructor(e,n=t.normalizeURL){this.normalizeURL=n,this.groups=[];const r=[],s=[];for(let n of t.splitValues(e))"-"===n[0]?s.push(n.substring(1)):r.push(n);this.positiveRegexp=this.buildRegexp(r,!0),this.negativeRegexp=this.buildRegexp(s,!1)}buildRegexp(e,n){if(!e.length)return;let r=e.map(this.normalizeURL).map(t.escapeRegExp).join("|");return r=r.replace(/\\\*/g,".*?"),r=r.replace(/(\:|\\\$)([a-z][\w-]*)/gi,((t,e,r)=>"\\$"===e?(n&&this.groups.push({name:r,cast:Number}),"(\\d+)"):(n&&this.groups.push({name:r,cast:String}),"([^/?#]+)"))),new RegExp("^"+r+"$")}test(t,e=!0){return e&&(t=this.normalizeURL(t)),this.positiveRegexp.test(t)&&!this.isExcluded(t)}recognize(t,e=!0){e&&(t=this.normalizeURL(t));let n=this.positiveRegexp.exec(t);if(n&&!this.isExcluded(t)){const t={};return this.groups.forEach(((e,r)=>{let s=n[r+1];if(s)return t[e.name]=e.cast(s)})),t}}isExcluded(t){return this.negativeRegexp?.test(t)}}},9675:()=>{up.element=function(){const t=up.util,e=up.browser.isIE11()?"msMatchesSelector":"matches";function n(...t){const e=t.pop();return(t[0]||document).querySelector(e)}function r(...t){const e=t.pop();return(t[0]||document).querySelectorAll(e)}function s(t,e){const n=[];return o(t,e)&&n.push(t),n.push(...r(t,e)),n}function i(t,e){return t.closest?t.closest(e):o(t,e)?t:a(t,e)}function o(t,n){return t[e]?.(n)}function a(t,e){let n=t.parentElement;if(n)return o(n,e)?n:a(n,e)}function u(...e){const r=e.pop();return t.isElement(r)?r:t.isString(r)?n(...e,r):t.isList(r)?(r.length>1&&up.fail("up.element.get(): Cannot cast multiple elements (%o) to a single element",r),r[0]):r}function l(...e){return t.flatMap(e,c)}function c(e){return t.isString(e)?r(e):t.wrapList(e)}function p(t){t.style.display="none"}function h(t){t.style.display=""}function f(e,n){for(let r in n){const s=n[r];t.isGiven(s)?e.setAttribute(r,s):e.removeAttribute(r)}}function d(e,n){const r=[],s=e.replace(/\[([\w-]+)(?:[\~\|\^\$\*]?=(["'])?([^\2\]]*?)\2)?\]/g,(function(t,e,n,s){return r.push(s||""),`[${e}]`})).split(/[ >]+/);let i,o,a;for(let t of s){let n;if(t=t.replace(/^[\w-]+/,(function(t){return n=t,""})),o=document.createElement(n||"div"),i||(i=o),t=t.replace(/\#([\w-]+)/,(function(t,e){return o.id=e,""})),t=t.replace(/\.([\w-]+)/g,(function(t,e){return o.classList.add(e),""})),r.length&&(t=t.replace(/\[([\w-]+)\]/g,(function(t,e){return o.setAttribute(e,r.shift()),""}))),""!==t)throw up.error.invalidSelector(e);a?.appendChild(o),a=o}if(n){let e;if(e=t.pluckKey(n,"class"))for(let n of t.wrapList(e))i.classList.add(n);(e=t.pluckKey(n,"style"))&&F(i,e),(e=t.pluckKey(n,"text"))&&(i.textContent=e),(e=t.pluckKey(n,"content"))&&(i.innerHTML=e),f(i,n)}return i}const m=["HTML","BODY","HEAD","TITLE"],g=new RegExp("\\b("+m.join("|")+")\\b","i"),y=up.mockable((t=>o(t,m.join(","))));function b(t,e){return`[${t}="${e=e.replace(/"/g,'\\"')}"]`}function v(){return document.documentElement}function w(t){t.offsetHeight}function k(e,n,r){t.isMissing(e.getAttribute(n))&&e.setAttribute(n,r)}function E(e,n){return t.nullToUndefined(e.getAttribute(n))}function S(t,e,n){const r=E(t,e);switch(r){case"false":return!1;case"true":case"":case e:return!0;default:if(n)return r}}function L(t,e){const n=T(t,Object.keys(e));return F(t,e),()=>F(t,n)}function C(t,e){return R(window.getComputedStyle(t),e)}function x(e,n){const r=C(e,n);if(t.isGiven(r))return parseFloat(r)}function T(t,e){const{style:n}=t;return R(n,e)}function R(e,n){return t.isString(n)?e[n]:t.pick(e,n)}function F(t,e){const{style:n}=t;for(let t in e){let r=e[t];r=A(t,r),n[t]=r}}function A(e,n){var r;return t.isMissing(n)?n="":O.has(e.toLowerCase().replace(/-/,""))&&(r=n,n=t.isNumber(r)||t.isString(r)&&/^\d+$/.test(r)?r.toString()+"px":r),n}const O=t.arrayToSet(["top","right","bottom","left","padding","paddingtop","paddingright","paddingbottom","paddingleft","margin","margintop","marginright","marginbottom","marginleft","borderwidth","bordertopwidth","borderrightwidth","borderbottomwidth","borderleftwidth","width","height","maxwidth","maxheight","minwidth","minheight"]);function P(t){return!!(t.offsetWidth||t.offsetHeight||t.getClientRects().length)}return{all:r,subtree:s,isInSubtree:function(t,e){const n=u(e);return t.contains(n)},closest:i,closestAttr:function(t,e){return i(t,"["+e+"]")?.getAttribute(e)},matches:o,ancestor:a,around:function(t,e){return l(i(t,e),s(t,e))},get:u,list:l,remove:function(t){let e=t.parentNode;e&&e.removeChild(t)},toggle:function(t,e){null==e&&(e=!P(t)),(e?h:p)(t)},toggleClass:function(t,e,n){const r=t.classList;return null==n&&(n=!r.contains(e)),n?r.add(e):r.remove(e)},hide:p,show:h,metaContent:function(t){return n("meta"+b("name",t))?.getAttribute("content")},replace:function(t,e){t.parentElement.replaceChild(e,t)},insertBefore:function(t,e){t.insertAdjacentElement("beforebegin",e)},createFromSelector:d,setAttrs:f,setTemporaryAttrs:function(t,e){const n={};for(let r of Object.keys(e))n[r]=t.getAttribute(r);return f(t,e),()=>f(t,n)},affix:function(e,...n){let r,s;const i=t.extractOptions(n);2===n.length?[r,s]=n:(r="beforeend",s=n[0]);const o=d(s,i);return e.insertAdjacentElement(r,o),o},toSelector:function(...t){return up.fragment.toTarget(...t)},idSelector:function(t){return t.match(/^[a-z0-9\-_]+$/i)?`#${t}`:b("id",t)},classSelector:function(t){return`.${t=t.replace(/:/g,"\\:")}`},isSingleton:y,isSingletonSelector:function(t){return g.test(t)},attributeSelector:b,trueAttributeSelector:function(t){return`[${t}]:not([${t}=false])`},tagName:function(t){return t.tagName.toLowerCase()},createDocumentFromHTML:function(t){return(new DOMParser).parseFromString(t,"text/html")},createFromHTML:function(t){const e=document.createRange();return e.setStart(document.body,0),e.createContextualFragment(t).childNodes[0]},get root(){return v()},paint:w,concludeCSSTransition:function(t){const e=L(t,{transition:"none"});return w(t),e},hasCSSTransition:function(e){let n;n=t.isOptions(e)?e:C(e);const r=n.transitionProperty,s=n.transitionDuration;return!("none"===r||"all"===r&&0===s)},fixedToAbsolute:function(t){const e=t.getBoundingClientRect();t.style.position="absolute";const n=t.offsetParent.getBoundingClientRect();F(t,{left:e.left-x(t,"margin-left")-n.left,top:e.top-x(t,"margin-top")-n.top,right:"",bottom:""})},setMissingAttrs:function(t,e){for(let n in e)k(t,n,e[n])},setMissingAttr:k,unwrap:function(e){const n=e.parentNode,r=t.toArray(e.childNodes);t.each(r,(t=>n.insertBefore(t,e))),n.removeChild(e)},wrapChildren:function(t,e="up-wrapper"){let n;const r=d(e);for(;n=t.firstChild;)r.appendChild(n);return t.appendChild(r),r},attr:E,booleanAttr:S,numberAttr:function(t,e){let n=t.getAttribute(e);if(n&&(n=n.replace(/_/g,""),n.match(/^[\d\.]+$/)))return parseFloat(n)},jsonAttr:function(t,e){let n=t.getAttribute?.(e)?.trim();if(n)return JSON.parse(n)},callbackAttr:function(e,n,r=[]){let s=e.getAttribute(n);if(s){const n=new Function("event",...r,s);return function(s){const i=t.values(t.pick(s,r));return n.call(e,s,...i)}}},booleanOrStringAttr:function(t,e){return S(t,e,!0)},setTemporaryStyle:L,style:C,styleNumber:x,inlineStyle:T,setStyle:F,isVisible:P,upAttrs:function(t){const e=/^up-/,n={};for(let r of t.attributes){const{name:t}=r;t.match(e)&&(n[t]=r.value)}return n},toggleAttr:function(t,e,n,r){return null==r&&(r=!t.hasAttribute(e)),r?t.setAttribute(e,n):t.removeAttribute(e)},isDetached:function(t){return t!==document&&!v().contains(t)}}}()},3924:()=>{up.error=function(){const t=up.util;function e(e,n={}){t.isArray(e)&&(e=t.sprintf(...e));const r=new Error(e);return t.assign(r,n),r}function n(t,n=e){const r=function(...e){const r=n(...e);return r.name=t,r};return r.is=e=>e.name===t,r.async=(...t)=>Promise.reject(r(...t)),r}const r=n("up.Failed"),s=n("AbortError",(t=>e(t||"Aborted"))),i=n("up.NotImplemented"),o=n("up.NotApplicable",((t,n)=>e(`Cannot apply change: ${t} (${n})`)));return{failed:r,aborted:s,invalidSelector:n("up.InvalidSelector",(t=>e(`Cannot parse selector: ${t}`))),notApplicable:o,notImplemented:i,emitGlobal:function(t){const{message:e}=t;up.emit(window,"error",{message:e,error:t,log:!1})}}}()},8670:()=>{up.event=function(){const t=up.util,e=up.element;function n(...t){return r(t).bind()}function r(t,e){return up.EventListenerGroup.fromBindArgs(t,e)}function s(t){return up.EventEmitter.fromEmitArgs(t)}const i=["metaKey","shiftKey","ctrlKey","altKey"];function o(e){return(t.isUndefined(e.button)||0===e.button)&&!t.some(i,(t=>e[t]))}function a(e,n,r=[]){const s=up.event.build(n,t.pick(e,r));return s.originalEvent=e,["stopPropagation","stopImmediatePropagation","preventDefault"].forEach((function(t){const n=s[t];return s[t]=function(){return e[t](),n.call(s)}})),e.defaultPrevented&&s.preventDefault(),s}return n("up:click","a[up-emit]",(function(n,r){if(!o(n))return;const s=e.attr(r,"up-emit"),i=e.jsonAttr(r,"up-emit-props"),u=a(n,s);t.assign(u,i),up.emit(r,u)})),n("up:framework:reset",(function(){for(let t of[window,document,e.root,document.body])for(let e of up.EventListener.allNonDefault(t))e.unbind()})),{on:n,$on:function(...t){return r(t,{jQuery:!0}).bind()},off:function(...t){return r(t).unbind()},build:function(...e){const n=t.extractOptions(e),r=e[0]||n.type||up.fail("Expected event type to be passed as string argument or { type } property"),s=document.createEvent("Event");if(s.initEvent(r,!0,!0),t.assign(s,t.omit(n,["type","target"])),up.browser.isIE11()){const e=s.preventDefault;s.preventDefault=function(){return e.call(s),t.getter(s,"defaultPrevented",(()=>!0))}}return s},emit:function(...t){return s(t).emit()},assertEmitted:function(...t){return s(t).assertEmitted()},onEscape:function(t){return n("keydown",(function(e){if(function(t){const{key:e}=t;return"Escape"===e||"Esc"===e}(e))return t(e)}))},halt:function(t){t.stopImmediatePropagation(),t.preventDefault()},onReady:function(t){"loading"!==document.readyState?t():document.addEventListener("DOMContentLoaded",t)},isUnmodified:o,fork:a,keyModifiers:i}}(),up.on=up.event.on,up.$on=up.event.$on,up.off=up.event.off,up.$off=up.event.off,up.emit=up.event.emit},454:()=>{up.feedback=function(){const t=up.util,e=up.element,n=new up.Config((()=>({currentClasses:["up-current"],navSelectors:["[up-nav]","nav"]}))),r="up-active",s="a, [up-href]";function i(){return n.navSelectors.join(",")}function o(e){if(e)return t.normalizeURL(e,{stripTrailingSlash:!0})}function a(t){return t.upFeedbackURLs||(t.upFeedbackURLs=new up.LinkFeedbackURLs(t))}function u(n,r){const o=up.fragment.subtree(n,i(),r);l(t.flatMap(o,(t=>e.subtree(t,s))),r)}function l(t,r={}){if(!t.length)return;let s=(i=r.layer||up.layer.get(t[0])).feedbackLocation||i.location;var i;if(s)for(let r of t){const t=a(r).isCurrent(s);for(let s of n.currentClasses)e.toggleClass(r,s,t);e.toggleAttr(r,"aria-current","page",t)}}function c(t){return e.ancestor(t,s)||t}function p(t){c(t).classList.add(r)}function h(t){c(t).classList.remove(r)}function f(e,n){p(e);const r=n();return t.always(r,(()=>h(e))),r}function d(t){const e=t.feedbackLocation,n=o(t.location);e&&e===n||(t.feedbackLocation=n,u(t.element,{layer:t}))}return up.on("up:location:changed",(t=>{!function(){const t=up.layer.front;t.showsLiveHistory()&&d(t)}()})),up.on("up:fragment:inserted",((t,e)=>{!function(t){const e={layer:up.layer.get(t)};up.fragment.closest(t,i(),e)?l(up.fragment.subtree(t,s,e),e):u(t,e)}(e)})),up.on("up:layer:location:changed",(t=>{d(t.layer)})),up.on("up:framework:reset",(function(){n.reset()})),{config:n,start:p,stop:h,around:f,aroundForOptions:function(e,n){let r,s=e.feedback;return s&&(r=t.isBoolean(s)?e.origin:s),r?(r=up.fragment.get(r),f(r,n)):n()},normalizeURL:o}}()},2851:()=>{up.form=function(){const t=up.util,e=up.element,n=["[up-submit]","[up-target]","[up-layer]","[up-transition]"],r=new up.Config((()=>({validateTargets:["[up-fieldset]:has(:origin)","fieldset:has(:origin)","label:has(:origin)","form:has(:origin)"],fieldSelectors:["select","input:not([type=submit]):not([type=image])","button[type]:not([type=submit])","textarea"],submitSelectors:up.link.combineFollowableSelectors(["form"],n),noSubmitSelectors:["[up-submit=false]","[target]"],submitButtonSelectors:["input[type=submit]","input[type=image]","button[type=submit]","button:not([type])"],observeDelay:0})));let s;function i(){return r.submitSelectors.join(",")}function o(t=""){return r.fieldSelectors.map((e=>e+t)).join(",")}function a(n){n=e.get(n);let r=e.subtree(n,o());if(e.matches(n,"form[id]")){const s=o(e.attributeSelector("form",n.getAttribute("id"))),i=e.all(s);r.push(...i),r=t.uniq(r)}return r}function u(){return r.submitButtonSelectors.join(",")}const l=up.mockable(((t,e)=>up.render(c(t,e))));function c(n,r){r=t.options(r),n=up.fragment.get(n),n=e.closest(n,"form");const s=new up.OptionsParser(r,n),i=up.Params.fromForm(n);let o=function(t){const n=u(),r=document.activeElement;return r&&e.matches(r,n)&&t.contains(r)?r:e.get(t,n)}(n);return o&&(i.addField(o),r.method||(r.method=o.getAttribute("formmethod")),r.url||(r.url=o.getAttribute("formaction"))),i.addAll(r.params),r.params=i,s.string("url",{attr:"action",default:up.fragment.source(n)}),s.string("method",{attr:["up-method","data-method","method"],default:"GET",normalize:t.normalizeMethod}),"GET"===r.method&&(r.url=up.Params.stripURL(r.url)),s.string("failTarget",{default:up.fragment.toTarget(n)}),r.guardEvent||(r.guardEvent=up.event.build("up:form:submit",{log:"Submitting form"})),t.assign(r,up.link.followOptions(n,r)),r}up.on("up:click",u,(function(t,n){const r=e.closest(n,"form");r&&v(r)&&n.focus()}));const p=function(n,...s){n=e.list(n);const i=t.flatMap(n,a),o=t.extractCallback(s)||function(t){let e=t.getAttribute("up-observe");if(e)return new Function("value","name",e)}(n[0])||up.fail("up.observe: No change callback given"),u=t.extractOptions(s);u.delay=u.delay??e.numberAttr(n[0],"up-delay")??r.observeDelay;const l=new up.FieldObserver(i,u,o);return l.start(),()=>l.stop()};function h(t,e){return p(t,e,(()=>l(t)))}function f(n,s){return n=up.fragment.get(n),(s=t.options(s)).navigate=!1,s.origin=n,s.history=!1,s.target=function(n,s){let i;const o=y(n);return t.isElementish(s.target)?up.fragment.toTarget(s.target):(i=s.target||n.getAttribute("up-validate")||o.getAttribute("up-validate"))?i:e.matches(n,"form")?up.fragment.toTarget(n):function(e,n){const s=up.layer.get(e);return t.findResult(r.validateTargets,(function(t){if(up.fragment.get(t,{...n,layer:s}))return t}))}(n,s)||up.fail("Could not find validation target for %o (tried defaults %o)",n,r.validateTargets)}(n,s),s.focus="keep",s.fail=!1,s.headers||(s.headers={}),s.headers[up.protocol.headerize("validate")]=n.getAttribute("name")||":unknown",s.guardEvent=up.event.build("up:form:validate",{field:n,log:"Validating form"}),l(n,s)}function d(n){let r,s;if(e.matches(n,"input[type=checkbox]"))n.checked?(r=n.value,s=":checked"):s=":unchecked";else if(e.matches(n,"input[type=radio]")){const t=y(n),i=n.getAttribute("name"),o=t.querySelector(`input[type=radio]${e.attributeSelector("name",i)}:checked`);o?(s=":checked",r=o.value):s=":unchecked"}else r=n.value;const i=[];return t.isPresent(r)?(i.push(r),i.push(":present")):i.push(":blank"),t.isPresent(s)&&i.push(s),i}function m(t,n={}){const r=n.target||n.target||t.getAttribute("up-switch"),s=y(t);r||up.fail("No switch target given for %o",t);const i=d(t);for(let t of e.all(s,r))g(t,i)}const g=up.mockable((function(n,r){let s;r||(r=d(function(n){const r=y(n),s=e.all(r,"[up-switch]");return t.find(s,(function(t){const r=t.getAttribute("up-switch");return e.matches(n,r)}))||up.fail("Could not find [up-switch] field for %o",n)}(n)));let i=n.getAttribute("up-hide-for");if(i)i=t.splitValues(i),s=0===t.intersect(r,i).length;else{let e=n.getAttribute("up-show-for");e=e?t.splitValues(e):[":present",":checked"],s=t.intersect(r,e).length>0}return e.toggle(n,s),n.classList.add("up-switched")}));function y(t){return t.form||e.closest(t,`form, ${up.layer.anySelector()}`)}function b(t){return e.matches(t,o())}function v(t){return t=up.fragment.get(t),e.matches(t,i())&&!w(t)}function w(t){return e.matches(t,r.noSubmitSelectors.join(","))}return up.on("submit",i,(function(t,e){t.defaultPrevented||w(e)||(s?.(),up.event.halt(t),up.log.muteUncriticalRejection(l(e)))})),up.on("change","[up-validate]",(function(e){const n=a(e.target)[0];s=t.abortableMicrotask((()=>up.log.muteUncriticalRejection(f(n))))})),up.compiler("[up-switch]",(t=>{m(t)})),up.on("change","[up-switch]",((t,e)=>{m(e)})),up.compiler("[up-show-for]:not(.up-switched), [up-hide-for]:not(.up-switched)",(t=>{g(t)})),up.compiler("[up-observe]",(t=>p(t))),up.compiler("[up-autosubmit]",(t=>h(t))),up.on("up:framework:reset",(function(){r.reset()})),{config:r,submit:l,submitOptions:c,isSubmittable:v,observe:p,validate:f,autosubmit:h,fieldSelector:o,fields:a,focusedField:function(){return t.presence(document.activeElement,b)},switchTarget:g}}(),up.submit=up.form.submit,up.observe=up.form.observe,up.autosubmit=up.form.autosubmit,up.validate=up.form.validate},2667:(t,e,n)=>{n(8711);const r=up.util,s=up.element;up.fragment=function(){const t=new up.Config((()=>({badTargetClasses:[/^up-/],navigateOptions:{solo:!0,feedback:!0,cache:"auto",fallback:!0,focus:"auto",scroll:"auto",history:"auto",peel:!0},matchAroundOrigin:!0,runScripts:!1,autoHistoryTargets:[":main"],autoFocus:["hash","autofocus","main-if-main","target-if-lost"],autoScroll:["hash","layer-if-main"]})));function e(t,e={}){return t=f(t,e),s.closestAttr(t,"up-source")}r.delegate(t,"mainTargets",(()=>up.layer.config.any));const n=up.mockable(((...t)=>r.asyncify((function(){let e=v(t);e=up.RenderOptions.preprocess(e),up.browser.assertConfirmed(e);let n=r.pluckKey(e,"guardEvent");return n&&(n.renderOptions=e,up.event.assertEmitted(n,{target:e.origin})),up.RenderOptions.assertContentGiven(e),(e.url?i:o)(e)}))));function i(t){return up.feedback.aroundForOptions(t,(()=>new up.Change.FromURL(t).execute()))}function o(t){return up.network.mimicLocalRequest(t),new up.Change.FromContent(t).execute()}const a=up.mockable(((...t)=>{const e=v(t);return n({...e,navigate:!0})}));function u(t,e={}){t=f(t);const n=(e.keepPlans||[]).map((function(t){return c(t),t.oldElement}));return up.syntax.compile(t,{skip:n,layer:e.layer}),l(t,e),t}function l(t,e){return up.emit(t,"up:fragment:inserted",{log:["Inserted fragment %o",t],origin:e.origin})}function c(t){return p(t,"up:fragment:kept",{log:["Kept fragment %o",t.oldElement]})}function p(t,e,n){const r=t.oldElement,s=up.event.build(e,{newFragment:t.newElement,newData:t.newData});return up.emit(r,s,n)}const h=r.negate((function(t){return!!s.closest(t,".up-destroying")}));function f(...t){const e=r.extractOptions(t),n=t.pop(),i=t[0];return r.isElementish(n)?s.get(n):i?d(i,n,e):new up.FragmentFinder({selector:n,origin:e.origin,layer:e.layer}).find()}function d(...t){return g(...t)[0]}const m=/\:has\(([^\)]+)\)$/;function g(...t){const e=r.extractOptions(t);let n=t.pop();const s=t[0];return n=S(n,s,e),n.descendants(s||document)}function y(t,e,n={}){return(e=S(e,t,n)).subtree(t)}function b(t,e){return y(t,e).length>0}function v(t){const e=r.parseArgIntoOptions(t,"target");return r.isElement(e.target)&&(e.origin||(e.origin=e.target)),e}function w(t){if(r.isString(t))return t;let e;if(t=s.get(t),s.isSingleton(t))return s.tagName(t);if(e=t.getAttribute("up-id"))return s.attributeSelector("up-id",e);if(e=t.getAttribute("id"))return s.idSelector(e);if(e=t.getAttribute("name"))return s.tagName(t)+s.attributeSelector("name",e);if(e=r.presence(r.filter(t.classList,k))){let t="";for(let n of e)t+=s.classSelector(n);return t}return s.tagName(t)}function k(e){return!r.some(t.badTargetClasses,(function(t){return r.isRegExp(t)?t.test(e):t===e}))}function E(t,e={}){const{origin:n}=e;return t.replace(/&|:origin\b/,(function(e){if(n)return w(n);up.fail('Missing { origin } element to resolve "%s" reference (found in %s)',e,t)}))}function S(t,e,n={}){const i=[];n.destroying||i.push(h),n.layer||(n.layer=e);const o=up.layer.getAll(n);"any"===n.layer||e&&s.isDetached(e)||i.push((t=>r.some(o,(e=>e.contains(t)))));let a=up.fragment.expandTargets(t,{...n,layer:o[0]});return a=a.map((function(t){return(t=t.replace(m,(function(t,e){return i.push((t=>t.querySelector(e))),""})))||"*"})),new up.Selector(a,i)}return up.on("up:app:boot",(function(){const{body:t}=document;if(t.setAttribute("up-source",up.history.location),u(t),!up.browser.canPushState())return up.warn("Cannot push history changes. Next fragment update will load in a new page.")})),up.on("up:framework:reset",(function(){t.reset()})),{config:t,reload:function(...t){const r=v(t);r.target||(r.target=":main");const i=f(r.target,r);return r.url||(r.url=e(i)),r.headers||(r.headers={}),r.headers[up.protocol.headerize("reloadFromTime")]=function(t){return s.closestAttr(t,"up-time")||"0"}(i),n(r)},destroy:function(...t){const e=v(t);return(e.element=f(e.target,e))&&new up.Change.DestroyFragment(e).execute(),up.migrate.formerlyAsync?.("up.destroy()")},render:n,navigate:a,get:f,getDumb:d,all:g,subtree:y,contains:b,closest:function(t,e,n){return(e=S(e,t=s.get(t),n)).closest(t)},source:e,hello:u,visit:function(t,e){return a({...e,url:t})},markAsDestroying:function(t){t.classList.add("up-destroying"),t.setAttribute("aria-hidden","true")},emitInserted:l,emitDestroyed:function(t,e){const n=e.log??["Destroyed fragment %o",t],r=e.parent||document;return up.emit(r,"up:fragment:destroyed",{fragment:t,parent:r,log:n})},emitKeep:function(t){return p(t,"up:fragment:keep",{log:["Keeping fragment %o",t.oldElement],callback:s.callbackAttr(t.oldElement,"up-on-keep",["newFragment","newData"])})},emitKept:c,successKey:function(t){return r.unprefixCamelCase(t,"fail")},failKey:function(t){if(!t.match(/^fail[A-Z]/))return r.prefixCamelCase(t,"fail")},expandTargets:function(t,e={}){const{layer:n}=e;"new"===n||n instanceof up.Layer||up.fail("Must pass an up.Layer as { layer } option, but got %o",n),t=r.copy(r.wrapList(t));const s=[];for(;t.length;){const i=t.shift();if(":main"===i||!0===i){const r="new"===n?e.mode:n.mode;t.unshift(...up.layer.mainTargets(r))}else":layer"===i?"new"===n||n.opening||t.unshift(n.getFirstSwappableElement()):r.isElementish(i)?s.push(w(i)):r.isString(i)&&s.push(E(i,e))}return r.uniq(s)},toTarget:w,matches:function(t,e,n={}){return(e=S(e,t=s.get(t),n)).matches(t)},hasAutoHistory:function(e){return!!b(e,t.autoHistoryTargets)||(up.puts("up.render()","Will not auto-update history because fragment doesn't contain a selector from up.fragment.config.autoHistoryTargets"),!1)}}}(),up.reload=up.fragment.reload,up.destroy=up.fragment.destroy,up.render=up.fragment.render,up.navigate=up.fragment.navigate,up.hello=up.fragment.hello,up.visit=up.fragment.visit,r.delegate(up,"context",(()=>up.layer.current))},9634:()=>{up.framework=function(){let t=!0;return{boot:function(){let e=up.browser.supportIssue();e?console.error("Unpoly cannot load: %s",e):(up.emit("up:framework:boot",{log:!1}),t=!1,up.event.onReady((function(){up.emit("up:app:boot",{log:"Booting user application"})})))},startExtension:function(){t=!0},stopExtension:function(){t=!1},reset:function(){up.emit("up:framework:reset",{log:!1})},get booting(){return t}}}()},8944:()=>{up.history=function(){const t=up.util,e=up.element,n=new up.Config((()=>({enabled:!0,restoreTargets:["body"]})));let r,s;function i(e,n={}){return n.hash=!0,t.normalizeURL(e,n)}function o(t){return i(location.href,t)}function a(){const t=o();s!==t&&(r=s,s=t)}function u(t){const e={stripTrailingSlash:!0};return i(t,e)===o(e)}function l(e,n={}){c("replaceState",e)&&!1!==n.event&&h("up:location:changed",{url:e,reason:"replace",log:`Replaced state for ${t.urlWithoutHost(e)}`})}function c(t,e){if(n.enabled){const n={up:{}};return window.history[t](n,"",e),a(),!0}}function p(t){a(),up.viewport.saveScroll({location:r});const{state:e}=t;!async function(t){if(t?.up){let t=o();await up.render({url:t,history:!0,location:t,peel:!0,layer:"root",target:n.restoreTargets,cache:!0,keep:!1,scroll:"restore",saveScroll:!1}),t=o(),h("up:location:changed",{url:t,reason:"pop",log:`Restored location ${t}`})}else up.puts("pop","Ignoring a state not pushed by Unpoly (%o)",t)}(e)}function h(...e){return t.find(up.layer.stack.reversed(),"history").emit(...e)}function f(){window.history.scrollRestoration="manual",window.addEventListener("popstate",p),"GET"===up.protocol.initialRequestMethod()&&l(o(),{event:!1})}return a(),up.on("up:app:boot",(function(){"jasmine"in window?f():setTimeout(f,100)})),up.macro("a[up-back], [up-href][up-back]",(function(t){r&&(e.setMissingAttrs(t,{"up-href":r,"up-scroll":"restore"}),t.removeAttribute("up-back"),up.link.makeFollowable(t))})),up.on("up:framework:reset",(function(){n.reset(),r=void 0,s=void 0,a()})),{config:n,push:function(e){!u(e=i(e))&&c("pushState",e)&&up.emit("up:location:changed",{url:e,reason:"push",log:`Advanced to location ${t.urlWithoutHost(e)}`})},replace:l,get location(){return o()},get previousLocation(){return r},isLocation:u,normalizeURL:i}}()},9443:(t,e,n)=>{n(4432);const r=up.util,s=up.element;up.layer=function(){const t=[up.Layer.Root,up.Layer.Modal,up.Layer.Popup,up.Layer.Drawer,up.Layer.Cover],e=new up.Config((function(){const e={mode:"modal",any:{mainTargets:["[up-main='']","main",":layer"]},root:{mainTargets:["[up-main~=root]"],history:!0},overlay:{mainTargets:["[up-main~=overlay]"],openAnimation:"fade-in",closeAnimation:"fade-out",dismissLabel:"×",dismissAriaLabel:"Dismiss dialog",dismissable:!0,history:"auto"},cover:{mainTargets:["[up-main~=cover]"]},drawer:{mainTargets:["[up-main~=drawer]"],backdrop:!0,position:"left",size:"medium",openAnimation(t){switch(t.position){case"left":return"move-from-left";case"right":return"move-from-right"}},closeAnimation(t){switch(t.position){case"left":return"move-to-left";case"right":return"move-to-right"}}},modal:{mainTargets:["[up-main~=modal]"],backdrop:!0,size:"medium"},popup:{mainTargets:["[up-main~=popup]"],position:"bottom",size:"medium",align:"left",dismissable:"outside key"}};for(let n of t)e[n.mode].Class=n;return e}));let n=null,i=[];function o(t){return"root"===t?[e.root,e.any]:[e[t],e.overlay,e.any]}async function a(t){return t=r.options(t,{layer:"new",defaultToEmptyContent:!0,navigate:!0}),(await up.render(t)).layer}up.on("up:fragment:destroyed",(function(){n.sync()})),up.on("up:framework:boot",(function(){n=new up.LayerStack})),up.on("up:framework:reset",(function(){e.reset(),n.reset(),i=r.filter(i,"isDefault")}));const u={config:e,mainTargets:function(t){return r.flatMap(o(t),"mainTargets")},open:a,build:function(t,s){const{mode:i}=t,{Class:a}=e[i],u=r.reverse(o(i));let l=up.migrate.handleLayerConfig;return l&&u.forEach(l),t=r.mergeDefined(...u,{mode:i,stack:n},t),s&&(t=s(t)),new a(t)},ask:function(t){return new Promise((function(e,n){a(t={...t,onAccepted:t=>e(t.value),onDismissed:t=>n(t.value)})}))},normalizeOptions:function(t){if(up.migrate.handleLayerOptions?.(t),r.isGiven(t.layer)){let n=String(t.layer).match(/^(new|shatter|swap)( (\w+))?/);if(n){t.layer="new";const r=n[1],s=n[3];t.mode||(t.mode=s||e.mode),"swap"===r?up.layer.isOverlay()&&(t.baseLayer="parent"):"shatter"===r&&(t.baseLayer="root")}}else t.mode?t.layer="new":r.isElementish(t.target)?t.layer=n.get(t.target,{normalizeLayerOptions:!1}):t.origin?t.layer="origin":t.layer="current";t.context||(t.context={}),t.baseLayer=n.get("current",{...t,normalizeLayerOptions:!1})},openCallbackAttr:function(t,e){return s.callbackAttr(t,e,["layer"])},closeCallbackAttr:function(t,e){return s.callbackAttr(t,e,["layer","value"])},anySelector:function(){return r.map(t,(t=>t.selector())).join(",")},optionToString:function(t){return r.isString(t)?`layer "${t}"`:t.toString()},get stack(){return n}};return r.delegate(u,["get","getAll","root","overlays","current","front","sync","count","dismissOverlays"],(()=>n)),r.delegate(u,["accept","dismiss","isRoot","isOverlay","isFront","on","off","emit","parent","history","location","mode","context","element","contains","size","affix"],(()=>n.current)),u}()},3849:(t,e,n)=>{n(2065),up.link=function(){const t=up.util,e=up.element,n=new up.LinkPreloader;let r=null;const s=["a[up-content]","a[up-fragment]","a[up-document]"],i=["a[href]","[up-href]"],o=["[up-follow]","[up-target]","[up-layer]","[up-transition]","[up-preload]","[up-instant]"];function a(e,n){return t.flatMap(e,(t=>n.map((e=>t+e))))}const u=new up.Config((()=>({followSelectors:a(i,o).concat(s),noFollowSelectors:["[up-follow=false]","a[download]","a[target]",'a[href^="#"]:not([up-content]):not([up-fragment]):not([up-document])','a[href^="javascript:"]'],instantSelectors:["[up-instant]"],noInstantSelectors:["[up-instant=false]","[onclick]"],preloadSelectors:a(i,["[up-preload]"]),noPreloadSelectors:["[up-preload=false]"],clickableSelectors:s.concat(["[up-emit]","[up-accept]","[up-dismiss]","[up-clickable]"]),preloadDelay:90,preloadEnabled:"auto"})));function l(){return u.followSelectors.join(",")}function c(n){return e.matches(n,u.noFollowSelectors.join(","))||t.isCrossOrigin(n)}const p=up.mockable((function(t,e){return up.render(f(t,e))}));function h(e,n){n=t.options(n);const r=new up.OptionsParser(n,e);return n.url=function(t,e={}){const n=e.url||t.getAttribute("href")||t.getAttribute("up-href");if("#"!==n)return n}(e,n),n.method=d(e,n),r.json("headers"),r.json("params"),r.booleanOrString("cache"),r.booleanOrString("clearCache"),r.boolean("solo"),r.string("contentType",{attr:["enctype","up-content-type"]}),n}function f(t,n){n=h(t=up.fragment.get(t),n);const r=new up.OptionsParser(n,t,{fail:!0});return r.boolean("feedback"),r.boolean("fail"),null==r.options.origin&&(r.options.origin=t),r.boolean("navigate",{default:!0}),r.string("confirm"),r.string("target"),r.booleanOrString("fallback"),r.parse(((t,n)=>e.callbackAttr(t,n,["request","response","renderOptions"])),"onLoaded"),r.string("content"),r.string("fragment"),r.string("document"),r.boolean("peel"),r.string("layer"),r.string("baseLayer"),r.json("context"),r.string("mode"),r.string("align"),r.string("position"),r.string("class"),r.string("size"),r.booleanOrString("dismissable"),r.parse(up.layer.openCallbackAttr,"onOpened"),r.parse(up.layer.closeCallbackAttr,"onAccepted"),r.parse(up.layer.closeCallbackAttr,"onDismissed"),r.string("acceptEvent"),r.string("dismissEvent"),r.string("acceptLocation"),r.string("dismissLocation"),r.booleanOrString("history"),r.booleanOrString("focus"),r.boolean("saveScroll"),r.booleanOrString("scroll"),r.boolean("revealTop"),r.number("revealMax"),r.number("revealPadding"),r.number("revealSnap"),r.string("scrollBehavior"),r.booleanOrString("history"),r.booleanOrString("location"),r.booleanOrString("title"),r.booleanOrString("animation"),r.booleanOrString("transition"),r.string("easing"),r.number("duration"),up.migrate.parseFollowOptions?.(r),n.guardEvent||(n.guardEvent=up.event.build("up:link:follow",{log:"Following link"})),n}function d(e,n={}){return t.normalizeMethod(n.method||e.getAttribute("up-method")||e.getAttribute("data-method"))}function m(t){return t=up.fragment.get(t),e.matches(t,l())&&!c(t)}function g(t){m(t)||t.setAttribute("up-follow","")}function y(t){e.matches(t,"a[href], button")||(e.setMissingAttrs(t,{tabindex:"0",role:"link"}),t.addEventListener("keydown",(function(t){if("Enter"===t.key||"Space"===t.key)return w(t)})))}function b(t,n){if(t.defaultPrevented||c(n))return!1;const r=`a, [up-href], ${up.form.fieldSelector()}`,s=e.closest(t.target,r);return!s||s===n}function v(t){const n=e.closest(t,u.instantSelectors.join(","));return n&&(r=n,!(e.matches(r,u.noInstantSelectors.join(","))||c(r)));var r}function w(t){let e=["clientX","clientY","button",...up.event.keyModifiers];const n=up.event.fork(t,"up:click",e);up.emit(t.target,n,{log:!1})}return up.macro((function(){return u.clickableSelectors.join(",")}),y),up.on("up:click",l,(function(t,e){b(t,e)&&(up.event.halt(t),up.log.muteUncriticalRejection(p(e)))})),up.macro("[up-expand]",(function(t){const n=t.getAttribute("up-expand")||"a, [up-href]";let r=e.get(t,n);if(r){const n=e.upAttrs(r);n["up-href"]||(n["up-href"]=r.getAttribute("href")),e.setMissingAttrs(t,n),g(t)}})),up.compiler((function(){return u.preloadSelectors.join(",")}),(function(t){(function(t){return!up.browser.canPushState()||e.matches(t,u.noPreloadSelectors.join(","))||c(t)||!function(t){const e=h(t);if(e.url)return null==e.cache&&(e.cache="auto"),e.basic=!0,new up.Request(e).willCache()}(t)})(t)||n.observeLink(t)})),up.on("up:framework:reset",(function(){r=null,u.reset(),n.reset()})),{follow:p,followOptions:f,preload:function(t,e){if(t=up.fragment.get(t),!function(){const t=u.preloadEnabled;return"auto"===t?!up.network.shouldReduceRequests():t}())return up.error.failed.async("Link preloading is disabled");const n=up.event.build("up:link:preload",{log:["Preloading link %o",t]});return p(t,{...e,guardEvent:n,preload:!0})},makeFollowable:g,makeClickable:y,isSafe:function(t){const e=d(t);return up.network.isSafeMethod(e)},isFollowable:m,shouldFollowEvent:b,followMethod:d,convertClicks:function(t){t.on("click",(function(e,n){if(up.event.isUnmodified(e))return v(n)&&r?up.event.halt(e):t.wasHitByMouseEvent(e)&&(!r||r===e.target)&&w(e),r=null})),t.on("mousedown",(function(t,e){up.event.isUnmodified(t)&&(r=t.target,v(e)&&w(t))}))},config:u,combineFollowableSelectors:a}}(),up.follow=up.link.follow},4453:()=>{up.log=function(){const t=new up.store.Session("up.log"),e=new up.Config((()=>({enabled:t.get("enabled"),banner:!0}))),n=(...t)=>r("error",...t);function r(t,e,n,...r){n&&(up.browser.canFormatLog()?(r.unshift(""),r.unshift("color: #666666; padding: 1px 3px; border: 1px solid #bbbbbb; border-radius: 2px; font-size: 90%; display: inline-block"),n=`%c${e}%c ${n}`):n=`[${e}] ${n}`,console[t](n,...r))}function s(n){t.set("enabled",n),e.enabled=n}return up.on("up:app:boot",(function(){if(!e.banner)return;const t=` __ _____ ___ ___ / /_ __\n/ // / _ \\/ _ \\/ _ \\/ / // / ${up.version}\n\\___/_//_/ .__/\\___/_/\\_. / \n / / / /\n\n`;let n="";up.migrate.loaded||(n+="Load unpoly-migrate.js to enable deprecated APIs.\n\n"),e.enabled?n+="Call `up.log.disable()` to disable logging for this session.":n+="Call `up.log.enable()` to enable logging for this session.";const r="color: #777777";up.browser.canFormatLog()?console.log("%c"+t+"%c"+n,"font-family: monospace;"+r,r):console.log(t+n)})),up.on("up:framework:reset",(function(){e.reset()})),{puts:function(...t){e.enabled&&r("log",...t)},error:n,warn:(...t)=>r("warn",...t),config:e,enable:function(){s(!0)},disable:function(){s(!1)},fail:function(...t){throw n("error",...t),up.error.failed(t)},muteUncriticalRejection:function(t){return t.catch((function(t){if("object"!=typeof t||!("AbortError"===t.name||t instanceof up.RenderResult||t instanceof up.Response))throw t}))},isEnabled:()=>e.enabled}}(),up.puts=up.log.puts,up.warn=up.log.warn,up.fail=up.log.fail},6535:()=>{up.migrate={config:{}}},8374:()=>{up.mockable=function(t){let e;const n=function(){return(e||t).apply(null,arguments)};return n.mock=()=>e=jasmine.createSpy("mockable",t),document.addEventListener("up:framework:reset",(()=>e=null)),n}},4034:()=>{up.motion=function(){const t=up.util,e=up.element;let n={},r={};const s=new up.MotionController("motion"),i=new up.Config((()=>({duration:175,easing:"ease",enabled:!matchMedia("(prefers-reduced-motion: reduce)").matches})));function o(e){return t.pickBy(e,(t=>t.isDefault))}function a(){return i.enabled}function u(t,n,r){return c(r),a()&&!y(n)&&r.duration>0&&!e.isSingleton(t)}function l(t,e,n){return n={...n,finishEvent:s.finishEvent},new up.CSSTransition(t,e,n).start()}function c(t){t.easing||(t.easing=i.easing),t.duration||(t.duration=i.duration)}function p(e){if(!y(e)){if(t.isFunction(e))return e;if(t.isArray(e))return h(...e);if(!t.isString(e))return up.fail("Unknown transition %o",e);{let t;if(e.indexOf("/")>=0)return h(...e.split("/"));if(t=r[e])return p(t)}}}function h(e,n){if(!y(e)&&!y(n)){const r=f(e)||t.asyncNoop,s=f(n)||t.asyncNoop;return(t,e,n)=>Promise.all([r(t,n),s(e,n)])}}function f(e){return y(e)?void 0:t.isFunction(e)?e:t.isString(e)?n[r=e]||up.fail("Unknown animation %o",r):t.isOptions(e)?(t,n)=>l(t,e,n):up.fail("Unknown animation %o",e);var r}const d=up.mockable((function(t,n){e.replace(t,n)}));function m(t,e){const n=p(e);n.isDefault=up.framework.booting,r[t]=n}function g(t,e){const r=f(e);r.isDefault=up.framework.booting,n[t]=r}function y(t){return!t||"none"===t}function b(t,n,r){g(t,(function(t,s){return t.style.opacity=0,e.setStyle(t,{opacity:n}),l(t,{opacity:r},s)}))}function v(t,e){return{transform:`translate(${t}px, ${e}px)`}}function w(t){return e.setStyle(t,v(0,0)),t.getBoundingClientRect()}function k(t,n){const r=`move-from-${t}`;g(`move-to-${t}`,(function(t,e){const r=w(t);return l(t,n(r),e)})),g(r,(function(t,r){const s=w(t),i=n(s);return e.setStyle(t,i),l(t,v(0,0),r)}))}return b("fade-in",0,1),b("fade-out",1,0),k("top",(function(t){return v(0,-(t.top+t.height))})),k("bottom",(function(t){return v(0,up.viewport.rootHeight()-t.top)})),k("left",(function(t){return v(-(t.left+t.width),0)})),k("right",(function(t){return v(up.viewport.rootWidth()-t.left,0)})),m("cross-fade",["fade-out","fade-in"]),m("move-left",["move-to-left","move-from-right"]),m("move-right",["move-to-right","move-from-left"]),m("move-up",["move-to-top","move-from-bottom"]),m("move-down",["move-to-bottom","move-from-top"]),up.on("up:framework:boot",(function(){a()||up.puts("up.motion","Animations are disabled")})),up.on("up:framework:reset",(function(){s.reset(),n=o(n),r=o(r),i.reset()})),{morph:function(n,r,i,o){c(o=t.options(o)),n=up.fragment.get(n),r=up.fragment.get(r);const a=p(i),l=u(n,a,o),h=t.pluckKey(o,"beforeStart")||t.noop,f=t.pluckKey(o,"afterInsert")||t.noop,m=t.pluckKey(o,"beforeDetach")||t.noop,g=t.pluckKey(o,"afterDetach")||t.noop,y=t.pluckKey(o,"scrollNew")||t.asyncNoop;if(h(),l){if(s.isActive(n)&&!1===o.trackMotion)return a(n,r,o);up.puts("up.morph()","Morphing %o to %o with transition %O",n,r,i);const t=up.viewport.get(n),u=t.scrollTop,l=up.viewport.absolutize(n,{afterMeasure(){e.insertBefore(n,r),f()}}),c=async function(){await y();const s=t.scrollTop;l.moveBounds(0,s-u),await a(n,r,o),m(),e.remove(l.bounds),g()};return s.startFunction([n,r],c,o)}return m(),d(n,r),f(),g(),y()},animate:function(n,r,i){n=up.fragment.get(n),i=t.options(i);const o=f(r);if(u(n,r,i)){const t=()=>o(n,i);return s.startFunction(n,t,i)}return function(n,r){return t.isOptions(r)&&e.setStyle(n,r),Promise.resolve()}(n,r)},finish:function(t){return s.finish(t)},finishCount:()=>s.finishCount,transition:m,animation:g,config:i,isEnabled:a,isNone:y,willAnimate:u,swapElementsDirectly:d}}(),up.transition=up.motion.transition,up.animation=up.motion.animation,up.morph=up.motion.morph,up.animate=up.motion.animate},1647:(t,e,n)=>{n(35);const r=up.util;up.network=function(){const t=new up.Config((()=>({concurrency:4,wrapMethod:!0,cacheSize:70,cacheExpiry:3e5,badDownlink:.6,badRTT:750,badResponseTime:400,autoCache:t=>t.isSafe(),clearCache:(t,e)=>!t.isSafe(),requestMetaKeys:["target","failTarget","mode","failMode","context","failContext"],progressBar:!0}))),e=new up.Request.Queue,n=new up.Request.Cache;let s=null;function i(){return e.isBusy()}const o=r.negate(i);function a(...t){e.abort(...t)}return up.on("up:request:late",(function(){r.evalOption(t.progressBar)&&(s=new up.ProgressBar)})),up.on("up:request:recover",(function(){s?.conclude()})),up.on("up:framework:reset",(function(){a(),e.reset(),t.reset(),n.clear(),s?.destroy(),s=null})),{request:function(...s){const i=new up.Request(function(t){const e=r.extractOptions(t);return e.url||(e.url=t[0]),up.migrate.handleRequestOptions?.(e),e}(s));(function(t){let r;if(t.willCache()&&(r=n.get(t)))return up.puts("up.request()","Re-using previous request to %s %s",t.method,t.url),t.preload||e.promoteToForeground(r),t.followState(r),!0})(i)||function(s){s.preload&&!s.isSafe()&&up.fail("Will not preload request to %s",s.description),function(e){e.willCache()&&n.set(e,e),r.always(e,(function(r){let s=r.clearCache??e.clearCache??t.clearCache(e,r);s&&n.clear(s),(e.willCache()||n.get(e))&&n.set(e,e),r.ok||n.remove(e)}))}(s),e.asap(s)}(i);let o=i.solo;return o&&e.abortExcept(i,o),i},cache:n,isIdle:o,isBusy:i,isSafeMethod:function(t){return r.contains(["GET","OPTIONS","HEAD"],r.normalizeMethod(t))},config:t,abort:a,registerAliasForRedirect:function(t,e){if(t.cache&&e.url&&t.url!==e.url){const r=t.variant({method:e.method,url:e.url});n.alias(t,r)}},queue:e,shouldReduceRequests:function(){let e=navigator.connection;if(e)return e.saveData||e.rtt&&e.rtt>t.badRTT||e.downlink&&e.downlink<t.badDownlink},mimicLocalRequest:function(t){let e=t.solo;e&&a(e);let r=t.clearCache;r&&n.clear(r)}}}(),up.request=up.network.request,up.cache=up.network.cache},3535:()=>{up.protocol=function(){const t=up.util,e=up.element,n=function(t){return"X-Up"+t.replace(/(^.|[A-Z])/g,(t=>"-"+t.toUpperCase()))},r=function(e,r,s=t.identity){let i=e.getResponseHeader(n(r));if(i)return s(i)};function s(t){switch(t){case"true":return!0;case"false":return!1;default:return t}}const i=t.memoize((function(){return t.normalizeMethod(up.browser.popCookie("_up_method"))})),o=new up.Config((()=>({methodParam:"_method",csrfParam:()=>e.metaContent("csrf-param"),csrfToken:()=>e.metaContent("csrf-token"),csrfHeader:"X-CSRF-Token"})));function a(){o.reset()}return up.on("up:framework:reset",a),{config:o,reset:a,locationFromXHR:function(t){return r(t,"location")||t.responseURL},titleFromXHR:function(t){return r(t,"title")},targetFromXHR:function(t){return r(t,"target")},methodFromXHR:function(e){return r(e,"method",t.normalizeMethod)},acceptLayerFromXHR:function(t){return r(t,"acceptLayer",JSON.parse)},contextFromXHR:function(t){return r(t,"context",JSON.parse)},dismissLayerFromXHR:function(t){return r(t,"dismissLayer",JSON.parse)},eventPlansFromXHR:function(t){return r(t,"events",JSON.parse)},clearCacheFromXHR:function(t){return r(t,"clearCache",s)},csrfHeader:function(){return t.evalOption(o.csrfHeader)},csrfParam:function(){return t.evalOption(o.csrfParam)},csrfToken:function(){return t.evalOption(o.csrfToken)},initialRequestMethod:i,headerize:n,wrapMethod:function(t,e){return e.add(o.methodParam,t),"POST"}}}()},9615:()=>{up.radio=function(){const t=up.util,e=up.element,n=new up.Config((()=>({hungrySelectors:["[up-hungry]"],pollInterval:3e4,pollEnabled:"auto"})));function r(r,s={}){const i=s.interval??e.numberAttr(r,"up-interval")??n.pollInterval;let o=!1,a=null;function u(){o||(function(e){const r=t.evalOption(n.pollEnabled,e);return"auto"===r?!document.hidden&&!up.network.shouldReduceRequests()&&up.layer.get(e)?.isFront?.():r}(r)?t.always(up.reload(r,s),l):(up.puts("[up-poll]","Polling is disabled"),l(Math.min(1e4,i))))}function l(t=i){o||setTimeout(u,t)}function c(){o=!0,a?.abort()}return s.onQueued=t=>a=t,up.on(r,"up:poll:stop",c),l(),c}return up.compiler("[up-poll]",r),up.on("up:framework:reset",(function(){n.reset()})),{config:n,hungrySelector:function(){return n.hungrySelectors.join(",")},startPolling:r,stopPolling:function(t){up.emit(t,"up:poll:stop")}}}()},6774:()=>{up.rails=function(){const t=up.util,e=up.element;return t.each(["method","confirm"],(function(t){const n=`data-${t}`,r=`up-${t}`;up.macro(`a[${n}]`,(function(t){if((window._rails_loaded||window.Rails||window.jQuery?.rails)&&up.link.isFollowable(t))return e.setMissingAttr(t,r,t.getAttribute(n)),t.removeAttribute(n)}))}))}()},2514:()=>{up.syntax=function(){const t=up.util,e=up.element,n={"[up-back]":-100,"[up-content]":-200,"[up-drawer]":-200,"[up-modal]":-200,"[up-cover]":-200,"[up-popup]":-200,"[up-tooltip]":-200,"[up-dash]":-200,"[up-expand]":-300,"[data-method]":-400,"[data-confirm]":-400};let r=[],s=[];function i(...t){const e=a(t);return u(r,e)}function o(...e){const r=a(e);return up.framework.booting&&(r.priority=function(e){e=t.evalOption(e);for(let t in n){const r=n[t];if(e.indexOf(t)>=0)return r}}(r.selector)||up.fail("Unregistered priority for system macro %o",r.selector)),u(s,r)}function a(e){let[n,r,s]=function(e){const n=e.shift(),r=e.pop();return[n,t.extractOptions(e),r]}(e);return r=t.options(r,{selector:n,isDefault:up.framework.booting,priority:0,batch:!1,keep:!1,jQuery:!1}),t.assign(s,r)}function u(t,e){let n,r=0;for(;(n=t[r])&&n.priority>=e.priority;)r+=1;return t.splice(r,0,e),e}return up.on("up:framework:reset",(function(){r=t.filter(r,"isDefault"),s=t.filter(s,"isDefault")})),{compiler:i,macro:o,$compiler:function(...t){i(...t).jQuery=!0},$macro:function(...t){const e=o(...t);return e.jQuery=!0,e},destructor:function(e,n){let r=e.upDestructors;r||(r=[],e.upDestructors=r,e.classList.add("up-can-clean")),t.isArray(n)?r.push(...n):r.push(n)},compile:function(t,e){const n=s.concat(r);new up.CompilerPass(t,n,e).run()},clean:function(t,e={}){new up.DestructorPass(t,e).run()},data:function(t){return t=up.fragment.get(t),e.jsonAttr(t,"up-data")||{}}}}(),up.compiler=up.syntax.compiler,up.$compiler=up.syntax.$compiler,up.destructor=up.syntax.destructor,up.macro=up.syntax.macro,up.$macro=up.syntax.$macro,up.data=up.syntax.data},7924:()=>{up.util=function(){function t(){}const e={host:"cross-domain",stripTrailingSlash:!1,search:!0,hash:!1};function n(t,n){n=H(n,e);const r=o(t);let s="";var a,u;"cross-domain"===n.host&&(n.host=i(r)),n.host&&(s+=r.protocol+"//"+r.hostname,a=r.protocol,(""===(u=(u=r.port).toString())||"80"===u)&&"http:"===a||"443"===u&&"https:"===a||(s+=`:${r.port}`));let{pathname:l}=r;return n.stripTrailingSlash&&(l=l.replace(/\/$/,"")),s+=l,n.search&&(s+=r.search),n.hash&&(s+=r.hash),s}const r=location.protocol,s=location.hostname;function i(t){if(k(t)&&-1===t.indexOf("//"))return!1;const e=o(t);return s!==e.hostname||r!==e.protocol}function o(t){let e;return T(t)?e=up.element.get(t):t.pathname?e=t:(e=document.createElement("a"),e.href=t),e.hostname||(e.href=e.href),"/"!==e.pathname[0]&&(e=I(e,["protocol","hostname","port","pathname","search","hash"]),e.pathname="/"+e.pathname),e}function a(t,...e){for(let n of e)for(let e in n)t[e]=n[e];return t}const u=Object.assign||a,l=Object.values||function(t){return Object.keys(t).map((e=>t[e]))};function c(t){return k(t)?e=>e[t]:t}function p(t,e){if(0===t.length)return[];e=c(e);let n=[];for(let r=0;r<t.length;r++){let s=t[r];n.push(e(s,r))}return n}function h(t,e){for(let n=0;n<t.length;n++)e(t[n],n)}function f(t){return null===t}function d(t){return void 0===t}const m=ut(d);function g(t){return d(t)||f(t)}const y=ut(g);function b(t){return!!g(t)||(L(t)&&t[b.key]?t[b.key]():k(t)||F(t)?0===t.length:!!S(t)&&0===Object.keys(t).length)}b.key="up.util.isBlank";const v=ut(b);function w(t){return"function"==typeof t}function k(t){return"string"==typeof t||t instanceof String}function E(t){return"number"==typeof t||t instanceof Number}function S(t){return"object"==typeof t&&!f(t)&&(d(t.constructor)||t.constructor===Object)}function L(t){const e=typeof t;return"object"===e&&!f(t)||"function"===e}function C(t){return t instanceof Element}function x(t){return t instanceof RegExp}function T(t){return up.browser.canJQuery()&&t instanceof jQuery}const{isArray:R}=Array;function F(t){return R(t)||A(t)||O(t)||T(t)||function(t){return t instanceof HTMLCollection}(t)}function A(t){return t instanceof NodeList}function O(t){return"[object Arguments]"===Object.prototype.toString.call(t)}function P(t){return F(t)?t:g(t)?[]:[t]}function q(t){return L(t)&&t[q.key]?t=t[q.key]():F(t)?t=D(t):S(t)&&(t=u({},t)),t}function D(t){return Array.prototype.slice.call(t)}function M(...t){return u({},...t)}function H(t,e){return e?M(e,t):t?q(t):{}}function j(t,e){e=c(e);for(let n=0;n<t.length;n++){const r=e(t[n],n);if(r)return r}}function N(t,e){e=c(e);let n=!0;for(let r=0;r<t.length;r++)if(!e(t[r],r)){n=!1;break}return n}function $(t){const e=[];return t.forEach((t=>e.push(t))),e}function B(t){const e=new Set;return t.forEach((t=>e.add(t))),e}function z(t,e){e=c(e);const n=[];return h(t,(function(t,r){if(e(t,r))return n.push(t)})),n}function U(t){return Promise.resolve().then(t)}function K(t){return t[t.length-1]}function V(t,e){return t.indexOf(e)>=0}function I(t,e){const n={};for(let r of e)r in t&&(n[r]=t[r]);return n}function W(t,e){e=c(e);const n={};for(let r in t)e(t[r],r,t)&&(n[r]=t[r]);return n}q.key="up.util.copy",Date.prototype[q.key]=function(){return new Date(+this)};const Q={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;"};function _(t,e){const n=t[e];return delete t[e],n}function X(t,e){if(e(K(t)))return t.pop()}function G(t){return X(t,S)||{}}function J(t){return t}function Y(t){const e=[];for(let n of t)F(n)?e.push(...n):e.push(n);return e}function Z(e){return e?.catch(t)}function tt(t,e){if(t?.valueOf&&(t=t.valueOf()),e?.valueOf&&(e=e.valueOf()),typeof t!=typeof e)return!1;if(F(t)&&F(e))return et(t,e);if(L(t)&&t[tt.key])return t[tt.key](e);if(S(t)&&S(e)){const n=Object.keys(t);return!!et(n,Object.keys(e))&&N(n,(n=>tt(t[n],e[n])))}return t===e}function et(t,e){return t.length===e.length&&N(t,((t,n)=>tt(t,e[n])))}tt.key="up.util.isEqual";let nt=0;function rt(t){return t[0].toLowerCase()+t.slice(1)}function st(t){return t[0].toUpperCase()+t.slice(1)}function it(t){let e,n="";if(k(t))e=t.replace(/[\n\r\t ]+/g," "),e=e.replace(/^[\n\r\t ]+/,""),e=e.replace(/[\n\r\t ]$/,"");else if(d(t))e="undefined";else if(E(t)||w(t))e=t.toString();else if(R(t))e=`[${p(t,it).join(", ")}]`,n="]";else if(T(t))e=`$(${p(t,it).join(", ")})`,n=")";else if(C(t)){e=`<${t.tagName.toLowerCase()}`;for(let n of["id","name","class"]){let r=t.getAttribute(n);r&&(e+=` ${n}="${r}"`)}e+=">",n=">"}else if(x(t))e=t.toString();else try{e=JSON.stringify(t)}catch(t){if("TypeError"!==t.name)throw t;e="(circular structure)"}return e.length>200&&(e=`${e.substr(0,200)} …`,e+=n),e}const ot=/\%[oOdisf]/g;function at(t,e,...n){if(!e)return"";let r=0;return e.replace(ot,(function(){let e=n[r];return e=t(it(e)),r+=1,e}))}function ut(t){return function(...e){return!t(...e)}}return{parseURL:o,normalizeURL:n,urlWithoutHost:function(t){return n(t,{host:!1})},matchURLs:function(t,e){return n(t)===n(e)},normalizeMethod:function(t){return t?t.toUpperCase():"GET"},methodAllowsPayload:function(t){return"GET"!==t&&"HEAD"!==t},assign:u,assignPolyfill:a,copy:q,copyArrayLike:D,merge:M,mergeDefined:function(...t){const e={};for(let n of t)if(n)for(let t in n){const r=n[t];m(r)&&(e[t]=r)}return e},options:H,parseArgIntoOptions:function(t,e){let n=G(t);return m(t[0])&&(n=q(n),n[e]=t[0]),n},each:h,eachIterator:function(t,e){let n;for(;(n=t.next())&&!n.done;)e(n.value)},map:p,flatMap:function(t,e){return Y(p(t,e))},mapObject:function(t,e){return p(t,e).reduce((function(t,e){return t[e[0]]=e[1],t}),{})},findResult:j,some:function(t,e){return!!j(t,e)},every:N,find:function(t,e){let n;e=c(e);for(let r of t)if(e(r)){n=r;break}return n},filter:z,reject:function(t,e){return z(t,e=ut(c(e)))},intersect:function(t,e){return z(t,(t=>V(e,t)))},compact:function(t){return z(t,y)},compactObject:function(t){return W(t,y)},uniq:function(t){return t.length<2?t:$(B(t))},uniqBy:function(t,e){if(t.length<2)return t;e=c(e);const n=new Set;return z(t,(function(t,r){const s=e(t,r);return!n.has(s)&&(n.add(s),!0)}))},last:K,isNull:f,isDefined:m,isUndefined:d,isGiven:y,isMissing:g,isPresent:v,isBlank:b,presence:function(t,e=v){if(e(t))return t},isObject:L,isFunction:w,isString:k,isBoolean:function(t){return"boolean"==typeof t||t instanceof Boolean},isNumber:E,isElement:C,isJQuery:T,isElementish:function(t){return!(!t||!t.addEventListener&&!t[0]?.addEventListener)},isPromise:function(t){return L(t)&&w(t.then)},isOptions:S,isArray:R,isFormData:function(t){return t instanceof FormData},isNodeList:A,isArguments:O,isList:F,isRegExp:x,timer:function(t,e){return setTimeout(e,t)},contains:V,objectContains:function(t,e){return tt(e,I(t,Object.keys(e)))},toArray:function(t){return R(t)?t:D(t)},pick:I,pickBy:W,omit:function(t,e){return W(t,((t,n)=>!V(e,n)))},unresolvablePromise:function(){return new Promise(t)},remove:function(t,e){const n=t.indexOf(e);if(n>=0)return t.splice(n,1),e},memoize:function(t){let e,n;return function(...r){return n?e:(n=!0,e=t.apply(this,r))}},pluckKey:_,renameKey:function(t,e,n){return t[n]=_(t,e)},extractOptions:G,extractCallback:function(t){return X(t,w)},noop:t,asyncNoop:function(){return Promise.resolve()},identity:J,escapeHTML:function(t){return t.replace(/[&<>"']/g,(t=>Q[t]))},escapeRegExp:function(t){return t.replace(/[\\^$*+?.()|[\]{}]/g,"\\$&")},sequence:function(t){return 1===t.length?t[0]:()=>p(t,(t=>t()))},evalOption:function(t,...e){return w(t)?t(...e):t},flatten:Y,isTruthy:function(t){return!!t},newDeferred:function(){let t,e;const n=new Promise((function(n,r){t=n,e=r}));return n.resolve=t,n.reject=e,n.promise=()=>n,n},always:function(t,e){return t.then(e,e)},muteRejection:Z,asyncify:function(t){try{return Promise.resolve(t())}catch(t){return Promise.reject(t)}},isBasicObjectProperty:function(t){return Object.prototype.hasOwnProperty(t)},isCrossOrigin:i,task:function(t){return setTimeout(t)},microtask:U,abortableMicrotask:function(t){let e=!1;return U((function(){if(!e)return t()})),()=>e=!0},isEqual:tt,splitValues:function(t,e=" "){return k(t)?t=z(t=p(t=t.split(e),(t=>t.trim())),v):P(t)},endsWith:function(t,e){return t.substring(t.length-e.length)===e},wrapList:P,wrapValue:function(t,...e){return e[0]instanceof t?e[0]:new t(...e)},simpleEase:function(t){return t<.5?2*t*t:t*(4-2*t)-1},values:l,arrayToSet:B,setToArray:$,uid:function(){return nt++},upperCaseFirst:st,lowerCaseFirst:rt,getter:function(t,e,n){Object.defineProperty(t,e,{get:n})},delegate:function(t,e,n){P(e).forEach((function(e){Object.defineProperty(t,e,{get(){const t=n.call(this);let r=t[e];return w(r)&&(r=r.bind(t)),r},set(t){n.call(this)[e]=t}})}))},reverse:function(t){return q(t).reverse()},prefixCamelCase:function(t,e){return e+st(t)},unprefixCamelCase:function(t,e){const n=new RegExp("^"+e+"(.+)$");let r=t.match(n);if(r)return rt(r[1])},camelToKebabCase:function(t){return t.replace(/[A-Z]/g,(t=>"-"+t.toLowerCase()))},nullToUndefined:function(t){if(!f(t))return t},sprintf:function(t,...e){return at(J,t,...e)},sprintfWithFormattedArgs:at,renameKeys:function(t,e){const n={};for(let r in t)n[e(r)]=t[r];return n},timestamp:function(){return Math.floor(.001*Date.now())},allSettled:function(t){return Promise.all(p(t,Z))},negate:ut}}()},4606:(t,e,n)=>{n(5074),up.viewport=function(){const t=up.util,e=up.element,n=up.fragment,r=new up.Config((()=>({viewportSelectors:["[up-viewport]","[up-fixed]"],fixedTop:["[up-fixed~=top]"],fixedBottom:["[up-fixed~=bottom]"],anchoredRight:["[up-anchored~=right]","[up-fixed~=top]","[up-fixed~=bottom]","[up-fixed~=right]"],revealSnap:200,revealPadding:0,revealTop:!1,revealMax:()=>.5*window.innerHeight,scrollSpeed:1}))),s=new up.MotionController("scrolling");function i(t,e,r={}){t=n.get(t,r);const i=new up.ScrollMotion(t,e,r);s.startMotion(t,i,r)}function o(e,r){if(r=t.options(r),e=n.get(e,r),!(r.layer=up.layer.get(e)))return up.error.failed.async("Cannot reveal a detached element");r.peel&&r.layer.peel();const i=new up.RevealMotion(e,r);return s.startMotion(e,i,r)}function a(t,e={}){if(up.browser.isIE11()){const e=c(t),n=e.scrollTop;t.focus(),e.scrollTop=n}else t.focus({preventScroll:!0});if(!e.preventScroll)return o(t)}function u(t=location.hash,e){let n=k(t,e);if(n)return up.reveal(n,{top:!0})}function l(){return[f(),...r.viewportSelectors].join(",")}function c(t,r={}){const s=n.get(t,r);return e.closest(s,l())}function p(t,r={}){return t=n.get(t,r),e.around(t,l())}function h(t={}){return n.all(l(),t)}function f(){let t;return(t=document.scrollingElement)?t.tagName:"html"}function d(){return document.querySelector(f())}function m(t){const n=e.style(t,"overflow-y");return"auto"===n||"scroll"===n}const g=t.memoize((function(){const t=up.element.affix(document.body,"[up-viewport]",{style:{position:"absolute",top:"0",left:"0",width:"100px",height:"100px",overflowY:"scroll"}}),e=t.offsetWidth-t.clientWidth;return up.element.remove(t),e}));function y(t){return up.fragment.toTarget(t)}function b(t=document){const e=["[up-fixed]"].concat(r.fixedTop).concat(r.fixedBottom);return t.querySelectorAll(e.join(","))}function v(e){const n=t.copy(t.extractOptions(e));let r;return n.layer=up.layer.get(n),r=e[0]?[c(e[0],n)]:n.around?p(n.around,n):h(n),[r,n]}function w(e,n){const r=t.map(e,(function(t){const e=y(t);return i(t,n[e]||0,{duration:0})}));return Promise.all(r)}function k(t,r={}){if(t=t?.replace(/^#/,"")){const s=[e.attributeSelector("id",t),"a"+e.attributeSelector("name",t)].join(",");return n.get(s,r)}}let E=!1;return up.on("scroll",{once:!0},(()=>E=!0)),up.on("up:app:boot",(()=>t.task((function(){if(!E)return u()})))),up.on(window,"hashchange",(()=>u())),up.on("up:framework:reset",(function(){r.reset(),s.reset()})),{reveal:o,revealHash:u,firstHashTarget:k,scroll:i,config:r,get:c,subtree:function(t,r={}){return t=n.get(t,r),e.subtree(t,l())},around:p,all:h,rootSelector:f,get root(){return d()},rootWidth:function(){return e.root.clientWidth},rootHeight:function(){return e.root.clientHeight},rootHasReducedWidthFromScrollbar:function(){return window.innerWidth>document.documentElement.offsetWidth},rootOverflowElement:function(){const{body:e}=document,n=document.documentElement;return t.find([n,e],m)||d()},isRoot:function(t){return e.matches(t,f())},scrollbarWidth:g,scrollTops:function(e={}){return t.mapObject(h(e),(t=>[y(t),t.scrollTop]))},saveScroll:function(...e){const[n,r]=v(e),s=r.location||r.layer.location;if(s){const e=r.tops??function(e){return t.mapObject(e,(t=>[y(t),t.scrollTop]))}(n);r.layer.lastScrollTops.set(s,e)}},restoreScroll:function(...e){const[n,r]=v(e),s=r.layer.location,i=r.layer.lastScrollTops.get(s)||{};return up.puts("up.viewport.restoreScroll()","Restoring scroll positions for URL %s to %o",t.urlWithoutHost(s),i),w(n,i)},resetScroll:function(...t){const[e,n]=v(t);return w(e,{})},anchoredRight:function(){const t=r.anchoredRight.join(",");return n.all(t,{layer:"root"})},fixedElements:b,absolutize:function(n,r={}){const s=c(n).getBoundingClientRect(),i=n.getBoundingClientRect(),o=new up.Rect({left:i.left-s.left,top:i.top-s.top,width:i.width,height:i.height});r.afterMeasure?.(),e.setStyle(n,{position:"static"===n.style.position?"static":"relative",top:"auto",right:"auto",bottom:"auto",left:"auto",width:"100%",height:"100%"});const a=e.createFromSelector("up-bounds");e.insertBefore(n,a),a.appendChild(n);const u=function(t,n){return o.left+=t,o.top+=n,e.setStyle(a,o)};u(0,0);const l=n.getBoundingClientRect();return u(i.left-l.left,i.top-l.top),t.each(b(n),e.fixedToAbsolute),{bounds:a,moveBounds:u}},focus:a,tryFocus:function(t,e){return a(t,e),t===document.activeElement},makeFocusable:function(t){t.hasAttribute("tabindex")||function(t){return e.matches(t,"a[href], button, textarea, input, select")}(t)||(t.setAttribute("tabindex","-1"),t.classList.add("up-focusable-content"))}}}(),up.focus=up.viewport.focus,up.scroll=up.viewport.scroll,up.reveal=up.viewport.reveal},3507:()=>{window.up={version:"2.2.0"}}},e={};function n(r){var s=e[r];if(void 0!==s)return s.exports;var i=e[r]={exports:{}};return t[r](i,i.exports,n),i.exports}n(3507),n(8374),n(7924),n(3924),n(6535),n(2811),n(9675),n(2406),n(3742),n(3115),n(1279),n(6346),n(3030),n(7948),n(1752),n(8228),n(7050),n(9441),n(7422),n(9005),n(2200),n(1569),n(2737),n(3635),n(1906),n(4158),n(3139),n(6866),n(665),n(2828),n(2587),n(7031),n(4850),n(6267),n(7956),n(7403),n(6412),n(7965),n(7771),n(86),n(4552),n(5580),n(7101),n(6066),n(6387),n(5390),n(2618),n(7792),n(1104),n(8665),n(3645),n(7782),n(2705),n(606),n(5437),n(7974),n(6413),n(5221),n(2298),n(4517),n(7241),n(2723),n(6956),n(8720),n(104),n(5438),n(7885),n(4818),n(9634),n(8670),n(3535),n(4453),n(2514),n(8944),n(2667),n(4606),n(4034),n(1647),n(9443),n(3849),n(2851),n(454),n(9615),n(6774),up.framework.boot()})();
data/lib/unpoly-rails.rb CHANGED
@@ -1,13 +1,13 @@
1
1
  require 'memoized'
2
- require 'unpoly/rails/version'
3
- require 'unpoly/rails/error'
4
- require 'unpoly/rails/engine'
5
- require 'unpoly/rails/request_echo_headers'
6
- require 'unpoly/rails/request_method_cookie'
7
- require 'unpoly/rails/change/field_definition'
8
- require 'unpoly/rails/change/field'
9
- require 'unpoly/rails/change/layer'
10
- require 'unpoly/rails/change/cache'
11
- require 'unpoly/rails/change/context'
12
- require 'unpoly/rails/change'
13
- require 'unpoly/rails/controller'
2
+ require_relative 'unpoly/rails/version'
3
+ require_relative 'unpoly/rails/error'
4
+ require_relative 'unpoly/rails/engine'
5
+ require_relative 'unpoly/rails/request_echo_headers'
6
+ require_relative 'unpoly/rails/request_method_cookie'
7
+ require_relative 'unpoly/rails/change/field_definition'
8
+ require_relative 'unpoly/rails/change/field'
9
+ require_relative 'unpoly/rails/change/layer'
10
+ require_relative 'unpoly/rails/change/cache'
11
+ require_relative 'unpoly/rails/change/context'
12
+ require_relative 'unpoly/rails/change'
13
+ require_relative 'unpoly/rails/controller'
@@ -40,7 +40,7 @@ module Unpoly
40
40
  super(target, *args)
41
41
  end
42
42
 
43
- ActionController::Base.prepend(self)
43
+ ::ActionController::Base.prepend(self)
44
44
 
45
45
  end
46
46
  end
@@ -4,29 +4,22 @@ module Unpoly
4
4
  initializer 'unpoly-rails.assets' do |app|
5
5
  # Some projects may choose to completely remove the asset pipeline from the project.
6
6
  # In that case the config.assets accessor is not defined.
7
- asset_pipeline_required = app.config.respond_to?(:assets)
7
+ asset_pipeline_active = app.config.respond_to?(:assets)
8
8
 
9
- if asset_pipeline_required
10
- # The gem package has a dist folder with the pre-built unpoly.js/.css.
11
- # The folder may be empty in the local repository, or contain a stale build.
12
- dist_folder = root.join('dist')
9
+ if asset_pipeline_active
10
+ # The spec folder only exists for local development,
11
+ # it is not shipped with the .gem package.
12
+ spec_folder = root.join('spec')
13
13
 
14
- # The local repository has a lib/assets folder, but the gem package does not.
15
- # The Rails asset pipeline can require unpoly.js/.css from there and compile
16
- # it within the Rails process.
17
- source_folder = root.join('lib', 'assets')
18
-
19
- is_local_gem = source_folder.directory?
20
-
21
- # If someone has required the local gem (e.g. `gem 'unpoly', path: '../unpoly'`)
22
- # we use the local path. This way changes in the source are immediately picked
14
+ # If a local application has referenced the local gem sources
15
+ # (e.g. `gem 'unpoly', path: '../unpoly'`) we use the local build.
16
+ # This way changes from the Webpack watcher are immediately picked
23
17
  # up by the application.
24
- if is_local_gem
25
- app.config.assets.paths << source_folder.join('javascripts').to_s
26
- app.config.assets.paths << source_folder.join('stylesheets').to_s
27
- else
28
- app.config.assets.paths << dist_folder.to_s
29
- end
18
+ is_local_gem = spec_folder.directory?
19
+ assets_folder = is_local_gem ? 'unpoly-dev' : 'unpoly'
20
+
21
+ # Tell the asset pipeline where to find our assets.
22
+ app.config.assets.paths << root.join('assets', assets_folder).to_s
30
23
  end
31
24
  end
32
25
  end
@@ -24,7 +24,7 @@ module Unpoly
24
24
  response.headers['X-Up-Method'] = request.method
25
25
  end
26
26
 
27
- ActionController::Base.send(:include, self)
27
+ ::ActionController::Base.send(:include, self)
28
28
 
29
29
  end
30
30
  end
@@ -4,6 +4,6 @@ module Unpoly
4
4
  # The current version of the unpoly-rails gem.
5
5
  # This version number is also used for releases of the Unpoly
6
6
  # frontend code.
7
- VERSION = '2.0.0'
7
+ VERSION = '2.2.0'
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,17 +1,45 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unpoly-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Henning Koch
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-17 00:00:00.000000000 Z
11
+ date: 2021-08-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rails
14
+ name: railties
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '3.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: actionpack
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '3.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '3.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activesupport
15
43
  requirement: !ruby/object:Gem::Requirement
16
44
  requirements:
17
45
  - - ">="
@@ -74,28 +102,28 @@ extensions: []
74
102
  extra_rdoc_files: []
75
103
  files:
76
104
  - ".yardopts"
77
- - CHANGELOG.md
78
105
  - LICENSE
79
106
  - README.md
80
- - README_RAILS.md
81
- - dist/unpoly-bootstrap3.css
82
- - dist/unpoly-bootstrap3.js
83
- - dist/unpoly-bootstrap3.min.css
84
- - dist/unpoly-bootstrap3.min.js
85
- - dist/unpoly-bootstrap4.css
86
- - dist/unpoly-bootstrap4.js
87
- - dist/unpoly-bootstrap4.min.css
88
- - dist/unpoly-bootstrap4.min.js
89
- - dist/unpoly-bootstrap5.css
90
- - dist/unpoly-bootstrap5.js
91
- - dist/unpoly-bootstrap5.min.css
92
- - dist/unpoly-bootstrap5.min.js
93
- - dist/unpoly-migrate.js
94
- - dist/unpoly-migrate.min.js
95
- - dist/unpoly.css
96
- - dist/unpoly.js
97
- - dist/unpoly.min.css
98
- - dist/unpoly.min.js
107
+ - assets/unpoly/unpoly-bootstrap3.css
108
+ - assets/unpoly/unpoly-bootstrap3.js
109
+ - assets/unpoly/unpoly-bootstrap3.min.css
110
+ - assets/unpoly/unpoly-bootstrap3.min.js
111
+ - assets/unpoly/unpoly-bootstrap4.css
112
+ - assets/unpoly/unpoly-bootstrap4.js
113
+ - assets/unpoly/unpoly-bootstrap4.min.css
114
+ - assets/unpoly/unpoly-bootstrap4.min.js
115
+ - assets/unpoly/unpoly-bootstrap5.css
116
+ - assets/unpoly/unpoly-bootstrap5.js
117
+ - assets/unpoly/unpoly-bootstrap5.min.css
118
+ - assets/unpoly/unpoly-bootstrap5.min.js
119
+ - assets/unpoly/unpoly-migrate.js
120
+ - assets/unpoly/unpoly-migrate.min.js
121
+ - assets/unpoly/unpoly.css
122
+ - assets/unpoly/unpoly.es5.js
123
+ - assets/unpoly/unpoly.es5.min.js
124
+ - assets/unpoly/unpoly.js
125
+ - assets/unpoly/unpoly.min.css
126
+ - assets/unpoly/unpoly.min.js
99
127
  - lib/unpoly-rails.rb
100
128
  - lib/unpoly/rails/change.rb
101
129
  - lib/unpoly/rails/change/cache.rb
@@ -109,8 +137,7 @@ files:
109
137
  - lib/unpoly/rails/request_echo_headers.rb
110
138
  - lib/unpoly/rails/request_method_cookie.rb
111
139
  - lib/unpoly/rails/version.rb
112
- - lib/unpoly/tasks.rb
113
- homepage: https://unpoly.com
140
+ homepage: https://github.com/unpoly/unpoly-rails
114
141
  licenses:
115
142
  - MIT
116
143
  metadata: {}
@@ -118,7 +145,6 @@ post_install_message:
118
145
  rdoc_options: []
119
146
  require_paths:
120
147
  - lib
121
- - dist
122
148
  required_ruby_version: !ruby/object:Gem::Requirement
123
149
  requirements:
124
150
  - - ">="
data/CHANGELOG.md DELETED
@@ -1,2345 +0,0 @@
1
- Changelog
2
- =========
3
-
4
- Changes to this project will be documented in this file.
5
-
6
- If you're upgrading from an older Unpoly version you should load [`unpoly-migrate.js`](https://unpoly.com/changes/upgrading) to enable deprecated APIs.
7
-
8
- You may browse a formatted and hyperlinked version of this file at <https://unpoly.com/changes>.
9
-
10
-
11
- 2.0.0
12
- -----
13
-
14
- Unpoly 2 ships with many new features and API improvements, unlocking many use cases that were not possible with Unpoly 1.
15
-
16
- For an in-depth guide to all changes, see our [Unpoly 2 presentation](http://triskweline.de/unpoly2-slides/) (150 slides).
17
-
18
- If you're upgrading from an older Unpoly version you should load [`unpoly-migrate.js`](https://unpoly.com/changes/upgrading) to enable deprecated APIs. Also see below for an [overview of breaking changes](#overview-of-breaking-changes).
19
-
20
- ### Change overview
21
-
22
- #### Less need for boilerplate configuration
23
-
24
- - Fragment links often replace the primary content element of your application layout. For this purpose you can now define [default targets](/up-main) that are automatically updated when no target selector is given.
25
- - Unpoly can be configured to [handle all links and forms](/handling-everything), without any `[up-...]` attributes.
26
- - We have examined many real-world Unpoly apps for repetitive configuration and made these options the new default.
27
-
28
- #### New Layer API
29
-
30
- - A new [layer API](/up.layer) replaces modals and popups.
31
- - Layers can be stacked infinitely.
32
- - Layers are fully isolated, meaning a screen in one layer will not accidentally see elements or events from another layer. For instance, [fragment links](/up.link) will only update elements from the [current layer](/up.layer.current) unless you [explicitly target another layer](/layer-option).
33
- - A variety of [overlay modes](/layer-terminology) are supported, such as modal dialogs, popup overlays or drawers. You may [customize their appearance and behavior](/customizing-overlays).
34
-
35
- #### Subinteractions
36
-
37
- - Overlays allow you to break up a complex screen into [subinteractions](/subinteractions).
38
- - Subinteractions take place in overlays and may span one or many pages. The original screen remains open in the background.
39
- - Once the subinteraction is *done*, the overlay is [closed](/closing-overlays) and a result value is communicated back to the parent layer.
40
-
41
- #### Navigation intent
42
-
43
- - You can now define whether a framgent update constitutes a user navigation. Switching screens needs other defaults than updating a tiny box.
44
- - User navigation aborts earlier requests, fixing race conditions on slow connections.
45
-
46
- #### Accessibility
47
-
48
- - New overlays are focused automatically and trap focus in a cycle. Closing the overlay re-focuses the link that opened it.
49
- - Focus is automatically managed when rendering major new content. A new [`[up-focus]` attribute](/focus-option) allows
50
- you to explicitely move the user's focus as you update fragments.
51
- - Keyboard navigation is supported everywhere.
52
- - Focus, selection and scroll positions are preserved within an updated fragment.
53
-
54
- #### Reworked Bootstrap integration
55
-
56
- - The Bootstrap integration is now minimal and as unopinionated as possible. Little to no Bootstrap CSS is overridden.
57
- - Bootstrap versions 3, 4 and 5 are now supported.
58
-
59
- #### Quality of live improvements
60
-
61
- - Unpoly now ships with a bandwidth-friendly [polling implementation](/up-poll) that handles many edge cases.
62
- - The position of a clicked link is considered when deciding which element to replace. If possible, Unpoly will update an selector in the vicinity of the link that triggered the fragment update. This helps with multiple self-contained components (with the same selector) on the same page.
63
- - The [log](/up.log) output is more much more compact and has a calmer formatting.
64
- - New fragments are no longer revealed by default. Instead Unpoly scrolls to the top when the [main target](/up-main) has changed, but does not scroll otherwise.
65
- - History is no longer changed by default. Instead Unpoly updates history only when a [main target](/up-main) has changed.
66
- - All scroll-related options have been unified in a single [`[up-scroll]` attribute](/scroll-option).
67
- - Many optimizations have been made to preserve bandwidth on slow connections. For example, Unpoly stops [preloading](/up-preload) and [polling](/up-poll) whenthe connection has high latency or low throughput.
68
- - The client-side cache can be carefully managed by both the client and server.
69
- - Unpoly 1 had many functions for updating fragments (`up.replace()`, `up.extract()`, `up.modal.extract()`, etc.). Unpoly 2 has unified these into a single function `up.render()`.
70
- - Event handlers to `up:link:follow`, `up:form:submit` etc. may change the render options for the coming fragment update.
71
- - Added more options to handle [unexpected server responses](/server-errors), including the new `up:fragment:loaded` event.
72
-
73
- #### Extended server protocol
74
-
75
- The optional server protocol has been extended with additional headers that the server may use to interact with the frontend. For example:
76
-
77
- - The server may [emit events on the frontend](/X-Up-Events).
78
- - The server may [close overlays](/X-Up-Accept).
79
- - The server may [change the render target](/X-Up-Target) for a fragment update.
80
-
81
- See `up.protocol` for a full list of features.
82
-
83
- If you are using Ruby on Rails, the new protocol is already implemented by the [`unpoly-rails`](https://rubygems.org/gems/unpoly-rails) gem.
84
-
85
- If you are using Elixir / Phoenix, the new protocol is already implemented by the [`ex_unpoly`](https://hex.pm/packages/ex_unpoly) package.
86
-
87
-
88
- ### Overview of breaking changes
89
-
90
- Please use [`unpoly-migrate.js`](/changes/upgrading) for a very smooth upgrade process from Unpoly 0.x or 1.x to Unpoly 2.0.
91
-
92
- By loading <code>unpoly-migrate.js</code>, calls to most old APIs will be forwarded to the new version. A deprecation notice will be logged to your browser console. This way you can upgrade Unpoly, revive your application with a few changes, then replace deprecated API calls under green tests.
93
-
94
- There's a short list of changes that we cannot fix with aliases.
95
-
96
- #### Overlays (modals, popups) have different HTML
97
-
98
- But it's similar. E.g. `<div class="modal">` becomes `<up-modal>`.
99
-
100
- #### Unpoly only sees the current layer
101
-
102
- You can target other layers with `{ layer: 'any' }`.
103
-
104
- #### Async functions no longer wait for animations
105
-
106
- You might or might not notice. In cases where you absolutely do need to wait, an `{ onFinished }` callback can be used.
107
-
108
- #### Tooltips are no longer built-in
109
-
110
- But there are a million better libraries.
111
-
112
-
113
- ### Unpoly 1 maintenance
114
-
115
- With the release of Unpoly we're ending maintenance of Unpoly 1. Expect little to no changes to Unpoly 1 in the future. GitHub issues that have been fixed in Unpoly 2 will be closed.
116
-
117
- The legacy documentation for Unpoly 1.x has been archived to <https://v1.unpoly.com>.
118
-
119
-
120
-
121
- 1.0.0
122
- -----
123
-
124
- For six years Unpoly has been released under a 0.x version number. To establish the maturity and stability of the project, we're releasing today's version as 1.0.0.
125
-
126
- There are only three changes from 0.62.1:
127
-
128
- - Fix a bug where `up.util.escapeHTML()`` would not escape single quotes.
129
- - Unpoly will no longer wait a JavaScript execution task to boot after `DOMContentLoaded`. This may improve the stability of test suites that previously interacted with the page too soon.
130
- - You may now disable the Unpoly banner in the development console with `up.log.config.banner = false`. (change by @hfjallemark).
131
-
132
- This is the last release of the 0.x API line. We're tracking its code in the [`1.x-stable`](https://github.com/unpoly/unpoly/tree/1.x-stable), but expect little to no changes in the future.
133
-
134
- The next release will be [Unpoly 2](https://triskweline.de/unpoly2-slides). It will include major (but mostly backwards compatible) renovations to its API, unlocking many use cases that were not possible with Unpoly 1.
135
-
136
-
137
- 0.62.1
138
- ------
139
-
140
- This is another maintenance release while we're finishing [the next major version of Unpoly](https://groups.google.com/forum/#!topic/unpoly/FDdVjxbjNLg).
141
-
142
- Community members were involved in every change of this release:
143
-
144
- - [`up.submit()`](/up.submit) has a new options `{ params }`. It may be used to pass extra form [parameters](/up.Params) that will be submitted in addition to the parameters from the form. (fix by @robinvdvleuten)
145
- - [`a[up-modal]`](/a-up-modal) will now honor an [`[up-cache]`](/a-up-target#up-cache) attribute on the same link. (fix by @adam12)
146
- - Prevent destructor function from being called twice if [`up.destroy()`](/up.destroy) is called twice with the same element (reported by @kratob)
147
- - On devices that don't show a vertical scrollbar, users can no longer scroll the underlying page while a [modal overlay](/up.modal) is open. (reported by @msurdi)
148
-
149
-
150
- 0.62.0
151
- ------
152
-
153
- This release backports a number of accessibility improvements from [the next major version of Unpoly](https://groups.google.com/forum/#!topic/unpoly/FDdVjxbjNLg).
154
- We encourage everyone to upgrade to this release in order to better support users with visual impairments.
155
-
156
- The following changes are included:
157
-
158
- - Links with an [`[up-instant]`](/a-up-instant) attribute can now be followed with the keyboard.
159
- - Fragments that are being [destroyed](/up.destroy) now get an [`[aria-hidden=true]`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-hidden_attribute)
160
- attribute while its disappearance is being animated. When a fragment is being swapped with a new version, the old fragment version is also
161
- given `[aria-hidden=true]` while it's disappearing.
162
- - [Modal dialogs](/up.modal) now get an [`[aria-modal=true]`](https://a11ysupport.io/tech/aria/aria-modal_attribute) attribute.
163
-
164
- The next major version of Unpoly will include additional accessibility improvements. In particular the
165
- new modal ("layer") implementation will implement all best practices for accessible dialogs.
166
-
167
-
168
- 0.61.1
169
- ------
170
-
171
- This is a maintenance release while we're getting ready for [the next major version of Unpoly](https://groups.google.com/forum/#!topic/unpoly/FDdVjxbjNLg).
172
-
173
- - Fix a bug where [`up.destroy()`](/up.destroy) wouldn't clean up the global jQuery cache. This is only relevant when using Unpoly together with jQuery.
174
- - Fields outside a <form> are now recognized when they have a matching [form] attribute (fixes #85)
175
- - [`up.form.fields()`](/up.form.fields) now accepts a jQuery collection as a first argument, as was already documented.
176
-
177
-
178
- 0.61.0
179
- ------
180
-
181
- This release makes it easier to migrate to a recent version of Unpoly when your app still depends on jQuery.
182
- Unpoly dropped its jQuery dependency with version 0.60.0, but retains optional jQuery support through functions like
183
- [`up.$compiler()`](/up.$compiler) and [`up.$on()`](/up.$on). All Unpoly functions that take a native element as an
184
- argument may also be called with a jQuery collection as an argument.
185
-
186
- The following changes to the optional jQuery support were implemented:
187
-
188
- - In an ES6 build pipeline, Unpoly's jQuery support no longer requires `window.jQuery` to be defined before
189
- Unpoly is imported into the build. You still need to define `window.jQuery`, but you may do so at any time in your
190
- scripts, regardless of load order.
191
- - jQuery support functions like [`up.$compiler()`](/up.$compiler) now fail with a helpful message if the developer
192
- forgets to define `window.jQuery`.
193
-
194
- This release also exposes some convenience functions and selectors:
195
-
196
- - New experimental function [`up.event.halt()`](/up.event.halt). It prevents the event from bubbling up the DOM.
197
- It also prevents other event handlers bound on the same element. It also prevents the event's default action.
198
- - New experimental function [`up.form.fields()`](/up.form.fields). It returns a list of form fields within the given element.
199
- - The selector [`form[up-validate]`](/form-up-validate) is now supported. It performs
200
- [server-side validation](/input-up-validate) when any fieldset within this form changes. Previously only the variant
201
- [`input[up-validate]`](/input-up-validate) was supported.
202
-
203
-
204
- 0.60.3
205
- ------
206
-
207
- [`[up-validate]`](/up-validate) again recognizes the `[up-fieldset]` attribute to find the form fragment
208
- that should be replaced with validation results.
209
-
210
- In the example below, changing the `email` input would only validate the first fieldset:
211
-
212
- ```html
213
- <form action="/users" id="registration">
214
-
215
- <div up-fieldset>
216
- Validation message
217
- <input type="text" name="email" up-validate />
218
- </div>
219
-
220
- <div up-fieldset>
221
- Validation message
222
- <input type="password" name="password" up-validate />
223
- </div>
224
-
225
- </form>
226
- ```
227
-
228
-
229
- 0.60.2
230
- ------
231
-
232
- - When [submitting](/up-form) a form with a GET method, any query parameters in the form's `[action]` URL are now discarded.
233
- This matches the standard browser behavior when submitting a form without Unpoly.
234
- - When [submitting](/up-form) a form with a POST method, any query parameters in the form's `[action]` URL are now kept in the
235
- URL, instead of being merged into the form's data payload.
236
- This matches the standard browser behavior when submitting a form without Unpoly.
237
- - New experimental function [`up.Params.stripURL(url)`](/up.Params.stripURL).
238
- It returns the given URL without its [query string](https://en.wikipedia.org/wiki/Query_string).
239
-
240
-
241
- 0.60.1
242
- ------
243
-
244
- - When user does not confirm an [`[up-confirm]`](/a-up-target#up-confirm) link,
245
- the link's [`.up-active`](/a.up-active) class is now removed (fixes #89)
246
-
247
-
248
- 0.60.0
249
- ------
250
-
251
- This is a major update with some breaking changes.
252
-
253
- ### Highlights
254
-
255
- - jQuery is no longer required! Unpoly now has zero dependencies.
256
- - New `up.element` helpers to complement [native `Element` methods](https://www.w3schools.com/jsref/dom_obj_all.asp). You might not even miss jQuery anymore.
257
- - Vastly improved performance on slow devices.
258
- - Utility functions that work with arrays and array-like values have been greatly improved.
259
- - The `up.util` module now plug the worst emissions in JavaScript's standard library: Equality-by-value, empty-by-value and shallow-copy. Your own objects may hook into those protocols.
260
- - You may define a padding when [revealing](/up.reveal).
261
- - Smooth [scrolling](/up.scroll) now mimics [native scroll behavior](https://hospodarets.com/native_smooth_scrolling).
262
- - Fixed many positioning issues with [popups](/up.popup) and [tooltips](/up.tooltip).
263
- - Several modules have been renamed to match the pattern `up.thing.verb()`. `up.dom` is now `up.fragment`, `up.bus` is now `up.event`, `up.layout` is now `up.viewport`.
264
-
265
- Details below.
266
-
267
-
268
- ### jQuery is no longer required
269
-
270
- jQuery no longer required to use Unpoly. That means Unpoly no longer has any dependencies!
271
-
272
- Due to its use of native DOM APIs, Unpoly is now a lot faster. Like, a **lot**. Ditching jQuery also saves you 30 KB of gzipped bundle size and speeds up your own code.
273
-
274
- #### Migrating apps that use jQuery
275
-
276
- Effort has been made to ensure that migrating to this version is smooth for existing apps that use jQuery.
277
-
278
- All Unpoly functions that accept element arguments will accept both native elements and jQuery collections.
279
-
280
- You will need to prefix some function calls with `$` to have your callbacks called with jQuery collections instead of native elements:
281
-
282
- - The `up.compiler()` callback now receives a [native element](https://developer.mozilla.org/en-US/docs/Web/API/Element) instead of a jQuery collection. For the old behavior, use `up.$compiler()`.
283
- - The `up.macro()` callback now received a [native element](https://developer.mozilla.org/en-US/docs/Web/API/Element) instead of a jQuery collection. For the old behavior, use `up.$macro()`.
284
- - The event handler passed to `up.on()` now receives an element instead of a jQuery collection. For the old behavior, use `up.$on()`.
285
-
286
- Finally, all Unpoly events (`up:*`) are now triggered as native events that can be received with [`Element#addEventListener()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener). You may continue to use jQuery's [`jQuery#on()`](http://api.jquery.com/on/) to listen to Unpoly events, but you need to access custom properties through `event.originalEvent`.
287
-
288
- Also know that if you use jQuery's `$.fn.trigger()` to emit events, these events are not received by native event listeners (including Unpoly). Use `up.emit()` instead to trigger an event that can be received by both native listeners and jQuery listeners.
289
-
290
- See below for detailed changes.
291
-
292
-
293
- ### New DOM helpers
294
-
295
- A new, experimental `up.element` module offers convience functions for DOM manipulation and traversal.
296
-
297
- It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_obj_all.asp) and works across all [supported browsers](/up.browser) without polyfills.
298
-
299
- | `up.element.first()` | Returns the first descendant element matching the given selector.|
300
- | `up.element.all()` | Returns all descendant elements matching the given selector.|
301
- | `up.element.subtree()` | Returns a list of the given parent's descendants matching the given selector. The list will also include the parent element if it matches the selector itself.|
302
- | `up.element.closest()` | Returns the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.|
303
- | `up.element.matches()` | Matches all elements that have a descendant matching the given selector.|
304
- | `up.element.get()` | Casts the given value to a native [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element).|
305
- | `up.element.toggle()` | Display or hide the given element, depending on its current visibility.|
306
- | `up.element.toggleClass()` | Adds or removes the given class from the given element.|
307
- | `up.element.hide()` | Hides the given element.|
308
- | `up.element.show()` | Shows the given element.|
309
- | `up.element.remove()` | Removes the given element from the DOM tree.|
310
- | `up.element.replace()` | Replaces the given old element with the given new element.|
311
- | `up.element.setAttrs()` | Sets all key/values from the given object as attributes on the given element.|
312
- | `up.element.affix()` | Creates an element matching the given CSS selector and attaches it to the given parent element.|
313
- | `up.element.createFromSelector()` | Creates an element matching the given CSS selector.|
314
- | `up.element.createFromHtml()` | Creates an element from the given HTML fragment.|
315
- | `up.element.toSelector()` | Returns a CSS selector that matches the given element as good as possible.|
316
- | `up.element.setAttrs()` | Sets all key/values from the given object as attributes on the given element.|
317
- | `up.element.booleanAttr()` | Returns the value of the given attribute on the given element, cast as a boolean value.|
318
- | `up.element.numberAttr()` | Returns the value of the given attribute on the given element, cast to a number.|
319
- | `up.element.jsonAttr()` | Reads the given attribute from the element, parsed as [JSON](https://www.json.org/).|
320
- | `up.element.style()` | Receives [computed CSS styles](https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle) for the given element.|
321
- | `up.element.styleNumber()` | Receives a [computed CSS property value](https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle) for the given element, casted as a number.|
322
- | `up.element.setStyle()` | Sets the given CSS properties as inline styles on the given element.|
323
- | `up.element.isVisible()` | Returns whether the given element is currently visible.|
324
- | `:has()` | A non-standard [pseudo-class](https://developer.mozilla.org/en-US/docs/Learn/CSS/Introduction_to_CSS/Pseudo-classes_and_pseudo-elements) that matches all elements that have a descendant matching the given selector. |
325
-
326
- ### Events
327
-
328
- - The `up.bus` module has been renamed to `up.event`. We want to normalize Unpoly's API to the pattern `up.thing.verb()` in the future.
329
- - All Unpoly events (`up:*`) are now triggered as native events that can be received with [`Element#addEventListener()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener). You may continue to use jQuery's [`jQuery#on()`](http://api.jquery.com/on/) to listen to Unpoly events, but you need to access custom properties from `event.originalEvent`.
330
- - Properties named `event.$target` and `event.$element` have been removed from *all* Unpoly events.
331
- Use the standard `event.target` to retrieve the element on which the element was [emitted](/up.emit).
332
- - `up.on()` may now bind to a given element by passing it as an (optional) first argument:
333
-
334
- ```
335
- up.on(element, '.button', 'click', (event) => { ... })
336
- ```
337
-
338
- You may use this for [event delegation](https://davidwalsh.name/event-delegate).
339
- - The event handler passed to `up.on()` now receives an element instead of a jQuery collection:
340
-
341
- ```
342
- up.on('click', (event, element) => {
343
- alert("Clicked on an " + element.tagName)
344
- })
345
- ```
346
-
347
- For the old behavior, use `up.$on()`.
348
- - `up.emit()` may now trigger an event on a given element by passing the element as an (optional) first argument:
349
-
350
- ```
351
- up.emit(element, 'app:user:login', { email: 'foo@example.com' })
352
- ```
353
- - `up.emit()` option `{ message }` is now `{ log }`.
354
- - `up.emit()` no longer logs by default. You can enable the old efault message with `{ log: true }`.
355
- - `up.event.nobodyPrevents()` option `{ message }` is now `{ log }`.
356
- - The experimental function `up.reset()` was removed without replacement.
357
- - The experimental event `up:framework:reset` was removed without replacement.
358
-
359
-
360
-
361
- ### Custom JavaScript
362
-
363
- - [Compilers](/up.compiler) may again return an array of destructor functions. The previous deprecation was removed.
364
- - The `up.compiler()` callback now receives a [native element](https://developer.mozilla.org/en-US/docs/Web/API/Element) instead of a jQuery collection:
365
-
366
- ```
367
- up.compiler('.button', function(button) {
368
- alert("We have a new button with class " + button.className)
369
- })
370
- ```
371
-
372
- For the old behavior, use `up.$compiler()`.
373
- - The `up.macro()` callback now received a [native element](https://developer.mozilla.org/en-US/docs/Web/API/Element) instead of a jQuery collection:
374
-
375
- ```
376
- up.compiler('a.fast-link', function(element) {
377
- element.setAttribute('up-preload', 'up-preload')
378
- element.setAttribute('up-instant', 'up-instant')
379
- })
380
- ```
381
-
382
- For the old behavior, use `up.$macro()`.
383
-
384
-
385
-
386
- ### Forms
387
-
388
- - `up:form:submit` no longer has a `{ $form }` property. The event is now [emitted](/up.emit)
389
- on the form that is being submitted.
390
- - `up.observe()` now accepts a single form field, multiple fields,
391
- a `<form>` or any container that contains form fields.
392
- The callback is called once for each change in any of the given elements.
393
- - The callback for `up.observe()` now receives the arguments `(value, name)`, where
394
- `value` is the changed field value and `name` is the `[name]` of the field element:
395
-
396
- ```
397
- up.observe('form', function(value, name) {
398
- console.log('The value of %o is now %o', name, value);
399
- });
400
- ```
401
-
402
- The second argument was previously the observed input element as a jQuery collection.
403
- - `up.observe()` now accepts a `{ batch: true }` option to receive all changes
404
- since the last callback in a single object:
405
-
406
- ```
407
- up.observe('form', { batch: true }, function(diff) {
408
- console.log('Observed one or more changes: %o', diff);
409
- });
410
- ```
411
- - The default `up.form.config.validateTargets` no longer includes the
412
- selector `'[up-fieldset]'`.
413
-
414
-
415
- ### Animation
416
-
417
- - CSS property names for custom [animations](/up.animation) and [transitions](/up.transition) must be given in `kebab-case`.
418
- `camelCase` properties are no longer supported.
419
-
420
-
421
- ### Fragment update API
422
-
423
- - The module `up.dom` has been renamed to `up.fragment`. We want to normalize Unpoly's API to the pattern `up.thing.verb()` in the future.
424
- - The experimental function `up.all()` has been removed without replacement
425
- - The function `up.first()` has been renamed to `up.fragment.first()` to not be confused
426
- with the low-level `up.element.first()`.
427
- - The event `up:fragment:destroy` has been removed without replacement. This event was previously emitted before a fragment was removed. The event [`up:fragment:destroyed`](/up:fragment:destroyed) (emitted after a fragment was removed), remains in the API.
428
- - The `up:fragment:destroyed` event no longer has a `{ $element }` property. It now has a `{ fragment }` property that contains the detached element. Like before, it is emitted on the former parent of the destroyed element.
429
- - The properties for the `up:fragment:keep` event have been renamed.
430
- - The properties for the `up:fragment:kept` event have been renamed.
431
- - The properties for the `up:fragment:inserted` event have been renamed.
432
- - The properties for the `up:fragment:destroyed` event have been renamed.
433
-
434
-
435
- ### Utility functions
436
-
437
- The `up.util` module now plug the worst emissions in JavaScript's standard library: Equality-by-value, empty-by-value, shallow copy:
438
-
439
- - New experimental function `up.util.isEqual()`. It returns whether the given arguments are equal by value.
440
- - New experimental property `up.util.isEqual.key`.
441
- This property contains the name of a method that user-defined classes
442
- may implement to hook into the `up.util.isEqual()` protocol.
443
- - `up.util.isBlank()` now returns false for objects with a constructor.
444
- - New experimental property `up.util.isBlank.key`. This property contains the name of a method that user-defined classes may implement to hook into the `up.util.isBlank()` protocol.
445
- - New experimental property `up.util.copy.key`. This property contains the name of a method that user-defined classes may implement to hook into the `up.util.copy()` protocol.
446
-
447
- More utility functions to have been added to work with lists:
448
-
449
- - New experimental function `up.util.findResult()`.
450
- It consecutively calls the given function which each element in the given list and
451
- returns the first truthy return value.
452
- - New experimental function `up.util.flatten()`. This flattens the given list a single level deep.
453
- - New experimental function `up.util.flatMap()`. This maps each element using a mapping function, then flattens the result into a new array.
454
-
455
- Some list functions have been renamed to names used in the standard `Array` API:
456
-
457
- - `up.util.all()` was renamed to `up.util.every()` to match the standard [`Array#every()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every), and to be less confusing with `up.element.all()`.
458
- - `up.util.any()` was renamed to `up.util.some()` to match the standard
459
- [`Array#some()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some).
460
- - `up.util.select()` was renamed to `up.util.filter()` to match the standard
461
- [`Array#filter()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter).
462
- - `up.util.detect()` was renamed to `up.util.find()` to match the standard
463
- [`Array#find()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find).
464
-
465
- All functions that worked for arrays now also work for array-like values:
466
-
467
- - New experimental function `up.util.isList()`. It returns whether the given argument is an array-like value, like an `Array` or a
468
- [`NodeList`](https://developer.mozilla.org/en-US/docs/Web/API/NodeList).
469
- - `up.util.reject()` now works for all [array-like values](/up.util.isList), not just arrays.
470
- - `up.util.filter()` now works for all [array-like values](/up.util.isList), not just arrays.
471
- - `up.util.find()` now works for all [array-like values](/up.util.isList), not just arrays.
472
- - `up.util.some()` now works for all [array-like values](/up.util.isList), not just arrays.
473
- - `up.util.every()` now works for all [array-like values](/up.util.isList), not just arrays.
474
-
475
- And some minor changes:
476
-
477
- - `up.util.nextFrame()` has been renamed to `up.util.task()`.
478
- - `up.util.setTimer()` has been renamed to `up.util.timer()`.
479
- - `up.util.toArray() now returns its unchanged argument if the argument is already an array.
480
- - `up.util.copy()` now works with `Date` objects.
481
- - `up.util.isBoolean()` is now stable
482
- - `up.util.escapeHtml()` is now stable
483
- - `up.util.isJQuery()` now returns `false` if no jQuery is loaded into the `window.jQuery` global
484
- - `up.util.unresolvablePromise()` was removed without replacement.
485
- - `up.util.trim()` has been removed without replacement. Use the standard
486
- [`String#trim()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim) instead.
487
- - `up.util.parseUrl()` now returns the correct `{ hostname }`, `{ protocol }` and `{ pathname }` properties on IE11.
488
- - `up.util.selectorForElement()` is now `up.element.toSelector()`
489
-
490
-
491
- ### Scrolling Viewports
492
-
493
- - The `up.layout` module has been renamed to `up.viewport`. We want to normalize Unpoly's API to the pattern `up.thing.verb()` in the future.
494
- - Smooth [scrolling](/up.scroll) now mimics [native scroll behavior](https://hospodarets.com/native_smooth_scrolling):
495
- - `up.scroll()` no longer takes a `{ duration }` or `{ easing }` option.
496
- - `up.scroll()` now takes a `{ behavior }` option. Valid values are `auto` (no animation) and `smooth` (animates the scroll motion).
497
- - You may control the pace of `{ behavior: 'smooth' }` by also passing a `{ speed }` option`.
498
- - New config property `up.viewport.scrollSpeed`. This sets the default speed for smooth scrolling. The default value (`1`) roughly corresponds to the default speed of Chrome's native smooth scrolling.
499
- - Options for `up.reveal()` have been changed:
500
- - Options `{ duration }` and `{ easing }` have been removed.
501
- - New option `{ padding }` to pass the desired padding between the revealed element and the closest [viewport](/up.viewport) edge (in pixels).
502
- - New option `{ snap }`. It can be `true`, `false` or a pixel number.
503
- - New option `{ behavior }`
504
- - New option `{ speed }`. Defaults to `up.viewport.scrollSpeed`.
505
- - Config property `up.layout.config.snap` has been renamed to `up.viewport.config.revealSnap`.
506
- - New config option `up.viewport.revealPadding`.
507
- - New experimental function `up.viewport.root()`. It return the [scrolling element](https://developer.mozilla.org/en-US/docs/Web/API/document/scrollingElement)
508
- for the browser's main content area.
509
- - New experimental function `up.viewport.closest()`. It returns the scrolling container for the given element.
510
- - When a `#hash` anchor is [revealed](/up.reveal) during the initial page load, Unpoly will look for an `[up-id=hash]` before looking for `[id=hash]` and `a[name=hash]`.
511
- - Fix issues with restoring scroll positions when going back on some browsers.
512
-
513
-
514
- ### Navigation feedback
515
-
516
- - [`[up-alias]`](/up-nav#matching-url-by-pattern) now accepts one or more asterisks (`*`) anywhere in the pattern.
517
- It was previously limited to match URLs with a given prefix.
518
-
519
-
520
- ### Performance
521
-
522
- - Use of native browser APIs has improved performance drastically.
523
- - `[up-preload]` and `[up-instant]` links no longer bind to the `touchstart` event, increasing frame rate while scrolling.
524
-
525
-
526
- ### Request parameters
527
-
528
- The experimental `up.params` module has been replaced with the `up.Params` class.
529
- Wrap any type of parameter representation into `up.Params` to get consistent API for reading
530
- and manipulation.
531
-
532
- The following types of parameter representation are supported:
533
-
534
- 1. An object like `{ email: 'foo@bar.com' }`
535
- 2. A query string like `'email=foo%40bar.com'`
536
- 3. An array of `{ name, value }` objects like `[{ name: 'email', value: 'foo@bar.com' }]`
537
- 4. A [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) object.
538
- On IE 11 and Edge, `FormData` payloads require a [polyfill for `FormData#entries()`](https://github.com/jimmywarting/FormData).
539
-
540
- Supported methods are:
541
-
542
- | `new up.Params()` | Constructor. |
543
- | `up.Params#add()` | Adds a new entry with the given `name` and `value`. |
544
- | `up.Params#addAll()` | Adds all entries from the given list of params. |
545
- | `up.Params#addField()` | Adds params from the given [HTML form field](https://www.w3schools.com/html/html_form_elements.asp). |
546
- | `up.Params#delete()` | Deletes all entries with the given `name`. |
547
- | `up.Params#get()` | Returns the first param value with the given `name` from the given `params`. |
548
- | `up.Params#set()` | Sets the `value` for the entry with given `name`. |
549
- | `up.Params#toArray()` | Returns an array representation of this `up.Params` instance. |
550
- | `up.Params#toFormData()` | Returns a [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) representation of this `up.Params` instance. |
551
- | `up.Params#toObject()` | Returns an object representation of this `up.Params` instance. |
552
- | `up.Params#toQuery()` | Returns an [query string](https://en.wikipedia.org/wiki/Query_string) for this `up.Params` instance. |
553
- | `up.Params#toURL()` | Builds an URL string from the given base URL and this `up.Params` instance as a [query string](/up.Params.toString). |
554
- | `up.Params.fromFields()` | Constructs a new `up.Params` instance from one or more [HTML form field](https://www.w3schools.com/html/html_form_elements.asp). |
555
- | `up.Params.fromForm()` | Constructs a new `up.Params` instance from the given `<form>`. |
556
- | `up.Params.fromURL()` | Constructs a new `up.Params` instance from the given URL's [query string](https://en.wikipedia.org/wiki/Query_string). |
557
-
558
-
559
- ### Popups
560
-
561
- - The HTML markup for a popup has been changed to make it easier to style with CSS.
562
- The new structure is:
563
-
564
- ```
565
- <div class="up-popup">
566
- <div class="up-popup-content">
567
- Fragment content here
568
- </div>
569
- </div>
570
- ```
571
- - The default CSS styles for `.up-popup` has been changed. If you have customized popup styles,
572
- you should check if your modifications still work with the new defaults.
573
- - Popups now update their position when the screen is resized.
574
- - Popups now follow scrolling when placed within [viewports](/up.viewport) other than the main document.
575
- - The `[up-position]` attribute has been split into two attributes `[up-position]` and `[up-align]`.
576
- Similarly the `{ position }` option has been split into two options `{ position }` and `{ align }`:
577
- - `{ position }` defines on which side of the opening element the popup is attached. Valid values are `'top'`, `'right'`, `'bottom'` and `'left'`.
578
- - `{ align }` defines the alignment of the popup along its side.
579
- - When the popup's `{ position }` is `'top'` or `'bottom'`, valid `{ align }` values are `'left'`, `center'` and `'right'`.
580
- - When the popup's `{ position }` is `'left'` or `'right'`, valid `{ align }` values are `top'`, `center'` and `bottom'`.
581
- - New experimental function `up.popup.sync()`. It forces the popup to update its position when a
582
- layout change is not detected automatically.
583
- - popup elements are now appended to the respective viewport of the anchor element.
584
- They were previously always appended to the end of the `<body>`.
585
- - The events `up:popup:open`,`up:popup:opened`, `up:popup:close` and `up:popup:closed` have an `{ anchor }` property.
586
- It references the element that the popup was [attached](/up.popup.attach()) to.
587
-
588
-
589
- ### Tooltips
590
-
591
- - The HTML markup for a popup has been changed to make it easier to style with CSS.
592
- The new structure is:
593
-
594
- ```
595
- <div class="up-tooltip">
596
- <div class="up-tooltip-content">
597
- Tooltip text here
598
- </div>
599
- </div>
600
- ```
601
- - The default CSS styles for `.up-tooltip` have been changed. If you have customized tooltip styles,
602
- you should check if your modifications still work with the new defaults.
603
- - Tooltips now update their position when the screen is resized.
604
- - Tooltips now follow scrolling when placed within [viewports](/up.viewport) other than the main document.
605
- - The `[up-position]` attribute has been split into two attributes `[up-position]` and `[up-align]`. Similarly the `{ position }` option has been split into two options `{ position }` and `{ align }`:
606
- - `{ position }` defines on which side of the opening element the popup is attached. Valid values are `'top'`, `'right'`, `'bottom'` and `'left'`.
607
- - `{ align }` defines the alignment of the popup along its side.
608
- - When the tooltip's `{ position }` is `'top'` or `'bottom'`, valid `{ align }` values are `'left'`, `center'` and `'right'`.
609
- - When the tooltip's `{ position }` is `'left'` or `'right'`, valid `{ align }` values are `top'`, `center'` and `bottom'`.
610
- - New experimental function `up.tooltip.sync()`. It forces the popup to update its position when a
611
- layout change is not detected automatically.
612
- - Tooltip elements are now appended to the respective viewport of the anchor element.
613
- They were previously always appended to the end of the `<body>`.
614
-
615
-
616
- ### Ruby on Rails integration
617
-
618
- - Unpoly is now compatible with the jQuery-less UJS adapter (now [part of Action View](https://github.com/rails/rails/tree/master/actionview/app/assets/javascripts)).
619
-
620
-
621
- ### AJAX acceleration
622
-
623
- - The properties for the `up:link:preload` event have been renamed.
624
-
625
-
626
- ### Modal dialogs
627
-
628
- - Opening/closing a modal will now manipulate the `{ overflow-y }` style on the same element
629
- that was chosen by the CSS author ([nasty details](https://makandracards.com/makandra/55801-does-html-or-body-scroll-the-page)).
630
-
631
-
632
- ### Various
633
-
634
- - Renamed some files so they won't be blocked by over-eager ad blockers on developer PCs.
635
- - Deprecation warnings are only printed once per environment.
636
-
637
-
638
-
639
-
640
- 0.57.0
641
- ------
642
-
643
- ### Request parameters
644
-
645
- To prevent confusion with [`[up-data]`](/up-data), Unpoly now uses the word "params" when talking about form values or request parameters:
646
-
647
- - [`up.request()`](/up.request) option `{ data }` has been renamed to `{ params }`.
648
- - [`up.replace()`](/up.replace) option `{ data }` has been renamed to `{ params }`.
649
-
650
- Parameters may be passed in one of the following types:
651
-
652
- 1. an object like `{ email: 'foo@bar.com' }`
653
- 2. a [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) object
654
- 3. a query string like `email=foo%40bar.com`
655
- 4. an array of `{ name, value }` objects like `[{ name: 'email', value: 'foo@bar.com' }]`
656
-
657
- To help working with form values and request parameters, an experimental module [`up.params`](/up.params) has been added. It offers a consistent API to manipulate request parameters independent of their type.
658
-
659
- - [`up.params.fromForm()`](/up.params.fromForm) - serialize a `<form>`
660
- - [`up.params.fromURL()`](/up.params.fromURL) - extract params from a URL's query string
661
- - [`up.params.toArray()`](/up.params.toArray) - convert any params type to an array of `{ name, value }` elements
662
- - [`up.params.toObject()`](/up.params.toObject) - convert any params type to an object
663
- - [`up.params.toQuery()`](/up.params.toQuery) - convert any params type to a query string
664
- - [`up.params.toFormData()`](/up.params.toFormData) - convert any params type to a [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) object
665
- - [`up.params.buildURL()`](/up.params.buildURL) - composes a URL with query section from a base URL and a params value of any type
666
- - [`up.params.get()`](/up.params.get) - retrieve the value for the given params key
667
- - [`up.params.add()`](/up.params.add) - adds a single key/value to a params value of any type
668
- - [`up.params.assign()`](/up.params.assign) - adds the params to another params
669
- - [`up.params.merge()`](/up.params.merge) - [merges](/up.util.merge) two params
670
-
671
-
672
- ### Application layout
673
-
674
- - When Unpoly cannot find the [viewport](/up.layout.config#config.viewports) of an element, it now uses the scrolling root element. This is either `<body>` or `<html>`, depending on the browser.
675
- - Fix a bug where linking back and forth between multiple `#anchor` hashes of the same URL would always reveal the first anchor.
676
- - Revealing elements below [fixed navigation bars](/up-fixed-top) now honors the navigation bar's `padding`, `border`, `margin`, `top` and `bottom` properties.
677
- - Fix a bug where revealing elements [fixed navigation bars](/up-fixed-top) would scroll 1 pixel too short.
678
- - [`up.layout.revealHash()`](/up.layout.revealHash) no longer retrieves the hash anchor from the current URL. You need to pass in a `#hash` value as a first argument.
679
- - Fix a bug where a `#hash` anchor would not be revealed if it included non-word characters like spaces or dots.
680
-
681
-
682
- ### Compilers
683
-
684
- - To improve performance, Unpoly no longer parses [`[up-data]`](/up-data) attributes when a [compiler function](/up.compiler) does not require a second `data` argument.
685
- - Compilers that return [destructor functions](/up.compiler#cleaning-up-after-yourself) now run slightly faster.
686
- - [Compilers](/up.compiler) with `{ batch: true }` now receive an array of [`[up-data]`](/up-data) objects as their second `data` argument.
687
- - [Compilers](/up.compiler) with `{ batch: true }` can no longer return destructor functions. Previously the behavior of batch destructors was undefined, now it throws an error.
688
- - Returning an array of [destructor functions](/up.compiler#cleaning-up-after-yourself) from [`up.compiler()`](/up.compiler) is now deprecated. Please return a single destructor function instead.
689
- - [`up.syntax.data()`](/up.syntax.data) now returns `undefined` if the given object has no (or an empty) [`[up-data]`](/up-data) attribute. It previously returned an empty object.
690
-
691
-
692
- ### Event listeners
693
-
694
- - To improve performance, Unpoly no longer parses [`[up-data]`](/up-data) attributes when an [`up.on()`](/up.on) listener does not require a third `data` argument.
695
- - [`up.on()`](/up.on) now throws an error when the same callback function is registered multiple times.
696
-
697
-
698
- ### Fragment update API
699
-
700
- - New experimental function [`up.all()`](/up.all), which returns all elements matching the given selector. Like [`up.first()`](/up.first) it ignores elements that are being [destroyed](/up.destroy) or [transitioned](/up.morph).
701
-
702
-
703
- ### Various
704
-
705
- - New experimental function [`up.util.isBoolean()`](/up.util.isBoolean).
706
- - [`up.follow()`](/up.follow) now accepts a `{ url }` option. It can be used to override the given link's `[href]` attribute.
707
- - New configuration option [`up.form.config.submitButtons`](/up.form.config#config.submitButtons)
708
- - [`up.preload()`](/up.preload) now accepts an options hash that will be passed on to the function making the preload request.
709
- - New experimental function [`up.Response#getHeader()`](/up.Response.prototype.getHeader). It looks up the header value for the given name in the HTTP response header.
710
-
711
-
712
-
713
- 0.56.7
714
- ------
715
-
716
- - Calling `event.preventDefault()` on [`up:modal:close`](/up:modal:close) and [`up:popup:close`](/up:popup:close) events no longer prints `Uncaught (in promise)` to the error console. You still need to catch rejected promises in your own code when it calls Unpoly functions and that function is prevented by an event handler.
717
-
718
-
719
- 0.56.6
720
- ------
721
-
722
- - Fix a regression where the contents of `<noscript>` tags were parsed into DOM elements (instead of text) when a fragment contained more than one `<noscript>` element. Thanks to [@foobear](https://github.com/foobear) for helping with this.
723
-
724
-
725
- 0.56.5
726
- ------
727
-
728
- - Fix a bug where loading a page with both a ?query string and a #fragment hash would throw an error
729
-
730
-
731
- 0.56.4
732
- ------
733
-
734
- - Improve performance of HTML parsing.
735
-
736
-
737
- 0.56.3
738
- ------
739
-
740
- - Fix a bug where the Bootstrap 3 integration failed to load. Thanks [@dastra-mak](https://github.com/dastra-mak)!
741
-
742
-
743
- 0.56.2
744
- ------
745
-
746
- - Fix a bug where [`up.util.reject()`](/up.util.reject) would stop working after an animation.
747
-
748
-
749
- 0.56.1
750
- ------
751
-
752
- - New stable selector [`.up-destroying`](/up-destroying). This CSS class is assigned to elements before they are [destroyed](/up.destroy) or while they are being removed by a [transition](/up.morph).
753
- - Fix a bug where [`up.first()`](/up.first) would sometimes find an element that is being destroyed.
754
-
755
-
756
- 0.56.0
757
- ------
758
-
759
- This release includes major performance improvements and a new animation engine.
760
-
761
- Beware of the breaking change with [`.up-current`](/up-nav-a.up-current)!
762
-
763
-
764
- ### Navigation feedback
765
-
766
- Maintaining the [`.up-current`](/up-nav-a.up-current) on all links turned out to be a major performance bottleneck, so we had to make some breaking changes:
767
-
768
- - The [`.up-current`](/up-nav-a.up-current) class is now only assigned to links with an [`[up-nav]`](/up-nav) attribute, or to links within a container with an [`[up-nav]`](/up-nav) attribute. You should assign the [`[up-nav]`](/up-nav) attribute to all navigational elements that rely on `.up-current` for styling`.
769
- - You can also globally configure selectors for your navigational elements in `up.feedback.config.navs`:
770
-
771
- up.feedback.config.navs.push('.my-nav-bar')
772
- - The normalized URLs of [`[up-nav]`](/up-nav) links are now cached for performance reasons.
773
- - [`[up-nav]`](/up-nav) links are only updated once when multiple fragments are updated in a single [replacement](/a-up-target).
774
-
775
-
776
- ### Animation
777
-
778
- - When performing an [animated page transition](/up.motion) Unpoly will no longer create copies of the old and new fragment versions. The animation will instead be performed on the fragment elements themselves.
779
- - When animating an element with an existing [CSS transition](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions), Unpoly will now pause the CSS transition in its current state, perform the animation, then resume the CSS transition.
780
- - Unpoly now does less work when animation is disabled globally through `up.motion.config.enabled = false`.
781
- - [`up.morph()`](/up.morph) will now expect the new fragment version to be detached from the DOM before morphing.
782
- - [`up.morph()`](/up.morph) will now detach the old fragment version from the DOM after morphing.
783
- - The [`up.morph()`](/up.morph) function has been demoted from *stable* to *experimental*.
784
- - [`up.motion.finish()`](/up.motion.finish) now longer queries the DOM when there are no active animations.
785
-
786
-
787
- ### Application layout
788
-
789
- - When Unpoly cannot find the viewport of an element, it will now always considers `document` to be the viewport.
790
-
791
-
792
- ### Fragment updates
793
-
794
- - The [`up:fragment:destroyed`](/up:fragment:destroyed) event is now emitted after the fragment has been removed from the DOM. The event is emitted on the former parent of the removed fragment.
795
-
796
-
797
- ### Utility functions
798
-
799
- - Fix a bug where [`up.util.isBlank()`](/up.util.isBlank) returned `true` for a function value
800
- - Fix a bug where [`up.util.only()`](/up.util.only) did not copy properties inherited from a prototype
801
-
802
-
803
- ### General
804
-
805
- - Partially remove jQuery from internal code for performance reasons. We want to eventually remove jQuery as a dependency.
806
- - Cache the results of feature detection for performance reasons.
807
- - Unpoly is now more efficient when selecting elements from the DOM.
808
- - Unpoly is now more efficient when reacting to mouse events.
809
-
810
-
811
-
812
- 0.55.1
813
- ------
814
-
815
- This release restores support for Internet Explorer 11, which we accidentally broke in 0.55.0.
816
-
817
- Thanks to [@foobear](https://github.com/foobear) for helping with this.
818
-
819
-
820
- 0.55.0
821
- ------
822
-
823
- ### Fragment updates
824
-
825
- - Unpoly now detects when an [`[up-target]`](/up-target) with multiple selectors would [replace](/up.replace) the same element multiple times. In such a case the target selector will be shortened to contain the element once.
826
- - Unpoly now detects when an [`[up-target]`](/up-target) with multiple selectors contains nested elements. In such a case the target selector will be shortened to only contain the outmost element.
827
-
828
-
829
- ### Utility functions
830
-
831
- - [`up.util.uniq()`](/up.util.uniq) now works on DOM elements and other object references.
832
- - New experimental function [`up.util.uniqBy()`](/up.util.uniqBy). This function is like [`uniq`](/up.util.uniq), accept that the given function is invoked for each element to generate the value for which uniquness is computed.
833
- - Changes to [utility functions](/up.util) that work on lists ([`up.util.each()`](/up.util.each), [`up.util.map()`](/up.util.map), [`up.util.all()`](/up.util.all), [`up.util.any()`](/up.util.any), [`up.util.select()`](/up.util.select), [`up.util.reject()`](/up.util.reject)):
834
- - List functions now accept a property name instead of a mapping function:
835
-
836
- ```
837
- users = [{ name: 'foo' }, { name: 'bar' }]
838
- up.util.map(users, 'name') // ['foo', 'bar']
839
- ```
840
- - List functions now pass the iteration index as a second argument to the given function:
841
-
842
- ```
843
- users = [{ name: 'foo' }, { name: 'bar' }]
844
- up.util.map(users, function(user, index) { return index }) // [0, 1]
845
- ```
846
-
847
- 0.54.1
848
- ------
849
-
850
- This release contains no new features, but will help you when using tools like Babel or Webpack:
851
-
852
- - Unpoly now ship without any uses of [`eval()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval) in its JavaScript sources. Use of `eval()` had previously prevented minifiers from shortening local variables in some files.
853
- - Documentation in Unpoly's JavaScript sources can no longer be confused with [JSDoc](http://usejsdoc.org/) comments. Unpoly does not use JSDoc, but some build pipelines eagerly look for JSDoc comments to generate type information.
854
-
855
-
856
- 0.54.0
857
- ------
858
-
859
- ### Passive updates
860
-
861
- - [`[up-hungry]`](/up-hungry) elements will now also be updated when the server responds with an error code. This helps when `[up-hungry]` is used to display error messages.
862
-
863
- ### Forms
864
-
865
- - When a [form is submitted](/form-up-target) you can now consistently refer to that form element as `&` in CSS selectors ([like in Sass](https://sass-lang.com/documentation/file.SASS_REFERENCE.html#parent-selector)).
866
-
867
- E.g. to reveal the first error message within a failed form submission:
868
-
869
- ```
870
- <form id="my-form" up-target=".page" up-fail-reveal="& .error">
871
- ...
872
- </form>
873
- ```
874
-
875
- In this case `& .error` will be replaced by `#my-form .error` before submission.
876
-
877
- This affects CSS selectors in the following HTML attributes:
878
-
879
- - `form[up-target]`
880
- - `form[up-fail-target]`
881
- - `form[up-reveal]`
882
- - `form[up-fail-reveal]`
883
-
884
-
885
- ### Linking to fragments
886
-
887
- * When a [link is followed](/a-up-target) you can now consistently refer to that link element as `&` in CSS selectors ([like in Sass](https://sass-lang.com/documentation/file.SASS_REFERENCE.html#parent-selector)).
888
-
889
- This affects CSS selectors in the following HTML attributes:
890
-
891
- - `a[up-target]`
892
- - `a[up-fail-target]`
893
- - `a[up-reveal]`
894
- - `a[up-fail-reveal]`
895
-
896
-
897
- ### Fragment update API
898
-
899
- - New option for [`up.replace()`](/up.replace): `{ keep: false }` will disable preservation of [`[up-keep]`](/up-keep) elements.
900
- - New option for [`up.replace()`](/up.replace): `{ hungry: false }` will disable updates of [`[up-hungry]`](/up-hungry) elements.
901
-
902
-
903
-
904
- 0.53.4
905
- ------
906
-
907
- ### Passive updates
908
-
909
- - Updates for [`[up-hungry]`](/up-hungry) elements will no longer auto-close a [modal dialog](/up.modal).
910
- - Updates for [`[up-hungry]`](/up-hungry) elements will no longer auto-close a [popup overlay](/up.popup).
911
- - CSRF-related `<meta>` tags are no longer updated automatically with every request. This is to prevent unnecessary DOM jitter in applications that don't rotate CSRF tokens.
912
-
913
- ### Popup overlays
914
-
915
- - Calling `up.popup.attach()` without a target selector will now throw an error.
916
-
917
-
918
- 0.53.2
919
- ------
920
-
921
- ### General
922
-
923
- - Failed requests in event handlers of CSS selectors like `form[up-target]` no longer print `Uncaught (in promise)` to the error console. You still need to catch and handle rejected promises in your own code when it calls Unpoly functions.
924
-
925
- ### Animated transitions
926
-
927
- - Fix a bug where a page transition would flicker if [revealing](/up.reveal) was animated globally by setting `up.layout.config.duration`.
928
-
929
- ### Preloading
930
-
931
- - Fix a bug where [preloading](/a-up-target) would not always be aborted when stopping to hover before [`up.proxy.config.preloadDelay`](/up.proxy.config#config.preloadDelay).
932
-
933
-
934
- 0.53.1
935
- ------
936
-
937
- ### General
938
-
939
- - Fix a bug where replacing the first element on the page (in DOM order) would shift the scroll position if animation is disabled.
940
- - Fix a bug where query params would be lost when Unpoly would fall back to a full page load.
941
-
942
- ### Optional server protocol
943
-
944
- - The optional cookie the server can send to [signal the initial request method](/up.protocol#signaling-the-initial-request-method) will now be removed as soon as Unpoly has booted.
945
-
946
- ### Animations
947
-
948
- - Fix a bug where the animation `move-from-top` would finish instantly after animating with `move-to-top`.
949
- - Fix a bug where the animation `move-from-right` would finish instantly after animating with `move-to-right`.
950
- - Fix a bug where the animation `move-from-bottom` would finish instantly after animating with `move-to-bottom`.
951
- - Fix a bug where the animation `move-from-left` would finish instantly after animating with `move-to-left`
952
-
953
-
954
- 0.53.0
955
- ------
956
-
957
- ### New module: Passive updates
958
-
959
- Thi work-in-progress package [`up.radio`](/up.radio) will contain functionality to
960
- passively receive updates from the server. Currently the following functionality is implemented:
961
-
962
- - Elements with an [`[up-hungry]`](/up-hungry) attribute are [updated](/up.replace) whenever there is a matching element found in a successful response. The element is replaced even when it isn't [targeted](/a-up-target) directly.
963
-
964
- Use cases for this are unread message counters or notification flashes. Such elements often live in the layout, outside of the content area that is being replaced.
965
- - When a reserver response contains a `<meta name="csrf-param">` or `<meta name="csrf-token">` element, it is automatically updated in the current page.
966
-
967
-
968
- ### General
969
-
970
- - Changes when generating CSS selectors for elements:
971
- - `[aria-label]` attributes are used if no better attributes exist (like `[id]` or `[up-id]` attributes).
972
- - Attribute values with quotes are now escaped if they appear in an attribute selector.
973
- - Attribute selectors now use double quotes instead of single quotes.
974
- - When a `[name]` attribute is used, the tag name is also used. E.g. `meta[name="csrf-token"]`.
975
- - Element IDs that contain non-word characters (e.g. slashes, spaces, dots), will now generate an attribute selector like `[id="foo/bar"]`.
976
-
977
- ### Forms
978
-
979
- - You can give forms an `[up-fail-reveal]` attribute to indicate which element should be [revealed](/up.reveal) when the server responds with an error. You may use this, for example, to reveal the first validation error message:
980
- ```
981
- <form up-target=".content" up-fail-reveal=".error">
982
- ...
983
- </form>
984
- ```
985
- - Forms with an `[up-reveal]` attribute will now only honor the attribute when the form submission was successful.
986
- - Forms with an `[up-restore-scroll]` attribute will now only honor the attribute when the form submission was successful.
987
- - Forms with an `[up-reveal="css-selector"]` attribute will no longer crash when the selector could not be found.
988
- - Fix a bug where you couldn't submit a form if it's ID contains a slash character ([#46](https://github.com/unpoly/unpoly/issues/46)).
989
-
990
- ### Links
991
-
992
- - You can give links an `[up-fail-reveal]` attribute to indicate which element should be [revealed](/up.reveal) when the server responds with an error
993
- - Links with an `[up-reveal]` attribute will now only honor the attribute when the link could be followed successfully.
994
- - Links with an `[up-restore-scroll]` attribute will now only honor the attribute when the link could be followed successfully.
995
- - Links with an `[up-reveal="css-selector"]` attribute will no longer crash when the selector could not be found.
996
-
997
- ### Animations
998
-
999
- - When [replacing](/up.replace) multiple elements, it is no longer possible to use different [transitions](/up.morph) for each element. The same transition is always applied to all elements.
1000
-
1001
-
1002
-
1003
- 0.52.0
1004
- ------
1005
-
1006
- ### Browser support
1007
-
1008
- - No longer prints an error to console when registering a [macro](/up.macro) on an unsupported browser.
1009
-
1010
- ### AJAX requests
1011
-
1012
- - Unpoly can now detect the final URL of a redirect response without the [optional server protocol](/up.protocol).
1013
- The server protocol is still needed to detect redirects on Internet Explorer 11.
1014
- - When making HTTP requests Unpoly will now always merge params in the URL's query section with params from the `{ data }` option.
1015
-
1016
- ### Forms
1017
-
1018
- - [Following](/up.follow) a link now emits an [`up:link:follow`](/up:link:follow) event. The event can be prevented.
1019
-
1020
- ### Forms
1021
-
1022
- - [Submitting](/up.submit) a form through Unpoly now emits an [`up:form:submit`](/up:form:submit) event. The event can be prevented.
1023
-
1024
-
1025
- 0.51.1
1026
- ------
1027
-
1028
- ### Fragment updates
1029
-
1030
- - Fix a bug where Unpoly would crash when replacing a fragment with a `<script>` tag with a later sibling element.
1031
-
1032
-
1033
- 0.51.0
1034
- ------
1035
-
1036
- ### Fragment updates
1037
-
1038
- - `<script>` tags that were inserted by a fragment update are no longer executed. They are still executed during the initial page load. If you need a fragment update to call JavaScript code, call it from a compiler ([Google Analytics example](https://makandracards.com/makandra/41488-using-google-analytics-with-unpoly)).
1039
- - The configuration option `up.dom.config.runInlineScripts` has been removed without replacement.
1040
- - The configuration option `up.dom.config.runLinkedScripts` has been removed without replacement.
1041
- - Fix a bug where the contents of `<noscript>` tags were parsed into DOM elements (instead of a single verbatim text node). This was confusing libraries that work with `<noscript>` tags, such as [lazysizes](https://github.com/aFarkas/lazysizes).
1042
- - Work around a [bug in IE11 and Edge](https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12453464/) where `<noscript>` tags that were inserted by a fragment update could not be found with jQuery or `document.querySelectorAll()`.
1043
-
1044
-
1045
- 0.50.2
1046
- ------
1047
-
1048
- ### Fragment updates
1049
-
1050
- - Updating fragments is now much faster when no [`[up-keep]`](/up-keep) elements are involved.
1051
-
1052
- ### Scrolling
1053
-
1054
- - [`up.reveal()`](/up.reveal) no longer crashes when called with a CSS selector or non-jQuery element.
1055
- - [`up.reveal()`](/up.reveal) now returns a rejected promise when no viewport could be found for the given element.
1056
-
1057
- ### Links
1058
-
1059
- - [`[up-expand]`](/up-expand) now ignores clicks on [form fields](/up.form.config#config.fields). This is useful e.g. when `up-expand`ing a table row that contains both links and form fields.
1060
-
1061
- ### Network
1062
-
1063
- - [`a[up-preload]`](/a-up-preload) will no longer preload a link when the user holds the Shift, Ctrl or Meta key while hovering.
1064
-
1065
-
1066
- 0.50.1
1067
- ------
1068
-
1069
- ### General
1070
-
1071
- - Boolean HTML attributes are now also considered `true` if their values equal the attribute name, e.g. `up-keep="up-keep"` ([#36](https://github.com/unpoly/unpoly/issues/36))
1072
-
1073
- ### AJAX
1074
-
1075
- - [`up.request()`](/up.request) now sends an `X-Requested-With: XMLHttpRequest` headers. This header is used by many server-side frameworks to detect an AJAX request. ([#42](https://github.com/unpoly/unpoly/issues/42))
1076
-
1077
-
1078
- 0.50.0
1079
- ------
1080
-
1081
- This is a major update with some breaking changes. Expect a few more updates like this as we move closer to our 1.0 release in 2018.
1082
-
1083
- ### General
1084
-
1085
- - jQuery 3 is now supported in addition to jQuery 1.9+ and jQuery 2.
1086
- - Unpoly now uses [native Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises) instead of jQuery deferreds.
1087
- - You can now help improve Unpoly's documentation by clicking an *Edit this page* link on any [unpoly.com](https://unpoly.com/) subpage (like [`a[up-target]`](/a-up-target)).
1088
-
1089
- ### Browser support
1090
-
1091
- - To enable support for Internet Explorer 11 you need to install a Polyfill for `Promise`. We recommend [ES6-promise](https://github.com/stefanpenner/es6-promise) (2.4 KB gzipped).
1092
- - Fix a bug where Unpoly would not boot on Safari 9 and 10 if the initial page was loaded with a `POST` method.
1093
-
1094
- ### AJAX
1095
-
1096
- - Unpoly now uses [native XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) instead of `jQuery.ajax()`. If you have been hacking into Unpoly's networking through `jQuery.ajaxPrefilter()`, you must now use the [`up:proxy:load`](/up:proxy:load) event.
1097
- - [`up.ajax()`](/up.ajax) has been deprecated since its signature is incompatible with native promises. Please use [`up.request()`](/up.request) instead, whose promise fulfills with an [`up.Response`](/up.Response) object.
1098
- - The `up:proxy:received` event has been renamed to [`up:proxy:loaded`](/up:proxy:loaded).
1099
- - The [`up:proxy:load`](/up:proxy:load) event properties have changed. You can now access request properties through a key `{ request }`, e.g. `event.request.url`.
1100
- - The [`up:proxy:load`](/up:proxy:load) event can now be prevented to prevent a request from being sent to the network.
1101
- - The [`up:proxy:load`](/up:proxy:load) event now allows listeners to change request headers by manipulating the `event.request.headers` object.
1102
- - A new event [`up:proxy:fatal`](/up:proxy:fatal) will be [emitted](/up.emit) when an [AJAX request](/up.request) encounters fatal error like a timeout or loss of network connectivity.
1103
-
1104
- ### Links
1105
-
1106
- - Links with unsafe HTTP methods like `POST` are no longer marked as [`.up-current`](/a.up-current), even if their `[href]` matches the current URL.
1107
- - New experimental function [`up.link.isSafe()`](/up.link.isSafe). It returns whether the given link has a [safe](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1) HTTP method like `GET`.
1108
-
1109
- ### Fragment updates
1110
-
1111
- - When a selector was not found in the response, the error notification now offers a link to show the unexpected response.
1112
- - The event [`up:fragment:destroy`](/up:fragment:destroy) can no longer be prevented.
1113
-
1114
- ### History
1115
-
1116
- - Clicking a link with an [`[up-restore-scroll]`](/a-up-target#up-restore-scroll) attribute will no longer crash if no previous scroll position for given URL is known ([#25](https://github.com/unpoly/unpoly/issues/25))
1117
- - Fix a bug where going back in history would sometimes not call destructors ([#24](https://github.com/unpoly/unpoly/issues/24))
1118
-
1119
- ### Forms
1120
-
1121
- - [`up.observe()`](/up.observe) no longer sends multiple callbacks when a previous callback was slow to respond.
1122
-
1123
- ### Tooltips
1124
-
1125
- - Fix a bug where tooltips would sometimes stay open when many tooltips are opened and closed concurrently.
1126
-
1127
- ### Server protocol
1128
-
1129
- - When the server [signals a redirect with a `X-Up-Location` header](/up.protocol#redirect-detection), sending a `X-Up-Method` header is now optional. If it is missing, `GET` is assumed.
1130
- - Unpoly will often update a different selector in case the request fails. This second selector is now sent to the server as a `X-Up-Fail-Target` header.
1131
- - You can now [configure how CSRF tokens are sent your server-side framework](/up.protocol.config).
1132
- - CSRF tokens are no longer sent for cross-domain requests.
1133
-
1134
- ### Animation
1135
-
1136
- - `up.motion.none()` has been removed without replacement. Just pass `false` or the string `'none'` to indicate a animation or transition which has no visual effects and completes instantly.
1137
- - [`up.motion.finish()`](/up.motion.finish) is now async. It returns a promise that fulfills when all animations are finished.
1138
- - [`up.motion.finish()`](/up.motion.finish) now also finishes animations in ancestors of the given element.
1139
-
1140
- ### Modals
1141
-
1142
- - [`up.follow()`](/up.follow) will now open a modal if the given link has an [`[up-modal]`](/a-up-modal) attribute
1143
- - [`a[up-modal]`](/a-up-modal) links can now have an `[up-fail-target]` attribute to indicate which selector to replace for an non-200 response
1144
- - Fix a bug where preloading an up-modal link would create an invisible .up-modal container in the DOM.
1145
-
1146
- ### Popups
1147
-
1148
- - [`up.follow()`](/up.follow) will now open a popup if the given link has [`[up-popup]`](/a-up-popup) attribute
1149
- - up-popup links can now have an up-fail-target attribute to indicate which selector to replace for an non-200 response
1150
- - Fix a bug where preloading an up-popup link would create an invisible .up-popup container in the DOM.
1151
- - [`up.popup.attach()`](/up.popup.attach) now throws an error if neither `{ url }` nor `{ html }` options are given.
1152
-
1153
- ### Events
1154
-
1155
- - When async functions emit an event and that event is prevented, the async function now rejects with an [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error).
1156
- - When async functions are called wth `{ confirm: true }` and the user denies confirmation, the async function now rejects with an [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error).
1157
-
1158
- ### Utility functions
1159
-
1160
- - [`up.util.setTimer()`](/up.util.setTimer) is now always async, even when called with a delay of `0` (zero). The function is now stable.
1161
- - `up.util.isHash()` has been removed without replacement. In your code you can replace `up.util.isHash(x)` with `up.util.isObject(x) && !up.util.isFunction(x)`.
1162
- - `up.util.resolvedDeferred()` has been removed without replacement. Use `Promise.resolve()` instead.
1163
- - `up.util.resolvedPromise()` has been removed without replacement. Use `Promise.resolve(`) instead.
1164
- - `up.util.rejectedPromise()` has been removed without replacement. Use `Promise.reject()` instead.
1165
- - `up.util.unresolvableDeferred()` has been removed without replacement. Use `new Promise(function() {})` instead.
1166
- - `up.motion.when()` has been removed without replacement. Use `Promise.all()` instead.
1167
- - [`up.util.isString()`](/up.util.isString) now also returns true for `String` instances (in addition to string literals)
1168
- - [`up.util.isNumber()`](/up.util.isNumber()) now also returns true for `Number` instances (in addition to number literals)
1169
-
1170
- ### Ruby on Rails bindings
1171
-
1172
- - New method `up.fail_target` available in controllers, helpers and views. It returns the selector targeted for a failed response.
1173
- - New method `up.fail_target?(target)` available in controllers, helpers and views. It returns whether the given selector is targeted for a failed response.
1174
- - New method `up.any_target?(target)` available in controllers, helpers and views. It returns whether the given selector is targeted for a either a successful or failed response.
1175
-
1176
-
1177
-
1178
- 0.37.0
1179
- ------
1180
-
1181
- ### Compatible changes
1182
-
1183
- - Fix a bug where [replacing](/up.replace) the `<body>` element would not trigger [destructor functions](/up.compiler#cleaning-up-after-yourself) in the old `<body>`.
1184
- - Fix a bug where [`[up-layer]`](/up-layer) attributes or `{ layer }` options were ignored.
1185
- - [`a[up-target]`](/a-up-target) and [`form[up-target]`] get a new modifying attribute `[up-fail-layer]`.
1186
- Use it to set the layer to update if the server sends a non-200 status code. Valid values are `auto`, `page`, `modal` and `popup`.
1187
- - JavaScript functions like [`up.replace()`](/up.replace) or [`up.submit()`](/up.submit) now have a `{ failLayer }` option.
1188
-
1189
-
1190
- 0.36.2
1191
- ------
1192
-
1193
- ### Compatible changes
1194
-
1195
- - [Validating forms](https://unpoly.com/input-up-validate) will no longer change the scroll position.
1196
-
1197
-
1198
- 0.36.1
1199
- ------
1200
-
1201
- ### Compatible changes
1202
-
1203
- - [npm package](/install/npm) now expresses Unpoly's dependency on `jquery`.
1204
- - [Modals](/up.modal) no longer close when clicking an element that exists outside the modal's DOM hierarchy.
1205
- - Fix a bug on IE11 where modals would immediately close after opening if the opening link had an [`[up-instant]`](/a-up-instant) attribute and the destination page was already cached.
1206
-
1207
-
1208
- 0.36.0
1209
- ------
1210
-
1211
- ### Compatible changes
1212
-
1213
- - The [`[up-observe]`](/up-observe) attribute can now be set on a `<form>` to run a function if any
1214
- contained input field changes.
1215
- - Fix a bug where [`[up-autosubmit]`](/form-up-autosubmit) didn't honor an `[up-delay]` attribute if
1216
- used on a form.
1217
- - When [submitting a form](/form-up-target), the `name` and `value` of the submit button is now included with the form parameters.
1218
- - [Going back in history](/up.history) after a [fragment update](/up.link) now always restores elements the page layer, never a selector in [modals](/up.modal) or [popups](/up.popup).
1219
- - [Going back in history](/up.history) now always closes a [modal](/up.modal) or [popup](/up.popup).
1220
- - Switch to [unpkg](https://unpkg.com) as our [CDN](/install/cdn).
1221
-
1222
-
1223
- 0.35.2
1224
- ------
1225
-
1226
- ### Compatible changes
1227
-
1228
- - `unpoly-rails` now supports Rails 5
1229
-
1230
-
1231
- 0.35.1
1232
- ------
1233
-
1234
- ### Compatible changes
1235
-
1236
- - Fix a bug where an Unpoly app would crash when embedded as an `<iframe>` if the user blocks third-party cookies and site data
1237
- - Fix a bug where the `up` global wasn't registered on `window` when using Webpack
1238
-
1239
-
1240
- 0.35.0
1241
- ------
1242
-
1243
- ### Compatible changes
1244
-
1245
- - Remove a use of global `$` that prevented Unpoly from being used with with [`jQuery.noConflict()`](https://api.jquery.com/jquery.noconflict/).
1246
- - Fix a bug where replacing the `<body>` element would lose the body class and other attributes
1247
- - Fix a bug where Unpoly would set the document title to a `<title>` tag of an inline SVG image.
1248
-
1249
-
1250
- ### Incompatible changes
1251
-
1252
- - Drop support for IE 9, which hasn't been supported on any platform since January 2016.
1253
- - Drop support for IE 10, which hasn't been supported since January 2016 on any platform except
1254
- Windows Vista, and Vista is end-of-life in April 2017.
1255
-
1256
-
1257
- 0.34.2
1258
- ------
1259
-
1260
- ### Compatible changes
1261
-
1262
- - The scroll positions of two [viewports](/up-viewport) with the same selector is now restored correctly when going back in history.
1263
- - Fix a bug where new modals and popups would sometime flash at full opacity before starting their opening animation.
1264
-
1265
-
1266
- 0.34.1
1267
- ------
1268
-
1269
- ### Compatible changes
1270
-
1271
- - Elements with [`up-show-for`](/up-show-for) and [`up-hide-for`](/up-hide-for) attributes
1272
- can now be inserted dynamically after its controlling [`up-switch`](/input-up-switch) field has been
1273
- compiled.
1274
- - Unpoly no longer strips a trailing slash in the current URL during startup
1275
-
1276
-
1277
- 0.34.0
1278
- ------
1279
-
1280
- ### Compatible changes
1281
-
1282
- - During the initial page load Unpoly now [reveals](/up.reveal) an element matching the
1283
- `#hash` in the current URL.
1284
-
1285
- Other than the default behavior found in browsers, `up.revealHash` works with
1286
- [multiple viewports](/up-viewport) and honors [fixed elements](/up-fixed-top) obstructing the user's
1287
- view of the viewport.
1288
- - New experimental function [`up.layout.revealHash()`](/up.layout.revealHash).
1289
- - The optional server protocol is now [documented](/up.protocol).
1290
- The protocol is already implemented by the [`unpoly-rails`](https://rubygems.org/gems/unpoly-rails) Ruby gem.
1291
- - New experimental property [`up.protocol.config`](/up.protocol.config).
1292
- - [`up.browser.isSupported()`](/up.browser.isSupported) has been promoted from experimental to stable API
1293
-
1294
-
1295
- ### Breaking changes
1296
-
1297
- - `up.proxy.config.wrapMethodParam` is now [`up.protocol.config.methodParam`](/up.protocol.config#config.methodParam).
1298
- - The event [`up:history:restored`](/up:history:restored) is no longer emitted when a history state
1299
- was not created by Unpoly.
1300
-
1301
-
1302
- 0.33.0
1303
- ------
1304
-
1305
- ### Compatible changes
1306
-
1307
- - When a fragment updates cannot find the requested element, you can now define a fallback selector to use instead.
1308
-
1309
- A `{ fallback }` option has been added to all Javascript functions that update fragments, like [`up.replace()`](/up.replace).
1310
-
1311
- Also an `[up-fallback]` attribute has been added to all CSS selectors that update fragments, like for [`a[up-target]`](/a-up-target).
1312
-
1313
- You can also define fallbacks globally using the [`up.dom.config`](/up.dom.config) property.
1314
- - Unpoly no longer crashes when a request fails due to a timeout or network problem. In such cases, async functions (like [`up.replace()`](/up.replace)) will leave the page unchanged and reject the returned promise.
1315
- - Functions that make a request (like [`up.replace()`](/up.replace) or like [`up.ajax()`](/up.ajax)) now accept a new option `{ timeout }`.
1316
- - [Modals](/up.modal) no longer create an `.up-modal` element when the server returns a non-200 status and the `{ failTarget }` is replaced instead
1317
- - [Popups](/up.popup) no longer create an `.up-popup` element when the server returns a non-200 status and the `{ failTarget }` is replaced instead
1318
- - Improve performance when updating fragments without transitions
1319
- - When updating the `body` element with a transition, that transition is now silently ignored instead of throwing an error.
1320
- - [`up.util.resolvedPromise()`](/up.util.resolvedPromise) now accepts arguments which will become the resolution values.
1321
- - [`up.util.resolvedDeferred()`](/up.util.resolvedDeferred) now accepts arguments which will become the resolution values.
1322
- - New utility method [`up.util.rejectedPromise()`](/up.util.rejectedPromise).
1323
- - [`up.first()`](/up.first) has new option `{ origin }`. You can use it provide a second element or selector that can be referenced as `&` in the first selector:
1324
-
1325
- $input = $('input.email');
1326
- up.first('.field:has(&)', $input); // returns the .field containing $input
1327
- - Fix a bug where the document title wasn't restored when the user uses the back button
1328
- - When [revealing a page fragment](/up.reveal), Unpoly will include the element's top and bottom margin in the area that should be revealed.
1329
-
1330
-
1331
- ### Breaking changes
1332
-
1333
- - [`up.replace()`](/up.replace) now returns a rejected promise if the server returns a non-200 status code.
1334
- - `up.util.merge()` has been replaced by [`up.util.assign()`](/up.util.assign), which no longer makes exceptions for `null` and `undefined` property values. This behaves like [`Object.assign`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign).
1335
- - The `up.flow` module has been renamed to [`up.dom`](/up.dom).
1336
- - The `up.navigation` module has been renamed to [`up.feedback`](/up.feedback).
1337
- - Functions that measure position, dimensions or margin now return floats instead of rounded integers.
1338
-
1339
-
1340
- 0.32.0
1341
- ------
1342
-
1343
- ### Compatible changes
1344
-
1345
- - Fix a bug where morphing an [`[up-keep]`](/up-keep) element with a destructor would throw an error.
1346
- - Fix a bug where an [`[up-keep]`](/up-keep) element would lose its jQuery event handlers when it was kept.
1347
- - Fix a bug where [`up.log.disable()`](/up.log.disable) did not persist through page reloads.
1348
- - Fix a bug where [`up.reveal()`](/up.reveal) would scroll too far if the viewport has a `padding-top`.
1349
- - Fix a bug where [`up.reveal()`](/up.reveal) would not scroll to an element at the bottom edge of the visible area
1350
- if [`up.layout.config.snap`](/up.layout.config) is set.
1351
- - Several features have been promoted from experimental API to stable API:
1352
- - [`[up-drawer]`](/a-up-drawer)
1353
- - [`up.syntax.data()`](/up.syntax.data)
1354
- - [`up.extract()`](/up.extract)
1355
- - When [targeting](/up-target) an URL with a #hash, the viewport will now scroll to the first row of an element
1356
- with that ID, rather than scrolling as little as possible.
1357
-
1358
-
1359
- ### Breaking changes
1360
-
1361
- - [Modals](/up.modal) can no longer grow wider than the screen
1362
- - The spacing around a modal dialog is longer implemented as a `margin` of `.up-modal-dialog`.
1363
- It is now a padding of `.up-modal-viewport`. This makes it easier to set the `width` or `max-width` of the dialog box.
1364
-
1365
- If your project has custom Unpoly styles, you should grep your CSS files for changes to the `margin`
1366
- of `.up-modal-dialog` and set it as a `padding` on `.up-modal-viewport[flavor=default]` instead.
1367
-
1368
-
1369
- 0.31.2
1370
- ------
1371
-
1372
- ### Compatible changes
1373
-
1374
- - Unpoly can now be installed as an npm module called `unpoly`.
1375
-
1376
-
1377
- 0.31.0
1378
- ------
1379
-
1380
- ### Compatible changes
1381
-
1382
- - Drawers are now a built-in modal flavor! Use the [`[up-drawer]`](/a-up-drawer) attribute to open page fragements
1383
- in a modal drawer that slides in from the edge of the screen.
1384
-
1385
-
1386
- ### Breaking changes
1387
-
1388
- - The [`up.modal.flavor()`](/up.modal.flavor) function was deprecated. Set values on the
1389
- [`up.modal.flavors`](/up.modal.flavors) property instead.
1390
-
1391
-
1392
- 0.30.1
1393
- ------
1394
-
1395
- ### Compatible changes
1396
-
1397
- - Fix [`up.observe()`](/up.observe) not honoring `{ delay }` option
1398
- - Fix [`[up-observe]`](/up-observe) not honoring `[up-delay]` modifier
1399
- - Fix many issues with concurrency and slow server responses for [`up.observe()`](/up.observe) and [`[up-observe]`](/up-observe)
1400
-
1401
-
1402
-
1403
- 0.30.0
1404
- ------
1405
-
1406
- ### Breaking changes
1407
-
1408
- - If you are using Unpoly's Boostrap integration, you now need to include `unpoly-bootstrap3.js` *after* you include the Bootstrap CSS.
1409
- - Fix some issues when using Unpoly together with Bootstrap modals.
1410
-
1411
-
1412
-
1413
- 0.29.0
1414
- ------
1415
-
1416
- ### Compatible changes
1417
-
1418
- - [`up.popup.attach()`](/up.popup.attach) now has a `{ html }` option. This allows you to extract popup contents
1419
- from a HTML string without making a network request.
1420
- - [`up.tooltip.attach()`](/up.tooltip.attach) now has a `{ text }` option which automatically escapes the given string.
1421
- - Fix a bug on Firefox where the page width would jump by the scrollbar width when opening a modal.
1422
- - Fix a bug where modals would close when following a link to a cached destination.
1423
-
1424
- ### Breaking changes
1425
-
1426
- - Events handled by Unpoly selectors will no longer bubble up the DOM.
1427
-
1428
-
1429
- 0.28.1
1430
- ------
1431
-
1432
- ### Compatible changes
1433
-
1434
- - [`up.tooltip.attach()`](/up.tooltip.attach) now has a `{ text }` option which automatically escapes the given string.
1435
- - Fix a bug where Unpoly would hang when parsing a page with a `<head>` but without a `<title>`
1436
-
1437
-
1438
- 0.28.0
1439
- ------
1440
-
1441
- ### Compatible changes
1442
-
1443
- - The error notification is now easier to read and can be closed.
1444
- - When a target selector was not found in the response, the error notification now offers a link to re-request the response for inspection.
1445
- - [Compilers](/up.compiler) can now return an array of functions that will *all* be called when the element is destroyed.
1446
- - [`up.observe()`](/up.observe) now works on checkboxes and radio buttons.
1447
- - [`up.observe()`](/up.observe) can now be called with multiple form fields, or any container that contains form fields.
1448
- - When opening a [modal](/up.modal) you can now pass an option `{ closable: false }` or set an `up-closable='false'` attribute
1449
- This lets you disable the default methods to close a modal (close button, clicking on the backdrop, pressing ESC).
1450
- You can also configure this globally by setting [`up.modal.config.closable`](/up.modal.config).
1451
- - Fix a bug where [`up.observe(form, options)`](/up.observe) would not respect options.
1452
- - Fix a bug where [`up.autosubmit(form)`](/up.autosubmit) was not published.
1453
- - Fix a bug where falling back to non-AJAX page loads on old browsers would not work
1454
-
1455
- ### Breaking changes
1456
-
1457
- - `up.error()` has been renamed to [`up.fail()`](/up.fail) in order to prevent confusion with [`up.log.error()`](/up.log.error).
1458
-
1459
-
1460
- 0.27.3
1461
- ------
1462
-
1463
- ### Compatible changes
1464
-
1465
- - [Popups](/up.popup) and [modals](/up.modal) will no longer try to restore a covered document title
1466
- and URL if they were opened without pushing a history entry.
1467
- - When fragments are [replaced](/up.replace) without pushing a new history entry,
1468
- the document title will no longer be changed by default.
1469
-
1470
-
1471
- ### Breaking changes
1472
-
1473
- - The `{ url }` option for [`up.destroy()`](/up.destroy) has been renamed to `{ history }` to be more
1474
- in line with [`up.replace()`](/up.replace).
1475
-
1476
-
1477
- 0.27.2
1478
- ------
1479
-
1480
- ### Compatible changes
1481
-
1482
- - Fix a bug where the back button would not work if the document contained carriage returns (`\r`).
1483
- - Fix a bug where auto-closed modals and popups would overwrite a changed
1484
- browser location with their cached "covered URL"
1485
-
1486
-
1487
- ### Breaking changes
1488
-
1489
- - Links with [`up-target`](/up.target) now prefer to update elements within their own layer (page, modal, or popup).
1490
- Only when the target element doesn't exist within the link's layer, Unpoly will look through all layers
1491
- from top to bottom.
1492
-
1493
-
1494
-
1495
- 0.27.1
1496
- ------
1497
-
1498
- ### Compatible changes
1499
-
1500
- - Fix a bug where absolutely positioned elements would be offset incorrectly during transitions
1501
- - Fix a bug where inserted elements were not revealed within their viewport
1502
- - When [validating](/input-up-validate) a form with transitions, transitions are no longer applied
1503
-
1504
-
1505
- ### Breaking changes
1506
-
1507
- - When [replacing](/up.replace) multiple page fragments at once, only the first fragment is revealed within its viewport
1508
-
1509
-
1510
- 0.27.0
1511
- ------
1512
-
1513
- ### Compatible changes
1514
-
1515
- - Calling [`up.log.enable()`](/up.log.enable) will now keep logging enabled for the remainder of this
1516
- browser session (and persist through page reloads).
1517
- - Added experimental events to observe history changes: [`up:history:push`](/up:history:push) (preventable), [`up:history:pushed`](/up:history:pushed) and [`up:history:restored`](/up:history:restored)
1518
- - Fix a bug where prepending or appending multiple elements with `:before` / `:after` pseudo-classes
1519
- would not work correctly in tables.
1520
- - Fix a bug where calling [`up.animate()`](/up.animate) with `{ duration: 0 }` would return a promise
1521
- that never resolved.
1522
- - A click on the page body now closes the popup on `mousedown` instead of `click`.
1523
- This fixes the case where an `[up-instant]` link removes its parent and thus a `click` event never bubbles up to the body.
1524
- - When opening a modal, elements behind the dialog can now be moved correctly when scrollbars have custom styles on `::-webkit-scrollbar`.
1525
- To take advantage of this, make sure to also style scrollbars on elements with an [`[up-viewport]`](/up-viewport) attribute.
1526
- - Fix a bug where [`up.tooltip.config`](/up.tooltip.config) was not publicly acccessible.
1527
- - Fix a bug where [`up.tooltip.isOpen()`](/up.tooltip.isOpen) was not publicly acccessible.
1528
- - New [tooltip configuration options](/up.tooltip.config): `config.openDuration`, `config.closeDuration`, `config.openEasing`, `config.closeEasing`
1529
- - Opening/closing many tooltips concurrently now behaves deterministically.
1530
- - Opening/closing many popups concurrently now behaves deterministically.
1531
- - Opening/closing many modals concurrently now behaves deterministically.
1532
- - IE9 fixes: Polyfill `window.console` and several properties (`log`, `debug`, `info`, `warn`, `error`, `group`, `groupCollapsed`, `groupEnd`)
1533
-
1534
-
1535
- ### Breaking changes
1536
-
1537
- - Tooltips now open and close much quicker.
1538
- - Popups now open and close much quicker.
1539
- - [`.up-current`](/a.up-current) now considers two URLs different if they have different query strings.
1540
-
1541
-
1542
-
1543
- 0.26.2
1544
- ------
1545
-
1546
- ### Compatible changes
1547
-
1548
- - Popups anchored to fixed elements are now positioned correctly if the document is scrolled
1549
- - Tooltips can now be anchored to fixed elements
1550
- - [`up-modal`](/a-up-modal) and [`up-popup`](/a-up-popup) now support an `up-method` modifier.
1551
-
1552
-
1553
-
1554
- 0.26.1
1555
- ------
1556
-
1557
- ### Breaking changes
1558
-
1559
- - When inserting a page fragment with a `<script src="...">` tag, the linked JavaScript is no longer loaded and executed. Inline scripts will still be executed. You can configure this behavior using the new [`up.flow.config`](/up.flow.config) property.
1560
-
1561
-
1562
-
1563
- 0.26.0
1564
- ------
1565
-
1566
- ### Compatible changes
1567
-
1568
- - [Popups](/up.popup) no longer scroll with the document if they are attached to an element with `position: fixed`
1569
- - [Tooltips](/up.tooltip) no longer flicker if an [`[up-tooltip]`](/up-tooltip) elements has children
1570
- - [Tooltips](/up.tooltip) no longer flicker if the user moves the mouse too close to the tooltip triangle
1571
- - Before [compiling](/up.compile) the body, Unpoly now explicitly waits until user-provided compiles have been registered and the DOM is ready.
1572
- - Debugging messages in the developer console are now disabled by default. Call [`up.log.enable()`](/up.log.enable) to get them back.
1573
- - New configuration options in [`up.log.config`](/up.log.config): `up.log.config.enabled`, `up.log.config.collapse` and
1574
- `up.log.config.prefix`.
1575
- - Improve formatting of error messages.
1576
- - New experimental utility function [`up.util.escapeHtml()`](/up.util.escapeHtml).
1577
- - If an error is thrown before the document is ready, Unpoly now waits until the document is ready before showing the red error box.
1578
-
1579
-
1580
-
1581
- 0.25.2
1582
- ------
1583
-
1584
- ### Compatible changes
1585
-
1586
- - Fix a bug where [submitting a form](/form-up-target) with file uploads would throw an error `"Cannot convert FormData into a query string"`
1587
-
1588
-
1589
-
1590
- 0.25.1
1591
- ------
1592
-
1593
- ### Compatible changes
1594
-
1595
- - Fix a bug where [`up.ajax()`](/up.ajax) would incorrectly re-use form responses even if the form data differed
1596
- - Fix a bug with the [`up-observe`](/up-observe) UJS attribute throwing an error when used
1597
- - Fix a bug where if multiple compilers with [destructors](/up.compiler#cleaning-up-after-yourself)
1598
- are applied to the same element and the element is removed, only the last destructor was called.
1599
-
1600
-
1601
- 0.25.0
1602
- ------
1603
-
1604
- ### Compatible changes
1605
-
1606
- - New modal default [`up.modal.config.sticky`](/up.modal.config)
1607
- - New experimental function [`up.modal.flavor()`](/up.modal.flavor) to register modal variants (like drawers).
1608
- - Fix a bug where [compilers](/up.compiler) and [macros](/up.macro) with higher priorities were executed last (instead of first like it says in the docs).
1609
- - Fix a bug that would occur if two compiled elements, that were nested within each other, would raise an error if the outer element was destroyed and both compilers have destructor functions.
1610
- - Fix a bug where replacing the `body` tag would raise an error if any element in the old `<body>` had a destructor function.
1611
- - The promise returned by [`up.replace()`](/up.replace) now waits for transitions to complete before resolving
1612
- - Fix a bug where an error would be shown when opening a modal while another modal was still loading
1613
- - Fix a bug where two popups would be shown when opening a popup while another popup was still loading
1614
- - New options for [up.popup.config](/up.popup.config):
1615
- - `up.popup.config.openDuration`
1616
- - `up.popup.config.closeDuration`
1617
- - `up.popup.config.openEasing`
1618
- - `up.popup.config.closeEasing`
1619
- - Modals now longer addsa right padding to the `<body>` if the document has no vertical scroll bars
1620
- - Animations now wait until the browser signals completion of the CSS transition. Previously
1621
- animations were canceled after its duration, which might or might not have matched to the actual
1622
- last animation frame.
1623
-
1624
- ### Breaking changes
1625
-
1626
- - When opening a modal while another modal is open, the first modal will be closed (with animation) before the second modal opens (with animation)
1627
- - When opening a popup while another popup is open, the first popup will be closed (with animation) before the second popup opens (with animation)
1628
- - User-defined macros are now always run *before* built-in macros.
1629
- This way you can set [`a[up-dash]`](/a-up-dash) and [`[up-expand]`](/up-expand) from your own macros.
1630
-
1631
-
1632
- 0.24.1
1633
- ------
1634
-
1635
- ### Compatible changes
1636
-
1637
- - Fix a bug that would stop transitions from working.
1638
-
1639
-
1640
- 0.24.0
1641
- ------
1642
-
1643
- ### Compatible changes
1644
-
1645
- - New function [`up.modal.extract()`](/up.modal.extract) to open a modal from an
1646
- existing HTML string.
1647
- - [`up.ajax()`](/up.ajax) now also accepts the URL as a first string argument.
1648
- - [Expanded](/up.expand) links to modals or popups now get a pointer cursor via CSS
1649
- - New options for [up.modal.config](/up.modal.config):
1650
- - `up.modal.config.openDuration`
1651
- - `up.modal.config.closeDuration`
1652
- - `up.modal.config.openEasing`
1653
- - `up.modal.config.closeEasing`
1654
- - `up.modal.config.backdropOpenAnimation`
1655
- - `up.modal.config.backdropCloseAnimation`
1656
- - Also see the breaking changes regarding modal structure below.
1657
- - Calling [`up.motion.finish()`](/up.motion.finish) without arguments will now
1658
- complete all animations and transitions on the screen.
1659
- - Fix a bug where [`up.motion.finish()`](/up.motion.finish) would not cancel CSS transitions that were still in progress.
1660
- - Fix a bug where [`up-active`](/a.up-active) classes where not removed from links when the destination
1661
- was already [preloaded](/up.preload).
1662
-
1663
-
1664
- ### Breaking changes
1665
-
1666
- - Animations when opening or closing a [modal](/up.modal) now only affect the viewport around the dialog.
1667
- The backdrop is animated separately. This allows animations like "zoom in", which would look strange if
1668
- the backdrop would zoom in together with the dialog.
1669
- - The modal's HTML structure has been changed to include a `.up-modal-backdrop` element:
1670
-
1671
- ```
1672
- <div class="up-modal">
1673
- <div class="up-modal-backdrop">
1674
- <div class="up-modal-viewport">
1675
- <div class="up-modal-dialog">
1676
- <div class="up-modal-content">
1677
- ...
1678
- </div>
1679
- <div class="up-modal-close" up-close>X</div>
1680
- </div>
1681
- </div>
1682
- </div>
1683
- ```
1684
-
1685
- - The `z-index` properties for modal elements have been [changed](https://github.com/unpoly/unpoly/blob/master/lib/assets/stylesheets/unpoly/modal.css.sass).
1686
- They might change again in the future.
1687
- - The modal will now take over the document's scrollbars after the open animation has finished.
1688
- In earlier versions the modal took over as soon as the animation had started.
1689
- - Calling [`up.motion.finish()`](/up.motion.finish) with an element will now also
1690
- complete animations/transitions on children of the given element.
1691
-
1692
-
1693
- 0.23.1
1694
- ------
1695
-
1696
- ### Compatible changes
1697
-
1698
- - [Animations](/up.motion) `move-to-*` and `move-from-*` now use CSS transforms instead of manipulating the
1699
- bounding box margins.
1700
- - Fix [`up.util.trim()`](/up.util.trim) not working properly.
1701
- - [`up.morph()`](/up.morph) no longer throws an error if called without an `options` object
1702
- - Custom transitions can now call [`up.morph()`](/up.morph) to refer to other transitions
1703
- - Fix a bug where following a link to a [preloaded](/a-up-preload) destination would keep the
1704
- link marked with a [up-active](/a.up-active) class forever.
1705
-
1706
-
1707
- 0.23.0
1708
- ------
1709
-
1710
- ### Compatible changes
1711
-
1712
- - Unpoly forms can now [submit](/up.submit) file uploads via AJAX.
1713
- - You can now position [tooltips](/up-tooltip) on the left or right side of an element.
1714
-
1715
-
1716
- ### Breaking changes
1717
-
1718
- - Tooltips have a darker background color.
1719
- - The tooltip CSS has been changed to be easier to override.
1720
-
1721
-
1722
- 0.22.1
1723
- ------
1724
-
1725
- ### Compatible changes
1726
-
1727
- - Fix a bug where the document title wasn't restored when using the back
1728
- and forward buttons
1729
- - Fix a bug where links would be followed multiple times if the link
1730
- had an [`up-dash`](/a-up-dash) attribute without a value and also an `up-target` attribute.
1731
- - Fix a bug where a link would be followed multiple times if the link's
1732
- click area was expanded using [`[up-expand]`](/up-expand) and if the
1733
- link also had an [`up-dash`](/a-up-dash) attribute.
1734
- - [`up.destroy()`](/up.destroy) now returns a resolved deferred if the given selector or jQuery collection does not exist
1735
-
1736
-
1737
- 0.22.0
1738
- ------
1739
-
1740
- ### Compatible changes
1741
-
1742
- - Fix a bug where using the `up-confirm` attribute would result in an infinite loop
1743
- - Unpoly no longer displays confirmation dialogs when [preloading](/a-up-preload) a link that
1744
- has both [`up-preload`](/a-up-preload) and `up-confirm` attributes.
1745
-
1746
-
1747
- ### Breaking changes
1748
-
1749
- - `up.proxy.idle()` is now [`up.proxy.isIdle()`](/up.proxy.isIdle)
1750
- - `up.proxy.busy()` is now [`up.proxy.isBusy()`](/up.proxy.isBusy)
1751
- - Event `up:proxy:busy` is now [`up:proxy:slow`](/up:proxy:slow)
1752
- - Event `up:proxy:idle` is now [`up:proxy:idle`](/up:proxy:recover)
1753
-
1754
-
1755
- 0.21.0
1756
- ------
1757
-
1758
- ### Compatible changes
1759
-
1760
- - New function `up.macro()`. This registers a [compiler](/up.compiler) that is run before all other compilers.
1761
- - [`up.compiler()`](/up.compiler) has a new options `{ priority }`. Compilers with higher priorities are run first.
1762
- - Fix a bug where trying to apply another transition on an element could throw a *Maximum call stack exceeded*
1763
- error if the element was already transitioning.
1764
-
1765
- ### Breaking changes
1766
-
1767
- - `up-toggle` has been renamed to `up-switch`
1768
-
1769
-
1770
- 0.20.0
1771
- ------
1772
-
1773
- - The project has been renamed to *Unpoly*.
1774
- - All functions remain in the `up` namespace, so e.g. `up.replace()` is still called `up.replace()`.
1775
- - All UJS functionality remains unchanged, so e.g. `up-target` is still called `up-target`.
1776
- - The Bower package has been renamed to `unpoly`.
1777
- - The Ruby gem for the Rails bindings has been renamed to `unpoly-rails`.
1778
- - The new JavaScript and stylesheet assets are:
1779
- - [`unpoly.js`](https://raw.githubusercontent.com/unpoly/unpoly/master/dist/unpoly.js)
1780
- - [`unpoly.min.js`](https://raw.githubusercontent.com/unpoly/unpoly/master/dist/unpoly.min.js)
1781
- - [`unpoly.css`](https://raw.githubusercontent.com/unpoly/unpoly/master/dist/unpoly.css)
1782
- - [`unpoly.min.css`](https://raw.githubusercontent.com/unpoly/unpoly/master/dist/unpoly.min.css)
1783
- - If you're using the Bootstrap integration the new assets are:
1784
- - [`unpoly-bootstrap3.js`](https://raw.githubusercontent.com/unpoly/unpoly/master/dist/unpoly-bootstrap3.js)
1785
- - [`unpoly-bootstrap3.min.js`](https://raw.githubusercontent.com/unpoly/unpoly/master/dist/unpoly-bootstrap3.min.js)
1786
- - [`unpoly-bootstrap3.css`](https://raw.githubusercontent.com/unpoly/unpoly/master/dist/unpoly-bootstrap3.css)
1787
- - [`unpoly-bootstrap3.min.css`](https://raw.githubusercontent.com/unpoly/unpoly/master/dist/unpoly-bootstrap3.min.css)
1788
-
1789
-
1790
- 0.19.0
1791
- ------
1792
-
1793
- ### Compatible changes
1794
-
1795
- - Elements can now be persisted during page updates using the [`up-keep`](/up-keep) attribute.
1796
- - `up.proxy.ajax()` is now available as [`up.ajax()`](/up.ajax).
1797
- - `up.ajax()` can now handle nested objects as `{ data }` option (used to pass form parameters).
1798
-
1799
- ### Breaking changes
1800
-
1801
- - `up.implant()` has been renamed to [`up.extract()`](/up.extract).
1802
-
1803
-
1804
- 0.18.1
1805
- ------
1806
-
1807
- ### Compatible changes
1808
-
1809
- - The logging output to the developer console is now much quieter and more useful
1810
-
1811
-
1812
- 0.18.0
1813
- ------
1814
-
1815
- ### Compatible changes
1816
-
1817
- - New UJS attribute [`[up-toggle]`](/up-toggle) to show or hide part of a form if certain options are selected or boxes are checked.
1818
- - Links can now have an optional `up-confirm` attribute. This opens a confirmation dialog with the given message
1819
- before the link is followed or the modal/popup is opened.
1820
- - New function [`up.off()`](/up.off). This unregisters an event listener previously bound with [`up.on()`](/up.on).
1821
- - If a container contains more than one link, you can now set the value of the [`up-expand`](/up-expand)
1822
- attribute to a CSS selector to define which link should be expanded.
1823
- - You can now configure a list of safe HTTP methods in [`up.proxy.config.safeMethods`](/up.proxy.config).
1824
- The proxy cache will only cache safe requests and will clear the entire
1825
- cache after a unsafe request.
1826
- - Loading modals and popups will now open if there is a fragment update between the modal/popup's
1827
- request and response.
1828
- - [`up.follow()`](/up.follow) and [`up.replace()`](/up.replace) now have an option `{ failTarget }`.
1829
- Use it to define the selector to replace if the server responds with an error.
1830
- - [`[up-target]`](/a-up-target) and [`up-follow`](/a-up-follow) now have a modifying attribute `up-fail-target`.
1831
- Use it to define the selector to replace if the server responds with an error.
1832
- - New utility method [`up.util.reject()`](/up.util.reject)
1833
- - New utility method [`up.util.only()`](/up.util.only)
1834
- - New utility method [`up.util.except()`](/up.util.except)
1835
- - Fix a bug where modals could no longer be opened on some browsers
1836
- - When preventing an event emitted by an async function, that function now rejects its promise.
1837
- - Async functions that encounter an error now prefer to reject promises with an [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) object (instead of a string with the error message)
1838
-
1839
- ### Breaking changes
1840
-
1841
- - By default Unpoly now converts `PUT`, `PATCH` and `DELETE` requests to `POST` requests
1842
- that carry their original method in a form parameter named `_method`.
1843
- This is to [prevent unexpected redirect behavior](https://makandracards.com/makandra/38347).
1844
-
1845
- Web frameworks like Ruby on Rails or Sinatra are aware of the `_method` parameter and use
1846
- its value as the method for routing.
1847
-
1848
- You can configure this behavior in [`up.proxy.config.wrapMethods`](/up.proxy.config)
1849
- and [`up.proxy.config.wrapMethodParam`](/up.proxy.config).
1850
- - The requested selector is now sent to the server as a request header `X-Up-Target`
1851
- (this used to be `X-Up-Selector`). If you are using `unpoly-rails`, you can access it
1852
- through `up.target` (this used to be `up.selector`).
1853
-
1854
-
1855
- 0.17.0
1856
- ------
1857
-
1858
- ### Compatible changes
1859
-
1860
- - When used with the [Ruby on Rails unobtrusive scripting adapter](https://github.com/rails/jquery-ujs) (`rails_ujs.js`),
1861
- now prevents duplicate form submission when Unpoly attributes are mixed with `data-method` attributes.
1862
- - [`a[up-instant]`](/a-up-instant) now works with modals and popups
1863
- - [`[up-expand]`](/up-expand) now works with modals and popups
1864
-
1865
- ### Breaking changes
1866
-
1867
- - When [`up.observe()`](/up.observe) is used with a delay of zero, the callback is invoked instantly (instead of
1868
- being invoked in the next animation frame).
1869
-
1870
-
1871
- 0.16.0
1872
- ------
1873
-
1874
- ### Compatible changes
1875
-
1876
- - You can now configure [`up.proxy.config.maxRequests`](/up.proxy.config) to limit
1877
- the maximum number of concurrent requests. Additional
1878
- requests are queued. This currently ignores preloading requests.
1879
-
1880
- You might find it useful to set this to `1` in full-stack integration
1881
- tests (e.g. Selenium).
1882
- - Allow to disable animations globally with `up.motion.enabled = false`.
1883
- This can be useful in full-stack integration tests like a Selenium test suite.
1884
- - New function [`up.motion.isEnabled`](/up.motion.isEnabled) to check if animations will be performed.
1885
- - [`up.popup.attach()`](/up.popup.attach) now throws a helpful error when trying to attach a popup to a non-existing element
1886
- - New option [`up.modal.config.history`](/up.modal.config) to configure if modals change the browser URL (defaults to `true`)
1887
- - New option [`up.popup.config.history`](/up.popup.config) to configure if popup change the browser URL (defaults to `false`).
1888
- - Fix CSS for popups with a position of `"bottom-left"`.
1889
-
1890
- ### Breaking changes
1891
-
1892
- - Popups and modals used to close automatically whenever an element behind the overlay was replaced.
1893
- This behavior is still in effect, but only if the replacement was triggered by a link or element from
1894
- within the popup or modal.
1895
- - Popups and modals no longer raise an error if their (hidden) overlay was closed before the
1896
- response was received.
1897
- - Popups and modals are now compiled before they are animated.
1898
-
1899
-
1900
- 0.15.1
1901
- ------
1902
-
1903
- ### Compatible changes
1904
-
1905
- - Fix an error where `up.form.config` was not published. This caused `unpoly-bootstrap3.js` to throw an error.
1906
-
1907
-
1908
- 0.15.0
1909
- ------
1910
-
1911
- ### Compatible changes
1912
-
1913
- - New function [`up.autosubmit()`](/up.autosubmit) and selector [`[up-autosubmit]`](/form-up-autosubmit) to
1914
- observe a form or field and submit the form when a value changes.
1915
- - [`up.observe()`](/up.observe) and [`[up-observe]`](/up-observe) can now be applied
1916
- to `<form>` tags. The callback is run when any field in the form changes.
1917
- - New function [`up.browser.canPushState()`](/up.browser.canPushState) to detect
1918
- if the browser supports `history.pushState`.
1919
- - New function [`up.browser.canCssTransition()`](/up.browser.canCssTransition) to
1920
- detect if the browser supports animation with CSS transitions.
1921
- - New function [`up.browser.canInputEvent()`](/up.browser.canInputEvent) to
1922
- detect if the browser supports the `input` event.
1923
- - Allow to [configure a default delay](/up.form.config) for [`up.observe()`](/up.observe).
1924
- - [Popups](/up.popup) now have events [`up:popup:open`](/up:popup:open),
1925
- [`up:popup:opened`](/up:popup:opened), [`up:popup:close`](/up:popup:close)
1926
- and [`up:popup:closed`](/up:popup:closed).
1927
- - The destructor returned by [`up.observe()`](/up.observe) now properly unregisters
1928
- event listeners.
1929
-
1930
- ### Breaking changes
1931
-
1932
- - [`up.observe()`](/up.observe) now takes the callback function as a last argument.
1933
- The callback can now longer be passed as a `.change` option.
1934
-
1935
-
1936
- 0.14.0
1937
- ------
1938
-
1939
- ### Compatible changes
1940
-
1941
- - Published the [up.util](/up.util) module.
1942
- This might save you from loading something like [Underscore.js](http://underscorejs.org/).
1943
-
1944
-
1945
- 0.13.0
1946
- ------
1947
-
1948
- ### Compatible changes
1949
-
1950
- - Support for server-side live validation of forms
1951
- using the [`[up-validate]`](/input-up-validate) selector.
1952
- - Support for [non-standard CSS selectors from jQuery](https://api.jquery.com/category/selectors/),
1953
- such as [`:has`](http://api.jquery.com/has-selector/) or [`:visible`](http://api.jquery.com/visible-selector/).
1954
- - Allow to refer to the current element as `&` in target selectors. This is useful
1955
- to reference containers that contain the triggering element, e.g.
1956
- `<a href="/path" up-target=".container:has(&)">`
1957
- - Improve automatic generation of selectors for elements when no
1958
- explicit selector is given.
1959
- - Forms with `file` inputs will now cause forms to fall back to a standard submission without AJAX.
1960
- In a future release we will be able to submit file inputs via AJAX.
1961
- - The [request cache](/up.proxy) now reuses responses for `body` and `html` when asked for other selectors.
1962
- - Server responses can now change the document title by including an `X-Up-Title` header.
1963
-
1964
-
1965
- 0.12.5
1966
- ------
1967
-
1968
- ### Compatible changes
1969
-
1970
- - `a[up-target]` and `up.follow` now scroll to a #hash in the link's destination URL
1971
- - When up.replace cannot make a change in old browsers, return an unresolved promise instead of a resolved promise.
1972
-
1973
-
1974
- 0.12.4
1975
- ------
1976
-
1977
- ### Compatible changes
1978
-
1979
- - When [morphing](/up.morph), prevent flickering caused by long repaint frames
1980
- - When [morphing](/up.morph) don't un-highlight current navigation sections in the element that is being destroyed. This makes for a smoother transition.
1981
- - Fix a bug where compositing wasn't forced properly during an animation
1982
-
1983
-
1984
- 0.12.3
1985
- ------
1986
-
1987
- Refactored internals. No API changes.
1988
-
1989
-
1990
- 0.12.2
1991
- ------
1992
-
1993
- ### Compatible changes
1994
-
1995
- - When marking links as `.up-current`, also consider the URL behind a current modal or popup to
1996
- be the "current" URL.
1997
-
1998
-
1999
- ### Breaking changes
2000
-
2001
- - `up.bus.emit()` is now [`up.emit()`](/up.emit)
2002
- - When `up.first()` finds no match, return `undefined` instead of `null`.
2003
-
2004
-
2005
- 0.12.1
2006
- ------
2007
-
2008
- ### Compatible changes
2009
-
2010
- - `up.on()` now returns a function that unbinds the events when called
2011
- - Fixed a bug where restoring previous scroll positions was not worked
2012
- in situations where the same operation would also reveal the replaced element.
2013
- - Various bugfixes
2014
-
2015
-
2016
- 0.12.0
2017
- ------
2018
-
2019
- ### Compatible changes
2020
-
2021
- - Unpoly can now be used with [`jQuery.noConflict()`](https://api.jquery.com/jquery.noconflict/).
2022
-
2023
-
2024
- ### Breaking changes
2025
-
2026
- - Remove `up.slot`, which was poorly implemented, untested, and not much better than the `:empty` pseudo-selector
2027
- which has great browser support
2028
- - Replaced the `up.bus.on(...)` event registry with vanilla DOM events bound to `document`. Also renamed
2029
- events in the process.
2030
-
2031
- Instead of the old ...
2032
-
2033
- up.bus.on('fragment:ready', function($fragment) {
2034
- ...
2035
- };
2036
-
2037
- ... you now need to write ...
2038
-
2039
- $(document).on('up:fragment:inserted', function(event) {
2040
- var $fragment = $(this);
2041
- ...
2042
- };
2043
-
2044
- ... or shorter:
2045
-
2046
- up.on('up:fragment:inserted', function(event, $fragment) {
2047
- ...
2048
- };
2049
- - Renamed `up.ready()` to `up.hello()`. This will emit an `up:event:inserted` event for the given element,
2050
- causing it to be compiled etc.
2051
- - `up.popup.open()` has been renamed to `up.popup.attach()`.
2052
- - `up.modal.open()` has been split into two methods `up.modal.visit(url)` and `up.modal.follow($link)`.
2053
- - `up.tooltip.open()` has been renamed to `up.tooltip.attach()`.
2054
- - Tooltips now escape HTML by default; To use HTML content, use an `[up-tooltip-html]` attribute instead.
2055
- - Module configurations are now simple properties like `up.layout.config` instead of methods like `up.layout.defaults(...)`.
2056
-
2057
- Instead of the old ...
2058
-
2059
- up.layout.defaults({ snap: 100 });
2060
-
2061
- ... you now need to write:
2062
-
2063
- up.layout.config.snap = 100;
2064
-
2065
-
2066
- 0.11.1
2067
- ------
2068
-
2069
- ### Compatible changes
2070
-
2071
- - Fix a bug where browsers without CSS animation support would crash after an animation call
2072
- - Expose `up.error()` as public API. This prints an error message to the error console and throws a new `Error` with that message.
2073
- - Fix a million bugs related to compatibility with IE9 and IE10
2074
-
2075
-
2076
- 0.11.0
2077
- ------
2078
-
2079
- ### Compatible changes
2080
-
2081
- - Rework the scrolling implementation so we don't need to scroll elements to the top before replacing them.
2082
- - `up.ajax()` now only caches responses with a status code of `200 OK`
2083
- - When a link with an `[up-close]` attribute is clicked, the link's default action will only be prevented
2084
- if the link was actually within a modal or popup.
2085
- - When revealing an element, Up will now compute the correct element position if there are
2086
- additional positioning contexts between the viewport and the element
2087
- - New option "top" for `up.reveal()`: Whether to scroll the viewport so that the first element row aligns with
2088
- the top edge of the viewport. Without this option, `up.reveal()` scrolls as little as possible.
2089
- - Allow to animate scrolling when the `document` is the viewport.
2090
- - New `up.layout` setting `fixedRight` that contains selectors for elements that are anchored to
2091
- the right edge of the screen. When opening a modal, these elements will be prevented from jumping
2092
- around. If you're using `unpoly-bootstrap3.js`, this will default to `['.navbar-fixed-top', '.navbar-fixed-bottom', '.footer']`.
2093
- - Fix a bug in `unpoly-rails` where the gem would fail to `include` itself in some versions
2094
- of Ruby and Rails.
2095
-
2096
-
2097
- ### Breaking changes
2098
-
2099
- - Interactions that would result in an URL change ("pushState") now fall back to a full page load
2100
- if Unpoly was booted from a non-GET request. [More information about the reasons for this](https://github.com/unpoly/unpoly/commit/d81d9007aa3bfae0fca8c55a71d180d1044acae5).
2101
-
2102
- This currently works out of the box if you're using Unpoly via the `unpoly-rails` Rubygem.
2103
- If you're integrating Unpoly with Bower or manually, you need to have your server app
2104
- set an `_up_request_method` cookie with the current request method on every request.
2105
-
2106
-
2107
- 0.10.5
2108
- ------
2109
-
2110
- ### Compatible changes
2111
-
2112
- - Fix a bug where the proxy would remain busy forever if a response failed.
2113
-
2114
-
2115
- 0.10.4
2116
- ------
2117
-
2118
- ### Compatible changes
2119
-
2120
- - Fix a bug where hovering multiple times over the same [up-preload] link would
2121
- not trigger a new request after the cache expired
2122
-
2123
-
2124
- 0.10.3
2125
- ------
2126
-
2127
- ### Compatible changes
2128
-
2129
- - The default viewport is now `document` instead of the `<body>` element.
2130
-
2131
-
2132
- 0.10.2
2133
- ------
2134
-
2135
- ### Breaking changes
2136
-
2137
- - While following links and submitting forms will still reveal elements by default,
2138
- direct calls of [`up.replace()`](/up.replace) no longer do.
2139
- This behavior can be activated using the `{ reveal: true }` option.
2140
-
2141
- ### Compatible changes
2142
-
2143
- - Options to control scrolling and cache use for
2144
- [`up.submit()`](/up.submit),
2145
- [`up.follow()`](/up.follow),
2146
- [`up.visit()`](/up.visit),
2147
- [`form[up-target]`](/form-up-target) and
2148
- [`a[up-target]`](/a-up-target).
2149
-
2150
-
2151
- 0.10.1
2152
- ------
2153
-
2154
- ### Breaking changes
2155
-
2156
- - [`up.reveal()`](/up.reveal) now only reveals the first 150 pixels of an element.
2157
-
2158
-
2159
- 0.10.0
2160
- -------
2161
-
2162
- ### Compatible changes
2163
-
2164
- - Viewport scroll positions are saved when the URL changes and restored when the user hits the back/forward button
2165
- - Allow to link to the previous page using [`[up-back]`](/a-up-back)
2166
- - Allow to restore previous scroll state using [`[up-restore-scroll]`](/a-up-target)
2167
- - Instead of saying `<tag up-something="true">` you can now simply say `<tag up-something>`.
2168
- - Create this Changelog.
2169
-
2170
- ### Breaking changes
2171
-
2172
- - The option `options.scroll` and attribute `up-scroll` have been removed. Instead you can use the
2173
- boolean option `options.reveal` or `up-reveal` to indicate whether an element should be revealed
2174
- within the viewport before replacement.
2175
- - The string `up.history.defaults('popTarget')` is now an array of selectors `up.history.defaults('popTargets')`
2176
-
2177
-
2178
- 0.9.1
2179
- -----
2180
-
2181
- ### Compatible changes
2182
-
2183
- - Change transition implementation so child elements with collapsing margins don't reposition within the animated element
2184
-
2185
-
2186
- 0.9.0
2187
- -----
2188
-
2189
- ### Compatible changes
2190
-
2191
- - Elements are now being [revealed](/up.reveal) within their viewport before they are updated
2192
- - Elements that are prepended or appended using `:before` or `:after` pseudo-selectors are now scrolled into view after insertion.
2193
- - New option `up.layout.defaults('snap')` lets you define a number of pixels under which Unpoly will snap to the top edge of the viewport when revealing an element
2194
- - You can now make [`up.reveal()`](/up.reveal) aware of fixed navigation bars blocking the viewport by setting new options `up.layout.defaults('fixedTop')` and `up.layout.defaults('fixedBottom')`.
2195
-
2196
-
2197
- 0.8.2
2198
- -----
2199
-
2200
- ### Compatible changes
2201
-
2202
- - [`up.reveal()`](/up.reveal) can now reveal content in modals and containers with `overflow-y: scroll`.
2203
- - Changing the default configuration of an Unpoly module now raises an error if a config key is unknown.
2204
- - Links linking to `"#"` are now never marked as `.up-current`.
2205
-
2206
-
2207
- 0.8.1
2208
- -----
2209
-
2210
- ### Compatible chanes
2211
-
2212
- - You can now include `unpoly-bootstrap3.js` and `unpoly-bootstrap3.css` to configure Unpoly to play nice with Bootstrap 3.
2213
-
2214
-
2215
- ### Breaking changes
2216
-
2217
- - Like Bootstrap, the Unpoly modal will now scroll the main document viewport instead of the modal dialog box.
2218
-
2219
-
2220
-
2221
- 0.8.0
2222
- -----
2223
-
2224
- ### Compatible changes
2225
-
2226
- - Unpoly will now emit [events](/up.bus) `proxy:busy` and `proxy:idle` whenever it is loading or is done loading content over HTTP.
2227
- - Add an option `up.proxy.defaults('busyDelay')` to delay the `proxy:busy` event in order to prevent flickering of loading spinners.
2228
-
2229
-
2230
- 0.7.8
2231
- ------
2232
-
2233
- ### Compatible changes
2234
-
2235
- - Now longer throws an error if the current location does not match an `up-alias` wildcard (bugfix).
2236
-
2237
-
2238
- 0.7.7
2239
- -----
2240
-
2241
- ### Compatible changes
2242
-
2243
- - Allow `up-alias` to match URLs by prefix (`up-alias="prefix*"`).
2244
-
2245
-
2246
- 0.7.6
2247
- -----
2248
-
2249
- ### Compatible changes
2250
-
2251
- - Fix what Unpoly considers the current URL of a modal or popup if multiple updates change different parts of the modal or popup.
2252
- - Don't replace elements within a container that matches `.up-destroying` or `.up-ghost` (which are cloned elements for animation purposes).
2253
-
2254
-
2255
- 0.7.5
2256
- -----
2257
-
2258
- ### Compatible changes
2259
-
2260
- - Make sure that an expanded link will be considered a link by adding an `up-follow` attribute if it doesn't already have an `up-target` attribute.
2261
-
2262
-
2263
- 0.7.4
2264
- -----
2265
-
2266
- ### Compatible changes
2267
-
2268
- - Correctly position tooltips when the user has scrolled the main document viewports.
2269
- - Allow popups within modal dialogs.
2270
-
2271
-
2272
- 0.7.3
2273
- -----
2274
-
2275
- ### Compatible changes
2276
-
2277
- - Use [up.proxy](/up.proxy) when submitting a form.
2278
-
2279
-
2280
- 0.7.2
2281
- -----
2282
-
2283
- ### Compatible changes
2284
-
2285
- - When marking links as `.up-current`, allow to additionally match on a space-separated list of URLs in an `up-alias` attribute.
2286
-
2287
-
2288
- 0.7.1
2289
- -----
2290
-
2291
- ### Compatible changes
2292
-
2293
- - Bugfix: Don't consider forms with an `up-target` attribute to be a link.
2294
-
2295
-
2296
- 0.7.0
2297
- -----
2298
-
2299
- ### Compatible changes
2300
-
2301
- - New selector [`[up-expand]`](/up-expand) to enlarge click areas
2302
-
2303
-
2304
- 0.6.5
2305
- -----
2306
-
2307
- ### Compatible changes
2308
-
2309
- - Animation options for `up.tooltip.open`
2310
- - Consider the left mouse button clicked when `event.button` is undefined (as happens with `.click()``)
2311
-
2312
- ### Breaking changes
2313
-
2314
- - Rename option `.origin` to `.position` in `up.popup` and `up.tooltip`
2315
-
2316
-
2317
- 0.6.4
2318
- -----
2319
-
2320
- ### Compatible changes
2321
-
2322
- - Don't follow links while CTRL, Meta or Shift keys are pressed
2323
-
2324
-
2325
- 0.6.3
2326
- -----
2327
-
2328
- ### Compatible changes
2329
-
2330
- - Show backtraces for Unpoly errors
2331
-
2332
- ### Breaking changes
2333
-
2334
- - Rename method `up.awaken()` to `up.compiler()`
2335
-
2336
-
2337
- 0.6.2
2338
- -----
2339
-
2340
- ### Compatible changes
2341
-
2342
- - Option to have a custom HTTP method for `up.follow()`
2343
- - No longer preloads links with unsafe HTTP methods
2344
-
2345
-