From 361a6b4d67a3808405b01e2198e09d13a242b16d Mon Sep 17 00:00:00 2001 From: Mischa Date: Sun, 5 Jul 2026 20:14:41 +0200 Subject: [PATCH] fix(review): harden photo reorder against data loss + failure-path drift MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses ce-code-review findings on the photo-editor media-API work: - P0 (#1): PhotoRenumberer now renumbers EVERY on-disk image, using the client manifest only as preferred ORDER and appending any omitted image at the end. A stale/incomplete `order` (e.g. a second browser tab) previously left an unlisted photo at a target slot for phase-2's rename() to silently overwrite — verified data loss, now impossible. The reorder route inherits the guard; create/reconcile is unchanged. - P2 (#3): unique per-call token in the .reorder-tmp-* name so two concurrent renumbers on one folder can't collide and clobber bytes. - P3 (#7): de-duplicate the manifest so a repeated name can't shift/drop a photo. - P2 (#2): applyReorder + doDelete split the two failure stages — a failed refresh AFTER a committed reorder/delete no longer reverts to a stale or ghost state, it reconciles to disk. A DELETE 404 is treated as success so a retried ghost cell converges. - P2 (#4): both custom routes call requirePermission('api.pages.write') so the GHSA-x7hm API-key scope cap applies (owner already holds it, so the owner-only behaviour is unchanged). - P3 (#8): refresh stale comments (photo-01..NN; drop editLoadPhotos ref). PhotoRenumberer's 7-case unit suite still passes and the data-loss repro now preserves all bytes. Assets rebuilt. Co-Authored-By: Claude Opus 4.8 --- .../cache-on-save/classes/PhotoRenumberer.php | 59 +++++++++++++++++-- .../classes/EntryActionsApiController.php | 11 +++- themes/intotheeast/js/post/post-form.js | 2 +- themes/intotheeast/js/src/post-form.js | 59 +++++++++++-------- 4 files changed, 100 insertions(+), 31 deletions(-) diff --git a/plugins/cache-on-save/classes/PhotoRenumberer.php b/plugins/cache-on-save/classes/PhotoRenumberer.php index ebf0bcd..9eb77f3 100644 --- a/plugins/cache-on-save/classes/PhotoRenumberer.php +++ b/plugins/cache-on-save/classes/PhotoRenumberer.php @@ -18,6 +18,14 @@ namespace Grav\Plugin\Shared; * renamed. A crafted manifest entry naming the entry `.md`, a `.gpx`, or a * `.meta.yaml` sidecar is silently skipped — it can never be renamed or clobbered. * This guard lives here (not only in the callers) so every caller inherits it. + * + * Completeness: renumber() ALWAYS renumbers every image already in $dir, not just + * the manifest subset. $names only supplies the preferred ORDER; any on-disk image + * the manifest omits is appended at the end. This makes an incomplete/stale + * manifest (e.g. a second browser tab whose list predates a change) harmless — + * without it, an unlisted image left sitting at a target slot would be silently + * OVERWRITTEN (destroyed) by the second-phase rename. The reorder route trusts a + * client-supplied list, so this guard is what keeps it from losing photos. */ class PhotoRenumberer { @@ -26,13 +34,16 @@ class PhotoRenumberer private const IMAGE_EXTS = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'heic', 'heif']; /** - * Rename the image files named in $names to photo-01..NN in that order, in $dir. + * Renumber every image in $dir to photo-01..NN, using $names as the preferred + * order and appending any unlisted on-disk images at the end. * * Two-phase via temp names so a target (photo-02.jpg) can't clobber a * not-yet-moved source of the same name (e.g. a straight swap or the * un-padded photo-N → photo-0N normalisation pass). Non-image and missing - * files in $names are skipped and do not consume an index, so the surviving - * images are always numbered contiguously from 01. + * files in $names are skipped and do not consume an index; a repeated name is + * counted once. Because every on-disk image becomes a target (see the + * completeness note on the class), the surviving images are numbered + * contiguously from 01 and no untouched file is ever overwritten. * * Idempotent: a file already at its correct padded name is left untouched, * so re-running with the same manifest (e.g. an auto-retried reorder) is a @@ -40,14 +51,18 @@ class PhotoRenumberer */ public static function renumber(string $dir, array $names): void { - // Keep only real image files, in the requested order — this is both the - // security filter and what determines the pad width. + // Keep only real image files, in the requested order, de-duplicated — + // this is both the security filter and what determines the pad width. $targets = []; + $seen = []; foreach ($names as $name) { if (!is_string($name) || $name === '') { continue; } $base = basename(str_replace('\\', '/', $name)); + if (isset($seen[$base])) { + continue; // a repeated name must not consume a second index + } $src = $dir . DIRECTORY_SEPARATOR . $base; if (!is_file($src)) { continue; // not on disk — skip (idempotent for auto-retry) @@ -56,11 +71,43 @@ class PhotoRenumberer if (!in_array($ext, self::IMAGE_EXTS, true)) { continue; // never rename the entry .md, a .gpx, or a sidecar } + $seen[$base] = true; $targets[] = [$src, $ext ?: 'jpg']; } + // Completeness guard: append EVERY other image already in $dir that the + // manifest didn't list (natural name order), so an incomplete/stale + // manifest can't leave an unlisted image at a target slot for phase-2 to + // overwrite. Hidden files ('.'-prefixed temp/sidecar) are never targets. + $extra = []; + foreach (@scandir($dir) ?: [] as $f) { + if ($f === '' || $f[0] === '.' || isset($seen[$f])) { + continue; + } + $p = $dir . DIRECTORY_SEPARATOR . $f; + if (!is_file($p)) { + continue; + } + $ext = strtolower(pathinfo($f, PATHINFO_EXTENSION)); + if (!in_array($ext, self::IMAGE_EXTS, true)) { + continue; + } + $extra[$f] = [$p, $ext ?: 'jpg']; + } + if ($extra) { + uksort($extra, 'strnatcasecmp'); + foreach ($extra as $t) { + $targets[] = $t; + } + } + $width = max(2, strlen((string) count($targets))); + // Unique per-call token in the temp name so two concurrent renumbers on + // the same folder can't collide on a shared '.reorder-tmp-N' path and + // overwrite one photo's bytes. + $token = bin2hex(random_bytes(4)); + $planned = []; $i = 1; foreach ($targets as [$src, $ext]) { @@ -70,7 +117,7 @@ class PhotoRenumberer $i++; continue; // already correctly named — leave it } - $tmp = $dir . DIRECTORY_SEPARATOR . '.reorder-tmp-' . $i . '.' . $ext; + $tmp = $dir . DIRECTORY_SEPARATOR . '.reorder-tmp-' . $token . '-' . $i . '.' . $ext; @rename($src, $tmp); $planned[] = [$tmp, $final]; $i++; diff --git a/plugins/entry-actions/classes/EntryActionsApiController.php b/plugins/entry-actions/classes/EntryActionsApiController.php index 2d8497a..b8ad249 100644 --- a/plugins/entry-actions/classes/EntryActionsApiController.php +++ b/plugins/entry-actions/classes/EntryActionsApiController.php @@ -35,6 +35,11 @@ class EntryActionsApiController extends AbstractApiController { // Authenticated OWNER only (KTD8). getUser() throws 401 for anonymous. $user = $this->getUser($request); + // Enforce the API-key scope cap (GHSA-x7hm) with the SAME permission the + // stock media/page-write endpoints require. The owner already holds it + // (their add/delete media uploads pass it), so this only caps a scoped + // key — it never blocks the legitimate owner. + $this->requirePermission($request, 'api.pages.write'); if (!EntryScopeGuard::isOwnerUser($this->grav, $user)) { throw new ForbiddenException('Only the site owner can delete journal entries.'); } @@ -73,12 +78,16 @@ class EntryActionsApiController extends AbstractApiController * Filename safety is defence in depth: unsafe segments (containing '/' or '..') * are dropped here, and PhotoRenumberer only ever renames files that already * exist as image media in the folder — so a crafted order body can never touch - * the entry .md, a .gpx or a .meta.yaml sidecar. + * the entry .md, a .gpx or a .meta.yaml sidecar. An incomplete `order` (e.g. a + * stale second tab) is safe too: PhotoRenumberer renumbers every on-disk image, + * appending any the manifest omits, so no photo is lost — `order` only sorts. */ public function reorderPhotos(ServerRequestInterface $request): ResponseInterface { // Authenticated OWNER only (KTD8). getUser() throws 401 for anonymous. $user = $this->getUser($request); + // Enforce the API-key scope cap (GHSA-x7hm) — see deleteEntry above. + $this->requirePermission($request, 'api.pages.write'); if (!EntryScopeGuard::isOwnerUser($this->grav, $user)) { throw new ForbiddenException('Only the site owner can reorder entry photos.'); } diff --git a/themes/intotheeast/js/post/post-form.js b/themes/intotheeast/js/post/post-form.js index 07a2ff4..832a963 100644 --- a/themes/intotheeast/js/post/post-form.js +++ b/themes/intotheeast/js/post/post-form.js @@ -92,7 +92,7 @@ Please report this to https://github.com/markedjs/marked.`,o){var f="

An error ----- `]},_p={link:"URL for the link:",image:"URL of the image:"},Bp={locale:"en-US",format:{hour:"2-digit",minute:"2-digit"}},Np={bold:"**",code:"```",italic:"*"},Op={sbInit:"Attach files by drag and dropping or pasting from clipboard.",sbOnDragEnter:"Drop image to upload it.",sbOnDrop:"Uploading image #images_names#...",sbProgress:"Uploading #file_name#: #progress#%",sbOnUploaded:"Uploaded #image_name#",sizeUnits:" B, KB, MB"},Ip={noFileGiven:"You must select a file.",typeNotAllowed:"This image type is not allowed.",fileTooLarge:`Image #image_name# is too big (#image_size#). -Maximum file size is #image_max_size#.`,importError:"Something went wrong when uploading the image #image_name#."};function te(o){o=o||{},o.parent=this;var l=!0;if(o.autoDownloadFontAwesome===!1&&(l=!1),o.autoDownloadFontAwesome!==!0)for(var s=document.styleSheets,a=0;a-1&&(l=!1);if(l){var f=document.createElement("link");f.rel="stylesheet",f.href="https://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css",document.getElementsByTagName("head")[0].appendChild(f)}if(o.element)this.element=o.element;else if(o.element===null){console.log("EasyMDE: Error. No element was found.");return}if(o.toolbar===void 0){o.toolbar=[];for(var p in Ur)Object.prototype.hasOwnProperty.call(Ur,p)&&(p.indexOf("separator-")!=-1&&o.toolbar.push("|"),(Ur[p].default===!0||o.showIcons&&o.showIcons.constructor===Array&&o.showIcons.indexOf(p)!=-1)&&o.toolbar.push(p))}if(Object.prototype.hasOwnProperty.call(o,"previewClass")||(o.previewClass="editor-preview"),Object.prototype.hasOwnProperty.call(o,"status")||(o.status=["autosave","lines","words","cursor"],o.uploadImage&&o.status.unshift("upload-image")),o.previewRender||(o.previewRender=function(h){return this.parent.markdown(h)}),o.parsingConfig=sr({highlightFormatting:!0},o.parsingConfig||{}),o.insertTexts=sr({},Mp,o.insertTexts||{}),o.promptTexts=sr({},_p,o.promptTexts||{}),o.blockStyles=sr({},Np,o.blockStyles||{}),o.autosave!=null&&(o.autosave.timeFormat=sr({},Bp,o.autosave.timeFormat||{})),o.iconClassMap=sr({},Me,o.iconClassMap||{}),o.shortcuts=sr({},Cp,o.shortcuts||{}),o.maxHeight=o.maxHeight||void 0,o.direction=o.direction||"ltr",typeof o.maxHeight<"u"?o.minHeight=o.maxHeight:o.minHeight=o.minHeight||"300px",o.errorCallback=o.errorCallback||function(h){alert(h)},o.uploadImage=o.uploadImage||!1,o.imageMaxSize=o.imageMaxSize||2097152,o.imageAccept=o.imageAccept||"image/png, image/jpeg, image/gif, image/avif",o.imageTexts=sr({},Op,o.imageTexts||{}),o.errorMessages=sr({},Ip,o.errorMessages||{}),o.imagePathAbsolute=o.imagePathAbsolute||!1,o.imageCSRFName=o.imageCSRFName||"csrfmiddlewaretoken",o.imageCSRFHeader=o.imageCSRFHeader||!1,o.imageInputName=o.imageInputName||"image",o.autosave!=null&&o.autosave.unique_id!=null&&o.autosave.unique_id!=""&&(o.autosave.uniqueId=o.autosave.unique_id),o.overlayMode&&o.overlayMode.combine===void 0&&(o.overlayMode.combine=!0),this.options=o,this.render(),o.initialValue&&(!this.options.autosave||this.options.autosave.foundSavedValue!==!0)&&this.value(o.initialValue),o.uploadImage){var c=this;this.codemirror.on("dragenter",function(h,b){c.updateStatusBar("upload-image",c.options.imageTexts.sbOnDragEnter),b.stopPropagation(),b.preventDefault()}),this.codemirror.on("dragend",function(h,b){c.updateStatusBar("upload-image",c.options.imageTexts.sbInit),b.stopPropagation(),b.preventDefault()}),this.codemirror.on("dragleave",function(h,b){c.updateStatusBar("upload-image",c.options.imageTexts.sbInit),b.stopPropagation(),b.preventDefault()}),this.codemirror.on("dragover",function(h,b){c.updateStatusBar("upload-image",c.options.imageTexts.sbOnDragEnter),b.stopPropagation(),b.preventDefault()}),this.codemirror.on("drop",function(h,b){b.stopPropagation(),b.preventDefault(),o.imageUploadFunction?c.uploadImagesUsingCustomFunction(o.imageUploadFunction,b.dataTransfer.files):c.uploadImages(b.dataTransfer.files)}),this.codemirror.on("paste",function(h,b){o.imageUploadFunction?c.uploadImagesUsingCustomFunction(o.imageUploadFunction,b.clipboardData.files):c.uploadImages(b.clipboardData.files)})}}te.prototype.uploadImages=function(o,l,s){if(o.length!==0){for(var a=[],f=0;f=2){var P=N[1];if(l.imagesPreviewHandler){var I=l.imagesPreviewHandler(N[1]);typeof I=="string"&&(P=I)}if(window.EMDEimagesCache[P])F(O,window.EMDEimagesCache[P]);else{window.EMDEimagesCache[P]={};var q=document.createElement("img");q.onload=function(){window.EMDEimagesCache[P]={naturalWidth:q.naturalWidth,naturalHeight:q.naturalHeight,url:P},F(O,window.EMDEimagesCache[P])},q.src=P}}}})}this.codemirror.on("update",function(){_()}),this.gui.sideBySide=this.createSideBySide(),this._rendered=this.element,(l.autofocus===!0||o.autofocus)&&this.codemirror.focus();var L=this.codemirror;setTimeout(function(){L.refresh()}.bind(L),0)};te.prototype.cleanup=function(){document.removeEventListener("keydown",this.documentOnKeyDown)};function Vf(){if(typeof localStorage=="object")try{localStorage.setItem("smde_localStorage",1),localStorage.removeItem("smde_localStorage")}catch{return!1}else return!1;return!0}te.prototype.autosave=function(){if(Vf()){var o=this;if(this.options.autosave.uniqueId==null||this.options.autosave.uniqueId==""){console.log("EasyMDE: You must set a uniqueId to use the autosave feature");return}this.options.autosave.binded!==!0&&(o.element.form!=null&&o.element.form!=null&&o.element.form.addEventListener("submit",function(){clearTimeout(o.autosaveTimeoutId),o.autosaveTimeoutId=void 0,localStorage.removeItem("smde_"+o.options.autosave.uniqueId)}),this.options.autosave.binded=!0),this.options.autosave.loaded!==!0&&(typeof localStorage.getItem("smde_"+this.options.autosave.uniqueId)=="string"&&localStorage.getItem("smde_"+this.options.autosave.uniqueId)!=""&&(this.codemirror.setValue(localStorage.getItem("smde_"+this.options.autosave.uniqueId)),this.options.autosave.foundSavedValue=!0),this.options.autosave.loaded=!0);var l=o.value();l!==""?localStorage.setItem("smde_"+this.options.autosave.uniqueId,l):localStorage.removeItem("smde_"+this.options.autosave.uniqueId);var s=document.getElementById("autosaved");if(s!=null&&s!=null&&s!=""){var a=new Date,f=new Intl.DateTimeFormat([this.options.autosave.timeFormat.locale,"en-US"],this.options.autosave.timeFormat.format).format(a),p=this.options.autosave.text==null?"Autosaved: ":this.options.autosave.text;s.innerHTML=p+f}}else console.log("EasyMDE: localStorage not available, cannot autosave")};te.prototype.clearAutosavedValue=function(){if(Vf()){if(this.options.autosave==null||this.options.autosave.uniqueId==null||this.options.autosave.uniqueId==""){console.log("EasyMDE: You must set a uniqueId to clear the autosave value");return}localStorage.removeItem("smde_"+this.options.autosave.uniqueId)}else console.log("EasyMDE: localStorage not available, cannot autosave")};te.prototype.openBrowseFileWindow=function(o,l){var s=this,a=this.gui.toolbar.getElementsByClassName("imageInput")[0];a.click();function f(p){s.options.imageUploadFunction?s.uploadImagesUsingCustomFunction(s.options.imageUploadFunction,p.target.files):s.uploadImages(p.target.files,o,l),a.removeEventListener("change",f)}a.addEventListener("change",f)};te.prototype.uploadImage=function(o,l,s){var a=this;l=l||function(y){Qf(a,y)};function f(b){a.updateStatusBar("upload-image",b),setTimeout(function(){a.updateStatusBar("upload-image",a.options.imageTexts.sbInit)},1e4),s&&typeof s=="function"&&s(b),a.options.errorCallback(b)}function p(b){var y=a.options.imageTexts.sizeUnits.split(",");return b.replace("#image_name#",o.name).replace("#image_size#",uo(o.size,y)).replace("#image_max_size#",uo(a.options.imageMaxSize,y))}if(o.size>this.options.imageMaxSize){f(p(this.options.errorMessages.fileTooLarge));return}var c=new FormData;c.append("image",o),a.options.imageCSRFToken&&!a.options.imageCSRFHeader&&c.append(a.options.imageCSRFName,a.options.imageCSRFToken);var h=new XMLHttpRequest;h.upload.onprogress=function(b){if(b.lengthComputable){var y=""+Math.round(b.loaded*100/b.total);a.updateStatusBar("upload-image",a.options.imageTexts.sbProgress.replace("#file_name#",o.name).replace("#progress#",y))}},h.open("POST",this.options.imageUploadEndpoint),a.options.imageCSRFToken&&a.options.imageCSRFHeader&&h.setRequestHeader(a.options.imageCSRFName,a.options.imageCSRFToken),h.onload=function(){try{var b=JSON.parse(this.responseText)}catch{console.error("EasyMDE: The server did not return a valid json."),f(p(a.options.errorMessages.importError));return}this.status===200&&b&&!b.error&&b.data&&b.data.filePath?l((a.options.imagePathAbsolute?"":window.location.origin+"/")+b.data.filePath):b.error&&b.error in a.options.errorMessages?f(p(a.options.errorMessages[b.error])):b.error?f(p(b.error)):(console.error("EasyMDE: Received an unexpected response after uploading the image."+this.status+" ("+this.statusText+")"),f(p(a.options.errorMessages.importError)))},h.onerror=function(b){console.error("EasyMDE: An unexpected error occurred when trying to upload the image."+b.target.status+" ("+b.target.statusText+")"),f(a.options.errorMessages.importError)},h.send(c)};te.prototype.uploadImageUsingCustomFunction=function(o,l){var s=this;function a(c){Qf(s,c)}function f(c){var h=p(c);s.updateStatusBar("upload-image",h),setTimeout(function(){s.updateStatusBar("upload-image",s.options.imageTexts.sbInit)},1e4),s.options.errorCallback(h)}function p(c){var h=s.options.imageTexts.sizeUnits.split(",");return c.replace("#image_name#",l.name).replace("#image_size#",uo(l.size,h)).replace("#image_max_size#",uo(s.options.imageMaxSize,h))}o.apply(this,[l,a,f])};te.prototype.setPreviewMaxHeight=function(){var o=this.codemirror,l=o.getWrapperElement(),s=l.nextSibling,a=parseInt(window.getComputedStyle(l).paddingTop),f=parseInt(window.getComputedStyle(l).borderTopWidth),p=parseInt(this.options.maxHeight),c=p+a*2+f*2,h=c.toString()+"px";s.style.height=h};te.prototype.createSideBySide=function(){var o=this.codemirror,l=o.getWrapperElement(),s=l.nextSibling;if(!s||!s.classList.contains("editor-preview-side")){if(s=document.createElement("div"),s.className="editor-preview-side",this.options.previewClass)if(Array.isArray(this.options.previewClass))for(var a=0;a"&&(l=l.substring(1)),o)try{if(o.matches)return o.matches(l);if(o.msMatchesSelector)return o.msMatchesSelector(l);if(o.webkitMatchesSelector)return o.webkitMatchesSelector(l)}catch{return!1}return!1}}function hc(o){return o.host&&o!==document&&o.host.nodeType&&o.host!==o?o.host:o.parentNode}function Gt(o,l,s,a){if(o){s=s||document;do{if(l!=null&&(l[0]===">"?o.parentNode===s&&Ro(o,l):Ro(o,l))||a&&o===s)return o;if(o===s)break}while(o=hc(o))}return null}var ic=/\s+/g;function Bt(o,l,s){if(o&&l)if(o.classList)o.classList[s?"add":"remove"](l);else{var a=(" "+o.className+" ").replace(ic," ").replace(" "+l+" "," ");o.className=(a+(s?" "+l:"")).replace(ic," ")}}function he(o,l,s){var a=o&&o.style;if(a){if(s===void 0)return document.defaultView&&document.defaultView.getComputedStyle?s=document.defaultView.getComputedStyle(o,""):o.currentStyle&&(s=o.currentStyle),l===void 0?s:s[l];!(l in a)&&l.indexOf("webkit")===-1&&(l="-webkit-"+l),a[l]=s+(typeof s=="string"?"":"px")}}function An(o,l){var s="";if(typeof o=="string")s=o;else do{var a=he(o,"transform");a&&a!=="none"&&(s=a+" "+s)}while(!l&&(o=o.parentNode));var f=window.DOMMatrix||window.WebKitCSSMatrix||window.CSSMatrix||window.MSCSSMatrix;return f&&new f(s)}function pc(o,l,s){if(o){var a=o.getElementsByTagName(l),f=0,p=a.length;if(s)for(;f=p:c=f<=p,!c)return a;if(a===Vt())break;a=Tr(a,!1)}return!1}function Fn(o,l,s,a){for(var f=0,p=0,c=o.children;p2&&arguments[2]!==void 0?arguments[2]:{},f=a.evt,p=zp(a,Qp);xi.pluginEvent.bind(pe)(l,s,er({dragEl:$,parentEl:qe,ghostEl:be,rootEl:Pe,nextEl:Yr,lastDownEl:Io,cloneEl:Re,cloneHidden:Fr,dragStarted:ci,putSortable:ut,activeSortable:pe.active,originalEvent:f,oldIndex:En,oldDraggableIndex:vi,newIndex:Nt,newDraggableIndex:Ar,hideGhostForTarget:wc,unhideGhostForTarget:Cc,cloneNowHidden:function(){Fr=!0},cloneNowShown:function(){Fr=!1},dispatchSortableEvent:function(h){Ct({sortable:s,name:h,originalEvent:f})}},p))};function Ct(o){Zp(er({putSortable:ut,cloneEl:Re,targetEl:$,rootEl:Pe,oldIndex:En,oldDraggableIndex:vi,newIndex:Nt,newDraggableIndex:Ar},o))}var $,qe,be,Pe,Yr,Io,Re,Fr,En,Nt,vi,Ar,_o,ut,Sn=!1,Wo=!1,qo=[],Xr,jt,Dl,wl,lc,sc,ci,kn,mi,bi=!1,Bo=!1,Po,pt,Cl=[],Tl=!1,Uo=[],Go=typeof document<"u",No=Bl,uc=yi||cr?"cssFloat":"float",Jp=Go&&!cc&&!Bl&&"draggable"in document.createElement("div"),yc=function(){if(Go){if(cr)return!1;var o=document.createElement("x");return o.style.cssText="pointer-events:auto",o.style.pointerEvents==="auto"}}(),xc=function(l,s){var a=he(l),f=parseInt(a.width)-parseInt(a.paddingLeft)-parseInt(a.paddingRight)-parseInt(a.borderLeftWidth)-parseInt(a.borderRightWidth),p=Fn(l,0,s),c=Fn(l,1,s),h=p&&he(p),b=c&&he(c),y=h&&parseInt(h.marginLeft)+parseInt(h.marginRight)+$e(p).width,x=b&&parseInt(b.marginLeft)+parseInt(b.marginRight)+$e(c).width;if(a.display==="flex")return a.flexDirection==="column"||a.flexDirection==="column-reverse"?"vertical":"horizontal";if(a.display==="grid")return a.gridTemplateColumns.split(" ").length<=1?"vertical":"horizontal";if(p&&h.float&&h.float!=="none"){var C=h.float==="left"?"left":"right";return c&&(b.clear==="both"||b.clear===C)?"vertical":"horizontal"}return p&&(h.display==="block"||h.display==="flex"||h.display==="table"||h.display==="grid"||y>=f&&a[uc]==="none"||c&&a[uc]==="none"&&y+x>f)?"vertical":"horizontal"},$p=function(l,s,a){var f=a?l.left:l.top,p=a?l.right:l.bottom,c=a?l.width:l.height,h=a?s.left:s.top,b=a?s.right:s.bottom,y=a?s.width:s.height;return f===h||p===b||f+c/2===h+y/2},Vp=function(l,s){var a;return qo.some(function(f){var p=f[Ft].options.emptyInsertThreshold;if(!(!p||Nl(f))){var c=$e(f),h=l>=c.left-p&&l<=c.right+p,b=s>=c.top-p&&s<=c.bottom+p;if(h&&b)return a=f}}),a},Dc=function(l){function s(p,c){return function(h,b,y,x){var C=h.options.group.name&&b.options.group.name&&h.options.group.name===b.options.group.name;if(p==null&&(c||C))return!0;if(p==null||p===!1)return!1;if(c&&p==="clone")return p;if(typeof p=="function")return s(p(h,b,y,x),c)(h,b,y,x);var S=(c?h:b).options.group.name;return p===!0||typeof p=="string"&&p===S||p.join&&p.indexOf(S)>-1}}var a={},f=l.group;(!f||Fl(f)!="object")&&(f={name:f}),a.name=f.name,a.checkPull=s(f.pull,!0),a.checkPut=s(f.put),a.revertClone=f.revertClone,l.group=a},wc=function(){!yc&&be&&he(be,"display","none")},Cc=function(){!yc&&be&&he(be,"display","")};Go&&!cc&&document.addEventListener("click",function(o){if(Wo)return o.preventDefault(),o.stopPropagation&&o.stopPropagation(),o.stopImmediatePropagation&&o.stopImmediatePropagation(),Wo=!1,!1},!0);var Kr=function(l){if($){l=l.touches?l.touches[0]:l;var s=Vp(l.clientX,l.clientY);if(s){var a={};for(var f in l)l.hasOwnProperty(f)&&(a[f]=l[f]);a.target=a.rootEl=s,a.preventDefault=void 0,a.stopPropagation=void 0,s[Ft]._onDragOver(a)}}},eg=function(l){$&&$.parentNode[Ft]._isOutsideThisEl(l.target)};function pe(o,l){if(!(o&&o.nodeType&&o.nodeType===1))throw"Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(o));this.el=o,this.options=l=fr({},l),o[Ft]=this;var s={group:null,sort:!0,disabled:!1,store:null,handle:null,draggable:/^[uo]l$/i.test(o.nodeName)?">li":">*",swapThreshold:1,invertSwap:!1,invertedSwapThreshold:null,removeCloneOnHide:!0,direction:function(){return xc(o,this.options)},ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",dragClass:"sortable-drag",ignore:"a, img",filter:null,preventOnFilter:!0,animation:0,easing:null,setData:function(c,h){c.setData("Text",h.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,delayOnTouchOnly:!1,touchStartThreshold:(Number.parseInt?Number:window).parseInt(window.devicePixelRatio,10)||1,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1,fallbackTolerance:0,fallbackOffset:{x:0,y:0},supportPointer:pe.supportPointer!==!1&&"PointerEvent"in window&&(!pi||Bl),emptyInsertThreshold:5};xi.initializePlugins(this,o,s);for(var a in s)!(a in l)&&(l[a]=s[a]);Dc(l);for(var f in this)f.charAt(0)==="_"&&typeof this[f]=="function"&&(this[f]=this[f].bind(this));this.nativeDraggable=l.forceFallback?!1:Jp,this.nativeDraggable&&(this.options.touchStartThreshold=1),l.supportPointer?ke(o,"pointerdown",this._onTapStart):(ke(o,"mousedown",this._onTapStart),ke(o,"touchstart",this._onTapStart)),this.nativeDraggable&&(ke(o,"dragover",this),ke(o,"dragenter",this)),qo.push(this.el),l.store&&l.store.get&&this.sort(l.store.get(this)||[]),fr(this,Xp())}pe.prototype={constructor:pe,_isOutsideThisEl:function(l){!this.el.contains(l)&&l!==this.el&&(kn=null)},_getDirection:function(l,s){return typeof this.options.direction=="function"?this.options.direction.call(this,l,s,$):this.options.direction},_onTapStart:function(l){if(l.cancelable){var s=this,a=this.el,f=this.options,p=f.preventOnFilter,c=l.type,h=l.touches&&l.touches[0]||l.pointerType&&l.pointerType==="touch"&&l,b=(h||l).target,y=l.target.shadowRoot&&(l.path&&l.path[0]||l.composedPath&&l.composedPath()[0])||b,x=f.filter;if(sg(a),!$&&!(/mousedown|pointerdown/.test(c)&&l.button!==0||f.disabled)&&!y.isContentEditable&&!(!this.nativeDraggable&&pi&&b&&b.tagName.toUpperCase()==="SELECT")&&(b=Gt(b,f.draggable,a,!1),!(b&&b.animated)&&Io!==b)){if(En=Pt(b),vi=Pt(b,f.draggable),typeof x=="function"){if(x.call(this,l,b,this)){Ct({sortable:s,rootEl:y,name:"filter",targetEl:b,toEl:a,fromEl:a}),At("filter",s,{evt:l}),p&&l.preventDefault();return}}else if(x&&(x=x.split(",").some(function(C){if(C=Gt(y,C.trim(),a,!1),C)return Ct({sortable:s,rootEl:C,name:"filter",targetEl:b,fromEl:a,toEl:a}),At("filter",s,{evt:l}),!0}),x)){p&&l.preventDefault();return}f.handle&&!Gt(y,f.handle,a,!1)||this._prepareDragStart(l,h,b)}}},_prepareDragStart:function(l,s,a){var f=this,p=f.el,c=f.options,h=p.ownerDocument,b;if(a&&!$&&a.parentNode===p){var y=$e(a);if(Pe=p,$=a,qe=$.parentNode,Yr=$.nextSibling,Io=a,_o=c.group,pe.dragged=$,Xr={target:$,clientX:(s||l).clientX,clientY:(s||l).clientY},lc=Xr.clientX-y.left,sc=Xr.clientY-y.top,this._lastX=(s||l).clientX,this._lastY=(s||l).clientY,$.style["will-change"]="all",b=function(){if(At("delayEnded",f,{evt:l}),pe.eventCanceled){f._onDrop();return}f._disableDelayedDragEvents(),!nc&&f.nativeDraggable&&($.draggable=!0),f._triggerDragStart(l,s),Ct({sortable:f,name:"choose",originalEvent:l}),Bt($,c.chosenClass,!0)},c.ignore.split(",").forEach(function(x){pc($,x.trim(),kl)}),ke(h,"dragover",Kr),ke(h,"mousemove",Kr),ke(h,"touchmove",Kr),c.supportPointer?(ke(h,"pointerup",f._onDrop),!this.nativeDraggable&&ke(h,"pointercancel",f._onDrop)):(ke(h,"mouseup",f._onDrop),ke(h,"touchend",f._onDrop),ke(h,"touchcancel",f._onDrop)),nc&&this.nativeDraggable&&(this.options.touchStartThreshold=4,$.draggable=!0),At("delayStart",this,{evt:l}),c.delay&&(!c.delayOnTouchOnly||s)&&(!this.nativeDraggable||!(yi||cr))){if(pe.eventCanceled){this._onDrop();return}c.supportPointer?(ke(h,"pointerup",f._disableDelayedDrag),ke(h,"pointercancel",f._disableDelayedDrag)):(ke(h,"mouseup",f._disableDelayedDrag),ke(h,"touchend",f._disableDelayedDrag),ke(h,"touchcancel",f._disableDelayedDrag)),ke(h,"mousemove",f._delayedDragTouchMoveHandler),ke(h,"touchmove",f._delayedDragTouchMoveHandler),c.supportPointer&&ke(h,"pointermove",f._delayedDragTouchMoveHandler),f._dragStartTimer=setTimeout(b,c.delay)}else b()}},_delayedDragTouchMoveHandler:function(l){var s=l.touches?l.touches[0]:l;Math.max(Math.abs(s.clientX-this._lastX),Math.abs(s.clientY-this._lastY))>=Math.floor(this.options.touchStartThreshold/(this.nativeDraggable&&window.devicePixelRatio||1))&&this._disableDelayedDrag()},_disableDelayedDrag:function(){$&&kl($),clearTimeout(this._dragStartTimer),this._disableDelayedDragEvents()},_disableDelayedDragEvents:function(){var l=this.el.ownerDocument;Ce(l,"mouseup",this._disableDelayedDrag),Ce(l,"touchend",this._disableDelayedDrag),Ce(l,"touchcancel",this._disableDelayedDrag),Ce(l,"pointerup",this._disableDelayedDrag),Ce(l,"pointercancel",this._disableDelayedDrag),Ce(l,"mousemove",this._delayedDragTouchMoveHandler),Ce(l,"touchmove",this._delayedDragTouchMoveHandler),Ce(l,"pointermove",this._delayedDragTouchMoveHandler)},_triggerDragStart:function(l,s){s=s||l.pointerType=="touch"&&l,!this.nativeDraggable||s?this.options.supportPointer?ke(document,"pointermove",this._onTouchMove):s?ke(document,"touchmove",this._onTouchMove):ke(document,"mousemove",this._onTouchMove):(ke($,"dragend",this),ke(Pe,"dragstart",this._onDragStart));try{document.selection?zo(function(){document.selection.empty()}):window.getSelection().removeAllRanges()}catch{}},_dragStarted:function(l,s){if(Sn=!1,Pe&&$){At("dragStarted",this,{evt:s}),this.nativeDraggable&&ke(document,"dragover",eg);var a=this.options;!l&&Bt($,a.dragClass,!1),Bt($,a.ghostClass,!0),pe.active=this,l&&this._appendGhost(),Ct({sortable:this,name:"start",originalEvent:s})}else this._nulling()},_emulateDragOver:function(){if(jt){this._lastX=jt.clientX,this._lastY=jt.clientY,wc();for(var l=document.elementFromPoint(jt.clientX,jt.clientY),s=l;l&&l.shadowRoot&&(l=l.shadowRoot.elementFromPoint(jt.clientX,jt.clientY),l!==s);)s=l;if($.parentNode[Ft]._isOutsideThisEl(l),s)do{if(s[Ft]){var a=void 0;if(a=s[Ft]._onDragOver({clientX:jt.clientX,clientY:jt.clientY,target:l,rootEl:s}),a&&!this.options.dragoverBubble)break}l=s}while(s=hc(s));Cc()}},_onTouchMove:function(l){if(Xr){var s=this.options,a=s.fallbackTolerance,f=s.fallbackOffset,p=l.touches?l.touches[0]:l,c=be&&An(be,!0),h=be&&c&&c.a,b=be&&c&&c.d,y=No&&pt&&ac(pt),x=(p.clientX-Xr.clientX+f.x)/(h||1)+(y?y[0]-Cl[0]:0)/(h||1),C=(p.clientY-Xr.clientY+f.y)/(b||1)+(y?y[1]-Cl[1]:0)/(b||1);if(!pe.active&&!Sn){if(a&&Math.max(Math.abs(p.clientX-this._lastX),Math.abs(p.clientY-this._lastY))=0&&(Ct({rootEl:qe,name:"add",toEl:qe,fromEl:Pe,originalEvent:l}),Ct({sortable:this,name:"remove",toEl:qe,originalEvent:l}),Ct({rootEl:qe,name:"sort",toEl:qe,fromEl:Pe,originalEvent:l}),Ct({sortable:this,name:"sort",toEl:qe,originalEvent:l})),ut&&ut.save()):Nt!==En&&Nt>=0&&(Ct({sortable:this,name:"update",toEl:qe,originalEvent:l}),Ct({sortable:this,name:"sort",toEl:qe,originalEvent:l})),pe.active&&((Nt==null||Nt===-1)&&(Nt=En,Ar=vi),Ct({sortable:this,name:"end",toEl:qe,originalEvent:l}),this.save()))),this._nulling()},_nulling:function(){At("nulling",this),Pe=$=qe=be=Yr=Re=Io=Fr=Xr=jt=ci=Nt=Ar=En=vi=kn=mi=ut=_o=pe.dragged=pe.ghost=pe.clone=pe.active=null;var l=this.el;Uo.forEach(function(s){l.contains(s)&&(s.checked=!0)}),Uo.length=Dl=wl=0},handleEvent:function(l){switch(l.type){case"drop":case"dragend":this._onDrop(l);break;case"dragenter":case"dragover":$&&(this._onDragOver(l),tg(l));break;case"selectstart":l.preventDefault();break}},toArray:function(){for(var l=[],s,a=this.el.children,f=0,p=a.length,c=this.options;ff.right+p||o.clientY>a.bottom&&o.clientX>a.left:o.clientY>f.bottom+p||o.clientX>a.right&&o.clientY>a.top}function og(o,l,s,a,f,p,c,h){var b=a?o.clientY:o.clientX,y=a?s.height:s.width,x=a?s.top:s.left,C=a?s.bottom:s.right,S=!1;if(!c){if(h&&Pox+y*p/2:bC-Po)return-mi}else if(b>x+y*(1-f)/2&&bC-y*p/2)?b>x+y/2?1:-1:0}function ag(o){return Pt($)0||C>0&&S0?"Converting "+l+" photo"+(l>1?"s":"")+"\u2026":"Uploading "+C+" photo"+(C>1?"s":"")+"\u2026",s.details.open=!0):C>0?(s.summary.textContent="\u2713 "+C+" photo"+(C>1?"s":"")+" ready \u2014 tap to review",s.details.open=!1):(s.summary.textContent="Photos (1\u20136)",s.details.open=!0)}}function c(){p(),setTimeout(p,150),setTimeout(p,500)}function h(){var x=o.querySelector('button[type="submit"], input[type="submit"]');if(x&&(x.disabled=l>0),l>0)f("Converting "+l+" photo"+(l>1?"s":"")+"\u2026");else{var C=Ec();C&&/Converting/.test(C.textContent)&&f("")}p()}o.addEventListener("submit",function(x){l>0&&(x.preventDefault(),f("Hang on \u2014 a photo is still converting.","err"))},!0);function b(x){return function(C){var S=C&&C.file;return S?_c(S).then(function(F){return F?(l++,h(),import("./heic-to-CN7JBE7H.js").then(function(_){var L=_.heicTo||_.default&&_.default.heicTo;return L({blob:S,type:"image/jpeg",quality:.85})}).then(function(_){var L=new File([_],dg(S.name),{type:"image/jpeg"});x.addFile(L)}).catch(function(){f("A photo couldn\u2019t be converted and was skipped \u2014 the others are fine.","err")}).then(function(){l--,h()}),!1):!0}):!0}}var y=0;(function x(){var C=window.GravFilePond&&window.GravFilePond.getInstances?window.GravFilePond.getInstances():[];if(!C.length){y++<120&&setTimeout(x,50);return}C.forEach(function(S){S&&!S._heicHooked&&(S._heicHooked=!0,S.setOptions({beforeAddFile:b(S),allowReorder:!0,itemInsertLocation:"after"}),a=S,["addfile","processfile","processfiles","removefile","error"].forEach(function(F){try{S.on(F,c)}catch{}}),p())})})()}function Ot(o){return document.querySelector('[name="data['+o+']"]')}function gg(){var o=Array.prototype.slice.call(document.querySelectorAll(".advanced-field"));if(o.length){var l=[];if(o.forEach(function(p){var c=p.closest(".form-field");c&&l.indexOf(c)===-1&&l.push(c)}),!!l.length){var s=document.createElement("details");s.className="more-options";var a=document.createElement("summary");a.className="more-options__summary",a.textContent="More options",s.appendChild(a),l[0].parentNode.insertBefore(s,l[0]),l.forEach(function(p){s.appendChild(p)});var f=l.some(function(p){var c=p.querySelector('input[type="text"]');if(c&&c.value.trim())return!0;var h=p.querySelector('input[type="radio"]:checked');return!!(h&&h.value&&h.value!=="0")});f&&(s.open=!0)}}}var vg={0:"Sunny",1:"Partly cloudy",2:"Partly cloudy",3:"Cloudy",45:"Foggy",48:"Foggy",51:"Drizzle",53:"Drizzle",55:"Drizzle",56:"Drizzle",57:"Drizzle",61:"Rain",63:"Rain",65:"Rain",66:"Rain",67:"Rain",80:"Rain",81:"Rain",82:"Rain",71:"Snow",73:"Snow",75:"Snow",77:"Snow",85:"Snow",86:"Snow",95:"Thunderstorm",96:"Thunderstorm",99:"Thunderstorm"};function dr(o,l,s){o&&(o.className="form-status"+(s?" form-status--"+s:""),o.textContent=l||"")}function mg(){var o=document.getElementById("get-location"),l=document.getElementById("get-weather");if(!o&&!l)return;var s=document.getElementById("location-status"),a=document.getElementById("weather-status");function f(){var h=Ot("lat"),b=Ot("lng"),y=h?h.value.trim():"",x=b?b.value.trim():"";return y&&x?{lat:y,lng:x}:null}function p(){if(l){var h=!!f();l.disabled=!h,l.title=h?"":"Get location first"}}p();function c(h,b){var y=Ot("location_city"),x=Ot("location_country");if(!((!y||y.value.trim())&&(!x||x.value.trim()))){var C="https://api.bigdatacloud.net/data/reverse-geocode-client?latitude="+encodeURIComponent(h)+"&longitude="+encodeURIComponent(b)+"&localityLanguage=en";fetch(C).then(function(S){return S.json()}).then(function(S){var F=(S.city||S.locality||"").trim(),_=(S.countryName||"").trim();y&&!y.value.trim()&&F&&(y.value=F),x&&!x.value.trim()&&_&&(x.value=_);var L=[F,_].filter(Boolean).join(", ");L&&dr(s,"\u2713 Location captured \xB7 "+L,"ok")}).catch(function(){})}}o&&o.addEventListener("click",function(){if(!navigator.geolocation){dr(s,"Geolocation is not supported on this device.","err");return}o.classList.add("is-loading"),o.disabled=!0,dr(s,"Getting location\u2026"),navigator.geolocation.getCurrentPosition(function(h){var b=h.coords.latitude.toFixed(6),y=h.coords.longitude.toFixed(6),x=Ot("lat"),C=Ot("lng");x&&(x.value=b),C&&(C.value=y),o.classList.remove("is-loading"),o.disabled=!1,dr(s,"\u2713 Location captured \xB7 "+b+", "+y,"ok"),p(),c(b,y)},function(h){o.classList.remove("is-loading"),o.disabled=!1,dr(s,"\u2717 "+(h&&h.message?h.message:"Could not get location")+" \u2014 enter coordinates manually if needed.","err")},{enableHighAccuracy:!0,timeout:15e3})}),l&&l.addEventListener("click",function(){var h=f();if(!h){dr(a,"Get location first, then fetch weather.","err");return}l.classList.add("is-loading"),l.disabled=!0,dr(a,"Fetching weather\u2026");var b="https://api.open-meteo.com/v1/forecast?latitude="+h.lat+"&longitude="+h.lng+"¤t=temperature_2m,weather_code&temperature_unit=celsius";fetch(b).then(function(y){return y.json()}).then(function(y){var x=Math.round(y.current.temperature_2m),C=vg[y.current.weather_code]||"Cloudy",S=Ot("weather_temp_c"),F=Ot("weather_desc");S&&(S.value=x),F&&(F.value=C),l.classList.remove("is-loading"),p(),dr(a,"\u2713 Weather set \xB7 "+C+" \xB7 "+x+"\xB0C (edit above if needed)","ok")}).catch(function(){l.classList.remove("is-loading"),p(),dr(a,"\u2717 Could not fetch weather \u2014 set it manually above.","err")})})}function bg(){var o=new Date;return o.setSeconds(0,0),o.setMinutes(o.getMinutes()-o.getTimezoneOffset()),o.toISOString().slice(0,16)}function yg(){var o={title:"Title",date:"Date & time",content:"Content"},l=document.querySelector('form[name="new-entry"]');if(!l)return;var s=Ot("date");s&&!String(s.value).trim()&&(s.value=bg());function a(){l.querySelectorAll(".field-error").forEach(function(c){c.remove()}),l.querySelectorAll(".field-invalid").forEach(function(c){c.classList.remove("field-invalid")})}function f(c,h){c.classList.add("field-invalid");var b=document.createElement("span");b.className="field-error",b.textContent=h,c.parentNode.insertBefore(b,c.nextSibling)}function p(c){var h=l.querySelector(".photos-collapse"),b,y;if(h?(h.open=!0,y=h.querySelector(".photos-collapse__summary"),b=h):(b=document.querySelector(".filepond-root, .form-input-file"),y=b),!y)return b||null;var x=document.createElement("span");return x.className="field-error",x.textContent=c,y.insertAdjacentElement("afterend",x),b||y}l.addEventListener("submit",function(c){a();var h=null;!Xo&&document.querySelectorAll(".filepond--item").length<1&&(h=p("Add at least one photo.")),Object.keys(o).forEach(function(b){var y=Ot(b);y&&!String(y.value).trim()&&(f(y,o[b]+" is required."),h||(h=y))}),h&&(c.preventDefault(),typeof h.focus=="function"&&h.focus(),h.scrollIntoView({behavior:"smooth",block:"center"}))})}var Pl="intotheeast:new-entry-draft";function xg(o){return Array.prototype.slice.call(o.querySelectorAll('[name^="data["]')).filter(function(l){if(l.type==="file")return!1;var s=l.name;return s.indexOf("data[_json")!==0&&s.indexOf("data[photos")!==0})}function Dg(){var o=document.querySelector(".filepond-root, .form-input-file");if(!(!o||!o.parentNode)&&!o.parentNode.querySelector(".photo-reauth-hint")){var l=document.createElement("p");l.className="photo-reauth-hint is-shown",l.textContent="Your text was restored \u2014 photos need re-selecting (they can\u2019t be saved in a draft).",o.parentNode.insertBefore(l,o.nextSibling)}}function wg(){var o=document.querySelector('form[name="new-entry"]');if(!o||Xo)return;if(document.querySelector(".notices.success")){try{localStorage.removeItem(Pl)}catch{}return}function l(){var p={};xg(o).forEach(function(c){c.type==="radio"?c.checked&&(p[c.name]=c.value):p[c.name]=c.value});try{localStorage.setItem(Pl,JSON.stringify(p))}catch{}}var s=null;try{s=localStorage.getItem(Pl)}catch{s=null}if(s){var a=null;try{a=JSON.parse(s)}catch{a=null}if(a){var f=!1;Object.keys(a).forEach(function(p){var c=a[p];if(c!=null&&String(c).trim()&&(f=!0),p!=="data[content]"){var h=o.querySelectorAll('input[type="radio"][name="'+p+'"]');if(h.length){h.forEach(function(y){y.checked=y.value===c});return}var b=o.querySelector('[name="'+p+'"]');b&&b.type!=="file"&&(b.value=c)}}),window.postFormEditor&&a["data[content]"]!=null&&window.postFormEditor.value(a["data[content]"]),f&&Dg()}}o.addEventListener("input",l),o.addEventListener("change",l),window.postFormEditor&&window.postFormEditor.codemirror.on("change",l)}function Cg(){var o=document.querySelector(".post-form-wrap"),l=document.querySelector(".post-form-wrap .notices.success, .post-form-wrap .notices.green");if(!(!o||!l)){var s=document.createElement("div");s.className="post-success";var a=document.createElement("p");a.className="post-success__title",a.textContent="\u2713 Saved to your journal.",s.appendChild(a);var f=document.createElement("div");f.className="post-success__actions";var p=o.getAttribute("data-trip-url");if(p){var c=document.createElement("a");c.className="post-success__view",c.href=p,c.textContent="View your journal \u2192",f.appendChild(c)}var h=document.createElement("a");h.className="post-success__again",h.href=window.location.pathname,h.textContent="Post another",f.appendChild(h),s.appendChild(f),l.parentNode.insertBefore(s,l.nextSibling),["form",".form-action-row","#location-status","#weather-status"].forEach(function(b){var y=o.querySelector(b);y&&(y.style.display="none")}),l.scrollIntoView({behavior:"smooth",block:"start"})}}var Xo=!1;function Ac(o){return new URLSearchParams(window.location.search).get(o)}function hr(o,l){var s=Ot(o);s&&(s.value=l==null?"":String(l))}function zl(o,l){var s=l?"1":"0",a=document.querySelectorAll('[name="data['+o+']"]');Array.prototype.forEach.call(a,function(f){f.checked=String(f.value)===s})}function kg(o){var l=o==null?"":String(o);if(window.postFormEditor&&typeof window.postFormEditor.value=="function")window.postFormEditor.value(l);else{var s=Ot("content");s&&(s.value=l)}}function Fc(o,l){var s=o.querySelectorAll("input, textarea, select, button");Array.prototype.forEach.call(s,function(a){a.type==="file"||a.name&&a.name.indexOf("data[photos")===0||(a.disabled=l)}),window.postFormEditor&&window.postFormEditor.codemirror&&window.postFormEditor.codemirror.setOption("readOnly",l?"nocursor":!1)}function Hl(o,l){o&&(o.tagName==="INPUT"?o.value=l:o.textContent=l)}function Sg(o,l){var s=o.querySelector(".post-edit-error");if(s){s.textContent=l;return}var a=document.createElement("div");a.className="post-edit-error",a.setAttribute("role","alert"),a.textContent=l;var f=o.querySelector("h1");f?f.insertAdjacentElement("afterend",a):o.insertBefore(a,o.firstChild)}var Eg=/\.(jpe?g|png|webp|heic|heif|gif)$/i;function Tc(o){var l=/(?:^|\/)photo-0*(\d+)\./i.exec(o);return l?parseInt(l[1],10):Number.MAX_SAFE_INTEGER}function Ag(o,l){var s=Tc(o),a=Tc(l);return s!==a?s-a:ol?1:0}function Lc(o,l){var s=String(o||"photo"),a=s.lastIndexOf("."),f=(a>0?s.slice(0,a):s).toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"photo",p=l?".jpg":a>0?s.slice(a).toLowerCase():".jpg",c=Date.now().toString(36)+Math.random().toString(36).slice(2,6);return f+"-"+c+p}function Fg(o){var l=document.querySelector('form[name="new-entry"]');if(!l||!o)return;var s=o.split("/").filter(Boolean).pop();if(!s)return;var a=document.querySelector(".filepond-root, .form-input-file"),f=a?a.closest(".form-field"):null;f&&(f.style.display="none");var p=l.querySelector(".photos-collapse");p&&(p.style.display="none");var c=document.createElement("div");c.className="photo-editor",c.innerHTML='

Photos

',f&&f.parentNode?f.parentNode.insertBefore(c,f):l.insertBefore(c,l.firstElementChild);var h=c.querySelector(".photo-editor__grid"),b=c.querySelector(".photo-editor__status"),y=c.querySelector(".photo-editor__add"),x=c.querySelector(".photo-editor__input"),C=[],S=null,F=!1,_=0;function L(K,E){b.textContent=K||"",b.className="photo-editor__status gpx-status"+(E?" error":"")}function T(K){F=K,y.disabled=K,Array.prototype.forEach.call(h.querySelectorAll(".photo-editor__del, .photo-editor__confirm-yes, .photo-editor__confirm-no"),function(E){E.disabled=K}),S&&S.option("disabled",K)}function O(K,E){return fetch(K,Object.assign({credentials:"include"},E)).then(function(z){return z.ok||z.status===204})}function N(){return fetch("/api/v1/pages"+o+"/media",{credentials:"include",headers:{Accept:"application/json"}}).then(function(K){if(!K.ok)throw new Error("HTTP "+K.status);return K.json()}).then(function(K){return(K&&K.data||[]).filter(function(E){return E&&typeof E.filename=="string"&&Eg.test(E.filename)}).map(function(E){return E.filename}).sort(Ag)})}function P(K){return O("/api/v1/entry/"+encodeURIComponent(s)+"/photos/order",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({order:K})}).then(function(E){if(!E)throw new Error("reorder failed")})}function I(K){if(C=(K||[]).slice(),S&&(S.destroy(),S=null),h.innerHTML="",!C.length){h.innerHTML='

No photos yet \u2014 add some.

';return}var E=++_;C.forEach(function(z){var R=document.createElement("div");R.className="photo-editor__cell",R.setAttribute("data-filename",z);var Z=document.createElement("img");Z.className="photo-editor__img",Z.loading="lazy",Z.alt=z,Z.src=o+"/"+encodeURIComponent(z)+"?v="+E;var ue=document.createElement("button");ue.type="button",ue.className="photo-editor__del",ue.setAttribute("aria-label","Delete "+z),ue.textContent="\u2715",ue.addEventListener("click",function(){me(R,z)}),R.appendChild(Z),R.appendChild(ue),h.appendChild(R)}),C.length>1&&(S=new Sc(h,{animation:150,draggable:".photo-editor__cell",filter:".photo-editor__confirm",onEnd:X}))}function q(){return Array.prototype.map.call(h.querySelectorAll(".photo-editor__cell"),function(K){return K.getAttribute("data-filename")})}function j(K,E){if(K.length!==E.length)return!1;for(var z=0;zDelete?',K.appendChild(z),K.classList.add("is-confirming"),z.querySelector(".photo-editor__confirm-no").addEventListener("click",function(){K.classList.remove("is-confirming"),z.remove()}),z.querySelector(".photo-editor__confirm-yes").addEventListener("click",function(){z.querySelector(".photo-editor__confirm-yes").disabled=!0,z.querySelector(".photo-editor__confirm-no").disabled=!0,U(E)})}}function U(K){var E=C.slice();T(!0),L("Deleting\u2026"),O("/api/v1/pages"+o+"/media/"+encodeURIComponent(K),{method:"DELETE"}).then(function(z){if(!z)throw new Error("delete failed");var R=C.filter(function(Z){return Z!==K});return(R.length?P(R):Promise.resolve()).then(N)}).then(function(z){L(""),I(z)}).catch(function(){L("Couldn\u2019t delete that photo. Try again.",!0),I(E)}).then(function(){T(!1)})}function le(K){return _c(K).then(function(E){return E?import("./heic-to-CN7JBE7H.js").then(function(z){var R=z.heicTo||z.default&&z.default.heicTo;return R({blob:K,type:"image/jpeg",quality:.85})}).then(function(z){return{blob:z,name:Lc(K.name,!0)}}):{blob:K,name:Lc(K.name,!1)}})}y.addEventListener("click",function(){F||x.click()}),x.addEventListener("change",function(){var K=Array.prototype.slice.call(x.files||[]);x.value="",K.length&&ie(K)});function ie(K){T(!0);var E=K.length,z=0,R=0,Z=C.slice(),ue=Promise.resolve();K.forEach(function(De){ue=ue.then(function(){return z++,L("Uploading "+z+" of "+E+"\u2026"),le(De).then(function(Ue){var A=new FormData;return A.append("file",Ue.blob,Ue.name),O("/api/v1/pages"+o+"/media",{method:"POST",body:A})}).then(function(Ue){Ue||R++},function(){R++})})}),ue.then(function(){return L("Finishing\u2026"),N()}).then(function(De){var Ue=Z.filter(function(ee){return De.indexOf(ee)!==-1}),A=De.filter(function(ee){return Z.indexOf(ee)===-1}),D=Ue.concat(A);return D.length?P(D).catch(function(){return P(D)}).catch(function(){return Promise.all(A.map(function(ee){return O("/api/v1/pages"+o+"/media/"+encodeURIComponent(ee),{method:"DELETE"}).catch(function(){})})).then(function(){var ee=new Error("reorder failed");throw ee.rolledBack=!0,ee})}).then(N):(I([]),null)}).then(function(De){De&&I(De),L(R?R+" photo"+(R>1?"s":"")+" couldn\u2019t be added.":"",!!R)}).catch(function(De){return L(De&&De.rolledBack?"Couldn\u2019t finish adding photos \u2014 changes were rolled back. Try again.":"Couldn\u2019t add photos. Please try again.",!0),N().then(I,function(){I(Z)})}).then(function(){T(!1)})}h.innerHTML='

Loading photos\u2026

',N().then(I).catch(function(){L("Couldn\u2019t load photos.",!0),I([])})}function Tg(){var o=document.querySelector('form[name="new-entry"]'),l=document.querySelector(".post-form-wrap");if(!(!o||!l)){var s=Ac("edit");if(s){Xo=!0;var a=l.querySelector("h1");a&&(a.textContent="Edit entry");var f=o.querySelector('button[type="submit"], input[type="submit"]'),p=f?f.tagName==="INPUT"?f.value:f.textContent:"Save changes";Fc(o,!0),Hl(f,"Loading entry\u2026");var c=Ac("return")||l.getAttribute("data-trip-url")||"";o.setAttribute("action","/post?edit="+encodeURIComponent(s)+(c?"&return="+encodeURIComponent(c):"")),fetch("/api/v1/pages"+s,{credentials:"include",headers:{Accept:"application/json"}}).then(function(h){if(!h.ok){var b=new Error("HTTP "+h.status);throw b.status=h.status,b}return h.json()}).then(function(h){var b=h&&h.data||{},y=b.header||{};hr("title",y.title!=null?y.title:b.title),hr("date",y.date?String(y.date).replace(" ","T"):""),kg(b.content),hr("lat",y.lat),hr("lng",y.lng),hr("location_city",y.location_city),hr("location_country",y.location_country),hr("weather_desc",y.weather_desc),hr("weather_temp_c",y.weather_temp_c),hr("transport_mode",y.transport_mode),zl("featured",y.featured),zl("force_connect",y.force_connect),zl("published",y.published!==void 0?y.published:b.published);var x=Ot("edit_path");x&&(x.value=s+"/entry.md"),Fc(o,!1),Hl(f,"Save changes");var C=o.querySelector(".more-options");C&&(C.open=!0),Fg(s)}).catch(function(h){var b=h&&h.status===404?"This entry no longer exists \u2014 it may have been deleted. Head back to the journal.":"Sorry \u2014 this entry couldn\u2019t be loaded for editing. Check your connection and try again.";Sg(l,b),Hl(f,p)})}}}function Mc(){window.postFormEditor=fg(),Cg(),Tg(),wg(),pg(),gg(),mg(),yg()}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",Mc):Mc(); +Maximum file size is #image_max_size#.`,importError:"Something went wrong when uploading the image #image_name#."};function te(o){o=o||{},o.parent=this;var l=!0;if(o.autoDownloadFontAwesome===!1&&(l=!1),o.autoDownloadFontAwesome!==!0)for(var s=document.styleSheets,a=0;a-1&&(l=!1);if(l){var f=document.createElement("link");f.rel="stylesheet",f.href="https://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css",document.getElementsByTagName("head")[0].appendChild(f)}if(o.element)this.element=o.element;else if(o.element===null){console.log("EasyMDE: Error. No element was found.");return}if(o.toolbar===void 0){o.toolbar=[];for(var p in Ur)Object.prototype.hasOwnProperty.call(Ur,p)&&(p.indexOf("separator-")!=-1&&o.toolbar.push("|"),(Ur[p].default===!0||o.showIcons&&o.showIcons.constructor===Array&&o.showIcons.indexOf(p)!=-1)&&o.toolbar.push(p))}if(Object.prototype.hasOwnProperty.call(o,"previewClass")||(o.previewClass="editor-preview"),Object.prototype.hasOwnProperty.call(o,"status")||(o.status=["autosave","lines","words","cursor"],o.uploadImage&&o.status.unshift("upload-image")),o.previewRender||(o.previewRender=function(h){return this.parent.markdown(h)}),o.parsingConfig=sr({highlightFormatting:!0},o.parsingConfig||{}),o.insertTexts=sr({},Mp,o.insertTexts||{}),o.promptTexts=sr({},_p,o.promptTexts||{}),o.blockStyles=sr({},Np,o.blockStyles||{}),o.autosave!=null&&(o.autosave.timeFormat=sr({},Bp,o.autosave.timeFormat||{})),o.iconClassMap=sr({},Me,o.iconClassMap||{}),o.shortcuts=sr({},Cp,o.shortcuts||{}),o.maxHeight=o.maxHeight||void 0,o.direction=o.direction||"ltr",typeof o.maxHeight<"u"?o.minHeight=o.maxHeight:o.minHeight=o.minHeight||"300px",o.errorCallback=o.errorCallback||function(h){alert(h)},o.uploadImage=o.uploadImage||!1,o.imageMaxSize=o.imageMaxSize||2097152,o.imageAccept=o.imageAccept||"image/png, image/jpeg, image/gif, image/avif",o.imageTexts=sr({},Op,o.imageTexts||{}),o.errorMessages=sr({},Ip,o.errorMessages||{}),o.imagePathAbsolute=o.imagePathAbsolute||!1,o.imageCSRFName=o.imageCSRFName||"csrfmiddlewaretoken",o.imageCSRFHeader=o.imageCSRFHeader||!1,o.imageInputName=o.imageInputName||"image",o.autosave!=null&&o.autosave.unique_id!=null&&o.autosave.unique_id!=""&&(o.autosave.uniqueId=o.autosave.unique_id),o.overlayMode&&o.overlayMode.combine===void 0&&(o.overlayMode.combine=!0),this.options=o,this.render(),o.initialValue&&(!this.options.autosave||this.options.autosave.foundSavedValue!==!0)&&this.value(o.initialValue),o.uploadImage){var c=this;this.codemirror.on("dragenter",function(h,b){c.updateStatusBar("upload-image",c.options.imageTexts.sbOnDragEnter),b.stopPropagation(),b.preventDefault()}),this.codemirror.on("dragend",function(h,b){c.updateStatusBar("upload-image",c.options.imageTexts.sbInit),b.stopPropagation(),b.preventDefault()}),this.codemirror.on("dragleave",function(h,b){c.updateStatusBar("upload-image",c.options.imageTexts.sbInit),b.stopPropagation(),b.preventDefault()}),this.codemirror.on("dragover",function(h,b){c.updateStatusBar("upload-image",c.options.imageTexts.sbOnDragEnter),b.stopPropagation(),b.preventDefault()}),this.codemirror.on("drop",function(h,b){b.stopPropagation(),b.preventDefault(),o.imageUploadFunction?c.uploadImagesUsingCustomFunction(o.imageUploadFunction,b.dataTransfer.files):c.uploadImages(b.dataTransfer.files)}),this.codemirror.on("paste",function(h,b){o.imageUploadFunction?c.uploadImagesUsingCustomFunction(o.imageUploadFunction,b.clipboardData.files):c.uploadImages(b.clipboardData.files)})}}te.prototype.uploadImages=function(o,l,s){if(o.length!==0){for(var a=[],f=0;f=2){var P=N[1];if(l.imagesPreviewHandler){var I=l.imagesPreviewHandler(N[1]);typeof I=="string"&&(P=I)}if(window.EMDEimagesCache[P])F(O,window.EMDEimagesCache[P]);else{window.EMDEimagesCache[P]={};var q=document.createElement("img");q.onload=function(){window.EMDEimagesCache[P]={naturalWidth:q.naturalWidth,naturalHeight:q.naturalHeight,url:P},F(O,window.EMDEimagesCache[P])},q.src=P}}}})}this.codemirror.on("update",function(){_()}),this.gui.sideBySide=this.createSideBySide(),this._rendered=this.element,(l.autofocus===!0||o.autofocus)&&this.codemirror.focus();var L=this.codemirror;setTimeout(function(){L.refresh()}.bind(L),0)};te.prototype.cleanup=function(){document.removeEventListener("keydown",this.documentOnKeyDown)};function Vf(){if(typeof localStorage=="object")try{localStorage.setItem("smde_localStorage",1),localStorage.removeItem("smde_localStorage")}catch{return!1}else return!1;return!0}te.prototype.autosave=function(){if(Vf()){var o=this;if(this.options.autosave.uniqueId==null||this.options.autosave.uniqueId==""){console.log("EasyMDE: You must set a uniqueId to use the autosave feature");return}this.options.autosave.binded!==!0&&(o.element.form!=null&&o.element.form!=null&&o.element.form.addEventListener("submit",function(){clearTimeout(o.autosaveTimeoutId),o.autosaveTimeoutId=void 0,localStorage.removeItem("smde_"+o.options.autosave.uniqueId)}),this.options.autosave.binded=!0),this.options.autosave.loaded!==!0&&(typeof localStorage.getItem("smde_"+this.options.autosave.uniqueId)=="string"&&localStorage.getItem("smde_"+this.options.autosave.uniqueId)!=""&&(this.codemirror.setValue(localStorage.getItem("smde_"+this.options.autosave.uniqueId)),this.options.autosave.foundSavedValue=!0),this.options.autosave.loaded=!0);var l=o.value();l!==""?localStorage.setItem("smde_"+this.options.autosave.uniqueId,l):localStorage.removeItem("smde_"+this.options.autosave.uniqueId);var s=document.getElementById("autosaved");if(s!=null&&s!=null&&s!=""){var a=new Date,f=new Intl.DateTimeFormat([this.options.autosave.timeFormat.locale,"en-US"],this.options.autosave.timeFormat.format).format(a),p=this.options.autosave.text==null?"Autosaved: ":this.options.autosave.text;s.innerHTML=p+f}}else console.log("EasyMDE: localStorage not available, cannot autosave")};te.prototype.clearAutosavedValue=function(){if(Vf()){if(this.options.autosave==null||this.options.autosave.uniqueId==null||this.options.autosave.uniqueId==""){console.log("EasyMDE: You must set a uniqueId to clear the autosave value");return}localStorage.removeItem("smde_"+this.options.autosave.uniqueId)}else console.log("EasyMDE: localStorage not available, cannot autosave")};te.prototype.openBrowseFileWindow=function(o,l){var s=this,a=this.gui.toolbar.getElementsByClassName("imageInput")[0];a.click();function f(p){s.options.imageUploadFunction?s.uploadImagesUsingCustomFunction(s.options.imageUploadFunction,p.target.files):s.uploadImages(p.target.files,o,l),a.removeEventListener("change",f)}a.addEventListener("change",f)};te.prototype.uploadImage=function(o,l,s){var a=this;l=l||function(y){Qf(a,y)};function f(b){a.updateStatusBar("upload-image",b),setTimeout(function(){a.updateStatusBar("upload-image",a.options.imageTexts.sbInit)},1e4),s&&typeof s=="function"&&s(b),a.options.errorCallback(b)}function p(b){var y=a.options.imageTexts.sizeUnits.split(",");return b.replace("#image_name#",o.name).replace("#image_size#",uo(o.size,y)).replace("#image_max_size#",uo(a.options.imageMaxSize,y))}if(o.size>this.options.imageMaxSize){f(p(this.options.errorMessages.fileTooLarge));return}var c=new FormData;c.append("image",o),a.options.imageCSRFToken&&!a.options.imageCSRFHeader&&c.append(a.options.imageCSRFName,a.options.imageCSRFToken);var h=new XMLHttpRequest;h.upload.onprogress=function(b){if(b.lengthComputable){var y=""+Math.round(b.loaded*100/b.total);a.updateStatusBar("upload-image",a.options.imageTexts.sbProgress.replace("#file_name#",o.name).replace("#progress#",y))}},h.open("POST",this.options.imageUploadEndpoint),a.options.imageCSRFToken&&a.options.imageCSRFHeader&&h.setRequestHeader(a.options.imageCSRFName,a.options.imageCSRFToken),h.onload=function(){try{var b=JSON.parse(this.responseText)}catch{console.error("EasyMDE: The server did not return a valid json."),f(p(a.options.errorMessages.importError));return}this.status===200&&b&&!b.error&&b.data&&b.data.filePath?l((a.options.imagePathAbsolute?"":window.location.origin+"/")+b.data.filePath):b.error&&b.error in a.options.errorMessages?f(p(a.options.errorMessages[b.error])):b.error?f(p(b.error)):(console.error("EasyMDE: Received an unexpected response after uploading the image."+this.status+" ("+this.statusText+")"),f(p(a.options.errorMessages.importError)))},h.onerror=function(b){console.error("EasyMDE: An unexpected error occurred when trying to upload the image."+b.target.status+" ("+b.target.statusText+")"),f(a.options.errorMessages.importError)},h.send(c)};te.prototype.uploadImageUsingCustomFunction=function(o,l){var s=this;function a(c){Qf(s,c)}function f(c){var h=p(c);s.updateStatusBar("upload-image",h),setTimeout(function(){s.updateStatusBar("upload-image",s.options.imageTexts.sbInit)},1e4),s.options.errorCallback(h)}function p(c){var h=s.options.imageTexts.sizeUnits.split(",");return c.replace("#image_name#",l.name).replace("#image_size#",uo(l.size,h)).replace("#image_max_size#",uo(s.options.imageMaxSize,h))}o.apply(this,[l,a,f])};te.prototype.setPreviewMaxHeight=function(){var o=this.codemirror,l=o.getWrapperElement(),s=l.nextSibling,a=parseInt(window.getComputedStyle(l).paddingTop),f=parseInt(window.getComputedStyle(l).borderTopWidth),p=parseInt(this.options.maxHeight),c=p+a*2+f*2,h=c.toString()+"px";s.style.height=h};te.prototype.createSideBySide=function(){var o=this.codemirror,l=o.getWrapperElement(),s=l.nextSibling;if(!s||!s.classList.contains("editor-preview-side")){if(s=document.createElement("div"),s.className="editor-preview-side",this.options.previewClass)if(Array.isArray(this.options.previewClass))for(var a=0;a"&&(l=l.substring(1)),o)try{if(o.matches)return o.matches(l);if(o.msMatchesSelector)return o.msMatchesSelector(l);if(o.webkitMatchesSelector)return o.webkitMatchesSelector(l)}catch{return!1}return!1}}function hc(o){return o.host&&o!==document&&o.host.nodeType&&o.host!==o?o.host:o.parentNode}function Gt(o,l,s,a){if(o){s=s||document;do{if(l!=null&&(l[0]===">"?o.parentNode===s&&Ro(o,l):Ro(o,l))||a&&o===s)return o;if(o===s)break}while(o=hc(o))}return null}var ic=/\s+/g;function Bt(o,l,s){if(o&&l)if(o.classList)o.classList[s?"add":"remove"](l);else{var a=(" "+o.className+" ").replace(ic," ").replace(" "+l+" "," ");o.className=(a+(s?" "+l:"")).replace(ic," ")}}function he(o,l,s){var a=o&&o.style;if(a){if(s===void 0)return document.defaultView&&document.defaultView.getComputedStyle?s=document.defaultView.getComputedStyle(o,""):o.currentStyle&&(s=o.currentStyle),l===void 0?s:s[l];!(l in a)&&l.indexOf("webkit")===-1&&(l="-webkit-"+l),a[l]=s+(typeof s=="string"?"":"px")}}function An(o,l){var s="";if(typeof o=="string")s=o;else do{var a=he(o,"transform");a&&a!=="none"&&(s=a+" "+s)}while(!l&&(o=o.parentNode));var f=window.DOMMatrix||window.WebKitCSSMatrix||window.CSSMatrix||window.MSCSSMatrix;return f&&new f(s)}function pc(o,l,s){if(o){var a=o.getElementsByTagName(l),f=0,p=a.length;if(s)for(;f=p:c=f<=p,!c)return a;if(a===Vt())break;a=Tr(a,!1)}return!1}function Fn(o,l,s,a){for(var f=0,p=0,c=o.children;p2&&arguments[2]!==void 0?arguments[2]:{},f=a.evt,p=zp(a,Qp);xi.pluginEvent.bind(pe)(l,s,er({dragEl:$,parentEl:qe,ghostEl:be,rootEl:Pe,nextEl:Yr,lastDownEl:Io,cloneEl:Re,cloneHidden:Fr,dragStarted:ci,putSortable:ut,activeSortable:pe.active,originalEvent:f,oldIndex:En,oldDraggableIndex:vi,newIndex:Nt,newDraggableIndex:Ar,hideGhostForTarget:wc,unhideGhostForTarget:Cc,cloneNowHidden:function(){Fr=!0},cloneNowShown:function(){Fr=!1},dispatchSortableEvent:function(h){Ct({sortable:s,name:h,originalEvent:f})}},p))};function Ct(o){Zp(er({putSortable:ut,cloneEl:Re,targetEl:$,rootEl:Pe,oldIndex:En,oldDraggableIndex:vi,newIndex:Nt,newDraggableIndex:Ar},o))}var $,qe,be,Pe,Yr,Io,Re,Fr,En,Nt,vi,Ar,_o,ut,Sn=!1,Wo=!1,qo=[],Xr,jt,Dl,wl,lc,sc,ci,kn,mi,bi=!1,Bo=!1,Po,pt,Cl=[],Tl=!1,Uo=[],Go=typeof document<"u",No=Bl,uc=yi||cr?"cssFloat":"float",Jp=Go&&!cc&&!Bl&&"draggable"in document.createElement("div"),yc=function(){if(Go){if(cr)return!1;var o=document.createElement("x");return o.style.cssText="pointer-events:auto",o.style.pointerEvents==="auto"}}(),xc=function(l,s){var a=he(l),f=parseInt(a.width)-parseInt(a.paddingLeft)-parseInt(a.paddingRight)-parseInt(a.borderLeftWidth)-parseInt(a.borderRightWidth),p=Fn(l,0,s),c=Fn(l,1,s),h=p&&he(p),b=c&&he(c),y=h&&parseInt(h.marginLeft)+parseInt(h.marginRight)+$e(p).width,x=b&&parseInt(b.marginLeft)+parseInt(b.marginRight)+$e(c).width;if(a.display==="flex")return a.flexDirection==="column"||a.flexDirection==="column-reverse"?"vertical":"horizontal";if(a.display==="grid")return a.gridTemplateColumns.split(" ").length<=1?"vertical":"horizontal";if(p&&h.float&&h.float!=="none"){var C=h.float==="left"?"left":"right";return c&&(b.clear==="both"||b.clear===C)?"vertical":"horizontal"}return p&&(h.display==="block"||h.display==="flex"||h.display==="table"||h.display==="grid"||y>=f&&a[uc]==="none"||c&&a[uc]==="none"&&y+x>f)?"vertical":"horizontal"},$p=function(l,s,a){var f=a?l.left:l.top,p=a?l.right:l.bottom,c=a?l.width:l.height,h=a?s.left:s.top,b=a?s.right:s.bottom,y=a?s.width:s.height;return f===h||p===b||f+c/2===h+y/2},Vp=function(l,s){var a;return qo.some(function(f){var p=f[Ft].options.emptyInsertThreshold;if(!(!p||Nl(f))){var c=$e(f),h=l>=c.left-p&&l<=c.right+p,b=s>=c.top-p&&s<=c.bottom+p;if(h&&b)return a=f}}),a},Dc=function(l){function s(p,c){return function(h,b,y,x){var C=h.options.group.name&&b.options.group.name&&h.options.group.name===b.options.group.name;if(p==null&&(c||C))return!0;if(p==null||p===!1)return!1;if(c&&p==="clone")return p;if(typeof p=="function")return s(p(h,b,y,x),c)(h,b,y,x);var S=(c?h:b).options.group.name;return p===!0||typeof p=="string"&&p===S||p.join&&p.indexOf(S)>-1}}var a={},f=l.group;(!f||Fl(f)!="object")&&(f={name:f}),a.name=f.name,a.checkPull=s(f.pull,!0),a.checkPut=s(f.put),a.revertClone=f.revertClone,l.group=a},wc=function(){!yc&&be&&he(be,"display","none")},Cc=function(){!yc&&be&&he(be,"display","")};Go&&!cc&&document.addEventListener("click",function(o){if(Wo)return o.preventDefault(),o.stopPropagation&&o.stopPropagation(),o.stopImmediatePropagation&&o.stopImmediatePropagation(),Wo=!1,!1},!0);var Kr=function(l){if($){l=l.touches?l.touches[0]:l;var s=Vp(l.clientX,l.clientY);if(s){var a={};for(var f in l)l.hasOwnProperty(f)&&(a[f]=l[f]);a.target=a.rootEl=s,a.preventDefault=void 0,a.stopPropagation=void 0,s[Ft]._onDragOver(a)}}},eg=function(l){$&&$.parentNode[Ft]._isOutsideThisEl(l.target)};function pe(o,l){if(!(o&&o.nodeType&&o.nodeType===1))throw"Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(o));this.el=o,this.options=l=fr({},l),o[Ft]=this;var s={group:null,sort:!0,disabled:!1,store:null,handle:null,draggable:/^[uo]l$/i.test(o.nodeName)?">li":">*",swapThreshold:1,invertSwap:!1,invertedSwapThreshold:null,removeCloneOnHide:!0,direction:function(){return xc(o,this.options)},ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",dragClass:"sortable-drag",ignore:"a, img",filter:null,preventOnFilter:!0,animation:0,easing:null,setData:function(c,h){c.setData("Text",h.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,delayOnTouchOnly:!1,touchStartThreshold:(Number.parseInt?Number:window).parseInt(window.devicePixelRatio,10)||1,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1,fallbackTolerance:0,fallbackOffset:{x:0,y:0},supportPointer:pe.supportPointer!==!1&&"PointerEvent"in window&&(!pi||Bl),emptyInsertThreshold:5};xi.initializePlugins(this,o,s);for(var a in s)!(a in l)&&(l[a]=s[a]);Dc(l);for(var f in this)f.charAt(0)==="_"&&typeof this[f]=="function"&&(this[f]=this[f].bind(this));this.nativeDraggable=l.forceFallback?!1:Jp,this.nativeDraggable&&(this.options.touchStartThreshold=1),l.supportPointer?ke(o,"pointerdown",this._onTapStart):(ke(o,"mousedown",this._onTapStart),ke(o,"touchstart",this._onTapStart)),this.nativeDraggable&&(ke(o,"dragover",this),ke(o,"dragenter",this)),qo.push(this.el),l.store&&l.store.get&&this.sort(l.store.get(this)||[]),fr(this,Xp())}pe.prototype={constructor:pe,_isOutsideThisEl:function(l){!this.el.contains(l)&&l!==this.el&&(kn=null)},_getDirection:function(l,s){return typeof this.options.direction=="function"?this.options.direction.call(this,l,s,$):this.options.direction},_onTapStart:function(l){if(l.cancelable){var s=this,a=this.el,f=this.options,p=f.preventOnFilter,c=l.type,h=l.touches&&l.touches[0]||l.pointerType&&l.pointerType==="touch"&&l,b=(h||l).target,y=l.target.shadowRoot&&(l.path&&l.path[0]||l.composedPath&&l.composedPath()[0])||b,x=f.filter;if(sg(a),!$&&!(/mousedown|pointerdown/.test(c)&&l.button!==0||f.disabled)&&!y.isContentEditable&&!(!this.nativeDraggable&&pi&&b&&b.tagName.toUpperCase()==="SELECT")&&(b=Gt(b,f.draggable,a,!1),!(b&&b.animated)&&Io!==b)){if(En=Pt(b),vi=Pt(b,f.draggable),typeof x=="function"){if(x.call(this,l,b,this)){Ct({sortable:s,rootEl:y,name:"filter",targetEl:b,toEl:a,fromEl:a}),At("filter",s,{evt:l}),p&&l.preventDefault();return}}else if(x&&(x=x.split(",").some(function(C){if(C=Gt(y,C.trim(),a,!1),C)return Ct({sortable:s,rootEl:C,name:"filter",targetEl:b,fromEl:a,toEl:a}),At("filter",s,{evt:l}),!0}),x)){p&&l.preventDefault();return}f.handle&&!Gt(y,f.handle,a,!1)||this._prepareDragStart(l,h,b)}}},_prepareDragStart:function(l,s,a){var f=this,p=f.el,c=f.options,h=p.ownerDocument,b;if(a&&!$&&a.parentNode===p){var y=$e(a);if(Pe=p,$=a,qe=$.parentNode,Yr=$.nextSibling,Io=a,_o=c.group,pe.dragged=$,Xr={target:$,clientX:(s||l).clientX,clientY:(s||l).clientY},lc=Xr.clientX-y.left,sc=Xr.clientY-y.top,this._lastX=(s||l).clientX,this._lastY=(s||l).clientY,$.style["will-change"]="all",b=function(){if(At("delayEnded",f,{evt:l}),pe.eventCanceled){f._onDrop();return}f._disableDelayedDragEvents(),!nc&&f.nativeDraggable&&($.draggable=!0),f._triggerDragStart(l,s),Ct({sortable:f,name:"choose",originalEvent:l}),Bt($,c.chosenClass,!0)},c.ignore.split(",").forEach(function(x){pc($,x.trim(),kl)}),ke(h,"dragover",Kr),ke(h,"mousemove",Kr),ke(h,"touchmove",Kr),c.supportPointer?(ke(h,"pointerup",f._onDrop),!this.nativeDraggable&&ke(h,"pointercancel",f._onDrop)):(ke(h,"mouseup",f._onDrop),ke(h,"touchend",f._onDrop),ke(h,"touchcancel",f._onDrop)),nc&&this.nativeDraggable&&(this.options.touchStartThreshold=4,$.draggable=!0),At("delayStart",this,{evt:l}),c.delay&&(!c.delayOnTouchOnly||s)&&(!this.nativeDraggable||!(yi||cr))){if(pe.eventCanceled){this._onDrop();return}c.supportPointer?(ke(h,"pointerup",f._disableDelayedDrag),ke(h,"pointercancel",f._disableDelayedDrag)):(ke(h,"mouseup",f._disableDelayedDrag),ke(h,"touchend",f._disableDelayedDrag),ke(h,"touchcancel",f._disableDelayedDrag)),ke(h,"mousemove",f._delayedDragTouchMoveHandler),ke(h,"touchmove",f._delayedDragTouchMoveHandler),c.supportPointer&&ke(h,"pointermove",f._delayedDragTouchMoveHandler),f._dragStartTimer=setTimeout(b,c.delay)}else b()}},_delayedDragTouchMoveHandler:function(l){var s=l.touches?l.touches[0]:l;Math.max(Math.abs(s.clientX-this._lastX),Math.abs(s.clientY-this._lastY))>=Math.floor(this.options.touchStartThreshold/(this.nativeDraggable&&window.devicePixelRatio||1))&&this._disableDelayedDrag()},_disableDelayedDrag:function(){$&&kl($),clearTimeout(this._dragStartTimer),this._disableDelayedDragEvents()},_disableDelayedDragEvents:function(){var l=this.el.ownerDocument;Ce(l,"mouseup",this._disableDelayedDrag),Ce(l,"touchend",this._disableDelayedDrag),Ce(l,"touchcancel",this._disableDelayedDrag),Ce(l,"pointerup",this._disableDelayedDrag),Ce(l,"pointercancel",this._disableDelayedDrag),Ce(l,"mousemove",this._delayedDragTouchMoveHandler),Ce(l,"touchmove",this._delayedDragTouchMoveHandler),Ce(l,"pointermove",this._delayedDragTouchMoveHandler)},_triggerDragStart:function(l,s){s=s||l.pointerType=="touch"&&l,!this.nativeDraggable||s?this.options.supportPointer?ke(document,"pointermove",this._onTouchMove):s?ke(document,"touchmove",this._onTouchMove):ke(document,"mousemove",this._onTouchMove):(ke($,"dragend",this),ke(Pe,"dragstart",this._onDragStart));try{document.selection?zo(function(){document.selection.empty()}):window.getSelection().removeAllRanges()}catch{}},_dragStarted:function(l,s){if(Sn=!1,Pe&&$){At("dragStarted",this,{evt:s}),this.nativeDraggable&&ke(document,"dragover",eg);var a=this.options;!l&&Bt($,a.dragClass,!1),Bt($,a.ghostClass,!0),pe.active=this,l&&this._appendGhost(),Ct({sortable:this,name:"start",originalEvent:s})}else this._nulling()},_emulateDragOver:function(){if(jt){this._lastX=jt.clientX,this._lastY=jt.clientY,wc();for(var l=document.elementFromPoint(jt.clientX,jt.clientY),s=l;l&&l.shadowRoot&&(l=l.shadowRoot.elementFromPoint(jt.clientX,jt.clientY),l!==s);)s=l;if($.parentNode[Ft]._isOutsideThisEl(l),s)do{if(s[Ft]){var a=void 0;if(a=s[Ft]._onDragOver({clientX:jt.clientX,clientY:jt.clientY,target:l,rootEl:s}),a&&!this.options.dragoverBubble)break}l=s}while(s=hc(s));Cc()}},_onTouchMove:function(l){if(Xr){var s=this.options,a=s.fallbackTolerance,f=s.fallbackOffset,p=l.touches?l.touches[0]:l,c=be&&An(be,!0),h=be&&c&&c.a,b=be&&c&&c.d,y=No&&pt&&ac(pt),x=(p.clientX-Xr.clientX+f.x)/(h||1)+(y?y[0]-Cl[0]:0)/(h||1),C=(p.clientY-Xr.clientY+f.y)/(b||1)+(y?y[1]-Cl[1]:0)/(b||1);if(!pe.active&&!Sn){if(a&&Math.max(Math.abs(p.clientX-this._lastX),Math.abs(p.clientY-this._lastY))=0&&(Ct({rootEl:qe,name:"add",toEl:qe,fromEl:Pe,originalEvent:l}),Ct({sortable:this,name:"remove",toEl:qe,originalEvent:l}),Ct({rootEl:qe,name:"sort",toEl:qe,fromEl:Pe,originalEvent:l}),Ct({sortable:this,name:"sort",toEl:qe,originalEvent:l})),ut&&ut.save()):Nt!==En&&Nt>=0&&(Ct({sortable:this,name:"update",toEl:qe,originalEvent:l}),Ct({sortable:this,name:"sort",toEl:qe,originalEvent:l})),pe.active&&((Nt==null||Nt===-1)&&(Nt=En,Ar=vi),Ct({sortable:this,name:"end",toEl:qe,originalEvent:l}),this.save()))),this._nulling()},_nulling:function(){At("nulling",this),Pe=$=qe=be=Yr=Re=Io=Fr=Xr=jt=ci=Nt=Ar=En=vi=kn=mi=ut=_o=pe.dragged=pe.ghost=pe.clone=pe.active=null;var l=this.el;Uo.forEach(function(s){l.contains(s)&&(s.checked=!0)}),Uo.length=Dl=wl=0},handleEvent:function(l){switch(l.type){case"drop":case"dragend":this._onDrop(l);break;case"dragenter":case"dragover":$&&(this._onDragOver(l),tg(l));break;case"selectstart":l.preventDefault();break}},toArray:function(){for(var l=[],s,a=this.el.children,f=0,p=a.length,c=this.options;ff.right+p||o.clientY>a.bottom&&o.clientX>a.left:o.clientY>f.bottom+p||o.clientX>a.right&&o.clientY>a.top}function og(o,l,s,a,f,p,c,h){var b=a?o.clientY:o.clientX,y=a?s.height:s.width,x=a?s.top:s.left,C=a?s.bottom:s.right,S=!1;if(!c){if(h&&Pox+y*p/2:bC-Po)return-mi}else if(b>x+y*(1-f)/2&&bC-y*p/2)?b>x+y/2?1:-1:0}function ag(o){return Pt($)0||C>0&&S0?"Converting "+l+" photo"+(l>1?"s":"")+"\u2026":"Uploading "+C+" photo"+(C>1?"s":"")+"\u2026",s.details.open=!0):C>0?(s.summary.textContent="\u2713 "+C+" photo"+(C>1?"s":"")+" ready \u2014 tap to review",s.details.open=!1):(s.summary.textContent="Photos (1\u20136)",s.details.open=!0)}}function c(){p(),setTimeout(p,150),setTimeout(p,500)}function h(){var x=o.querySelector('button[type="submit"], input[type="submit"]');if(x&&(x.disabled=l>0),l>0)f("Converting "+l+" photo"+(l>1?"s":"")+"\u2026");else{var C=Ec();C&&/Converting/.test(C.textContent)&&f("")}p()}o.addEventListener("submit",function(x){l>0&&(x.preventDefault(),f("Hang on \u2014 a photo is still converting.","err"))},!0);function b(x){return function(C){var S=C&&C.file;return S?_c(S).then(function(F){return F?(l++,h(),import("./heic-to-CN7JBE7H.js").then(function(_){var L=_.heicTo||_.default&&_.default.heicTo;return L({blob:S,type:"image/jpeg",quality:.85})}).then(function(_){var L=new File([_],dg(S.name),{type:"image/jpeg"});x.addFile(L)}).catch(function(){f("A photo couldn\u2019t be converted and was skipped \u2014 the others are fine.","err")}).then(function(){l--,h()}),!1):!0}):!0}}var y=0;(function x(){var C=window.GravFilePond&&window.GravFilePond.getInstances?window.GravFilePond.getInstances():[];if(!C.length){y++<120&&setTimeout(x,50);return}C.forEach(function(S){S&&!S._heicHooked&&(S._heicHooked=!0,S.setOptions({beforeAddFile:b(S),allowReorder:!0,itemInsertLocation:"after"}),a=S,["addfile","processfile","processfiles","removefile","error"].forEach(function(F){try{S.on(F,c)}catch{}}),p())})})()}function Ot(o){return document.querySelector('[name="data['+o+']"]')}function gg(){var o=Array.prototype.slice.call(document.querySelectorAll(".advanced-field"));if(o.length){var l=[];if(o.forEach(function(p){var c=p.closest(".form-field");c&&l.indexOf(c)===-1&&l.push(c)}),!!l.length){var s=document.createElement("details");s.className="more-options";var a=document.createElement("summary");a.className="more-options__summary",a.textContent="More options",s.appendChild(a),l[0].parentNode.insertBefore(s,l[0]),l.forEach(function(p){s.appendChild(p)});var f=l.some(function(p){var c=p.querySelector('input[type="text"]');if(c&&c.value.trim())return!0;var h=p.querySelector('input[type="radio"]:checked');return!!(h&&h.value&&h.value!=="0")});f&&(s.open=!0)}}}var vg={0:"Sunny",1:"Partly cloudy",2:"Partly cloudy",3:"Cloudy",45:"Foggy",48:"Foggy",51:"Drizzle",53:"Drizzle",55:"Drizzle",56:"Drizzle",57:"Drizzle",61:"Rain",63:"Rain",65:"Rain",66:"Rain",67:"Rain",80:"Rain",81:"Rain",82:"Rain",71:"Snow",73:"Snow",75:"Snow",77:"Snow",85:"Snow",86:"Snow",95:"Thunderstorm",96:"Thunderstorm",99:"Thunderstorm"};function dr(o,l,s){o&&(o.className="form-status"+(s?" form-status--"+s:""),o.textContent=l||"")}function mg(){var o=document.getElementById("get-location"),l=document.getElementById("get-weather");if(!o&&!l)return;var s=document.getElementById("location-status"),a=document.getElementById("weather-status");function f(){var h=Ot("lat"),b=Ot("lng"),y=h?h.value.trim():"",x=b?b.value.trim():"";return y&&x?{lat:y,lng:x}:null}function p(){if(l){var h=!!f();l.disabled=!h,l.title=h?"":"Get location first"}}p();function c(h,b){var y=Ot("location_city"),x=Ot("location_country");if(!((!y||y.value.trim())&&(!x||x.value.trim()))){var C="https://api.bigdatacloud.net/data/reverse-geocode-client?latitude="+encodeURIComponent(h)+"&longitude="+encodeURIComponent(b)+"&localityLanguage=en";fetch(C).then(function(S){return S.json()}).then(function(S){var F=(S.city||S.locality||"").trim(),_=(S.countryName||"").trim();y&&!y.value.trim()&&F&&(y.value=F),x&&!x.value.trim()&&_&&(x.value=_);var L=[F,_].filter(Boolean).join(", ");L&&dr(s,"\u2713 Location captured \xB7 "+L,"ok")}).catch(function(){})}}o&&o.addEventListener("click",function(){if(!navigator.geolocation){dr(s,"Geolocation is not supported on this device.","err");return}o.classList.add("is-loading"),o.disabled=!0,dr(s,"Getting location\u2026"),navigator.geolocation.getCurrentPosition(function(h){var b=h.coords.latitude.toFixed(6),y=h.coords.longitude.toFixed(6),x=Ot("lat"),C=Ot("lng");x&&(x.value=b),C&&(C.value=y),o.classList.remove("is-loading"),o.disabled=!1,dr(s,"\u2713 Location captured \xB7 "+b+", "+y,"ok"),p(),c(b,y)},function(h){o.classList.remove("is-loading"),o.disabled=!1,dr(s,"\u2717 "+(h&&h.message?h.message:"Could not get location")+" \u2014 enter coordinates manually if needed.","err")},{enableHighAccuracy:!0,timeout:15e3})}),l&&l.addEventListener("click",function(){var h=f();if(!h){dr(a,"Get location first, then fetch weather.","err");return}l.classList.add("is-loading"),l.disabled=!0,dr(a,"Fetching weather\u2026");var b="https://api.open-meteo.com/v1/forecast?latitude="+h.lat+"&longitude="+h.lng+"¤t=temperature_2m,weather_code&temperature_unit=celsius";fetch(b).then(function(y){return y.json()}).then(function(y){var x=Math.round(y.current.temperature_2m),C=vg[y.current.weather_code]||"Cloudy",S=Ot("weather_temp_c"),F=Ot("weather_desc");S&&(S.value=x),F&&(F.value=C),l.classList.remove("is-loading"),p(),dr(a,"\u2713 Weather set \xB7 "+C+" \xB7 "+x+"\xB0C (edit above if needed)","ok")}).catch(function(){l.classList.remove("is-loading"),p(),dr(a,"\u2717 Could not fetch weather \u2014 set it manually above.","err")})})}function bg(){var o=new Date;return o.setSeconds(0,0),o.setMinutes(o.getMinutes()-o.getTimezoneOffset()),o.toISOString().slice(0,16)}function yg(){var o={title:"Title",date:"Date & time",content:"Content"},l=document.querySelector('form[name="new-entry"]');if(!l)return;var s=Ot("date");s&&!String(s.value).trim()&&(s.value=bg());function a(){l.querySelectorAll(".field-error").forEach(function(c){c.remove()}),l.querySelectorAll(".field-invalid").forEach(function(c){c.classList.remove("field-invalid")})}function f(c,h){c.classList.add("field-invalid");var b=document.createElement("span");b.className="field-error",b.textContent=h,c.parentNode.insertBefore(b,c.nextSibling)}function p(c){var h=l.querySelector(".photos-collapse"),b,y;if(h?(h.open=!0,y=h.querySelector(".photos-collapse__summary"),b=h):(b=document.querySelector(".filepond-root, .form-input-file"),y=b),!y)return b||null;var x=document.createElement("span");return x.className="field-error",x.textContent=c,y.insertAdjacentElement("afterend",x),b||y}l.addEventListener("submit",function(c){a();var h=null;!Xo&&document.querySelectorAll(".filepond--item").length<1&&(h=p("Add at least one photo.")),Object.keys(o).forEach(function(b){var y=Ot(b);y&&!String(y.value).trim()&&(f(y,o[b]+" is required."),h||(h=y))}),h&&(c.preventDefault(),typeof h.focus=="function"&&h.focus(),h.scrollIntoView({behavior:"smooth",block:"center"}))})}var Pl="intotheeast:new-entry-draft";function xg(o){return Array.prototype.slice.call(o.querySelectorAll('[name^="data["]')).filter(function(l){if(l.type==="file")return!1;var s=l.name;return s.indexOf("data[_json")!==0&&s.indexOf("data[photos")!==0})}function Dg(){var o=document.querySelector(".filepond-root, .form-input-file");if(!(!o||!o.parentNode)&&!o.parentNode.querySelector(".photo-reauth-hint")){var l=document.createElement("p");l.className="photo-reauth-hint is-shown",l.textContent="Your text was restored \u2014 photos need re-selecting (they can\u2019t be saved in a draft).",o.parentNode.insertBefore(l,o.nextSibling)}}function wg(){var o=document.querySelector('form[name="new-entry"]');if(!o||Xo)return;if(document.querySelector(".notices.success")){try{localStorage.removeItem(Pl)}catch{}return}function l(){var p={};xg(o).forEach(function(c){c.type==="radio"?c.checked&&(p[c.name]=c.value):p[c.name]=c.value});try{localStorage.setItem(Pl,JSON.stringify(p))}catch{}}var s=null;try{s=localStorage.getItem(Pl)}catch{s=null}if(s){var a=null;try{a=JSON.parse(s)}catch{a=null}if(a){var f=!1;Object.keys(a).forEach(function(p){var c=a[p];if(c!=null&&String(c).trim()&&(f=!0),p!=="data[content]"){var h=o.querySelectorAll('input[type="radio"][name="'+p+'"]');if(h.length){h.forEach(function(y){y.checked=y.value===c});return}var b=o.querySelector('[name="'+p+'"]');b&&b.type!=="file"&&(b.value=c)}}),window.postFormEditor&&a["data[content]"]!=null&&window.postFormEditor.value(a["data[content]"]),f&&Dg()}}o.addEventListener("input",l),o.addEventListener("change",l),window.postFormEditor&&window.postFormEditor.codemirror.on("change",l)}function Cg(){var o=document.querySelector(".post-form-wrap"),l=document.querySelector(".post-form-wrap .notices.success, .post-form-wrap .notices.green");if(!(!o||!l)){var s=document.createElement("div");s.className="post-success";var a=document.createElement("p");a.className="post-success__title",a.textContent="\u2713 Saved to your journal.",s.appendChild(a);var f=document.createElement("div");f.className="post-success__actions";var p=o.getAttribute("data-trip-url");if(p){var c=document.createElement("a");c.className="post-success__view",c.href=p,c.textContent="View your journal \u2192",f.appendChild(c)}var h=document.createElement("a");h.className="post-success__again",h.href=window.location.pathname,h.textContent="Post another",f.appendChild(h),s.appendChild(f),l.parentNode.insertBefore(s,l.nextSibling),["form",".form-action-row","#location-status","#weather-status"].forEach(function(b){var y=o.querySelector(b);y&&(y.style.display="none")}),l.scrollIntoView({behavior:"smooth",block:"start"})}}var Xo=!1;function Ac(o){return new URLSearchParams(window.location.search).get(o)}function hr(o,l){var s=Ot(o);s&&(s.value=l==null?"":String(l))}function zl(o,l){var s=l?"1":"0",a=document.querySelectorAll('[name="data['+o+']"]');Array.prototype.forEach.call(a,function(f){f.checked=String(f.value)===s})}function kg(o){var l=o==null?"":String(o);if(window.postFormEditor&&typeof window.postFormEditor.value=="function")window.postFormEditor.value(l);else{var s=Ot("content");s&&(s.value=l)}}function Fc(o,l){var s=o.querySelectorAll("input, textarea, select, button");Array.prototype.forEach.call(s,function(a){a.type==="file"||a.name&&a.name.indexOf("data[photos")===0||(a.disabled=l)}),window.postFormEditor&&window.postFormEditor.codemirror&&window.postFormEditor.codemirror.setOption("readOnly",l?"nocursor":!1)}function Hl(o,l){o&&(o.tagName==="INPUT"?o.value=l:o.textContent=l)}function Sg(o,l){var s=o.querySelector(".post-edit-error");if(s){s.textContent=l;return}var a=document.createElement("div");a.className="post-edit-error",a.setAttribute("role","alert"),a.textContent=l;var f=o.querySelector("h1");f?f.insertAdjacentElement("afterend",a):o.insertBefore(a,o.firstChild)}var Eg=/\.(jpe?g|png|webp|heic|heif|gif)$/i;function Tc(o){var l=/(?:^|\/)photo-0*(\d+)\./i.exec(o);return l?parseInt(l[1],10):Number.MAX_SAFE_INTEGER}function Ag(o,l){var s=Tc(o),a=Tc(l);return s!==a?s-a:ol?1:0}function Lc(o,l){var s=String(o||"photo"),a=s.lastIndexOf("."),f=(a>0?s.slice(0,a):s).toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"photo",p=l?".jpg":a>0?s.slice(a).toLowerCase():".jpg",c=Date.now().toString(36)+Math.random().toString(36).slice(2,6);return f+"-"+c+p}function Fg(o){var l=document.querySelector('form[name="new-entry"]');if(!l||!o)return;var s=o.split("/").filter(Boolean).pop();if(!s)return;var a=document.querySelector(".filepond-root, .form-input-file"),f=a?a.closest(".form-field"):null;f&&(f.style.display="none");var p=l.querySelector(".photos-collapse");p&&(p.style.display="none");var c=document.createElement("div");c.className="photo-editor",c.innerHTML='
Photos

',f&&f.parentNode?f.parentNode.insertBefore(c,f):l.insertBefore(c,l.firstElementChild);var h=c.querySelector(".photo-editor__grid"),b=c.querySelector(".photo-editor__status"),y=c.querySelector(".photo-editor__add"),x=c.querySelector(".photo-editor__input"),C=[],S=null,F=!1,_=0;function L(K,E){b.textContent=K||"",b.className="photo-editor__status gpx-status"+(E?" error":"")}function T(K){F=K,y.disabled=K,Array.prototype.forEach.call(h.querySelectorAll(".photo-editor__del, .photo-editor__confirm-yes, .photo-editor__confirm-no"),function(E){E.disabled=K}),S&&S.option("disabled",K)}function O(K,E){return fetch(K,Object.assign({credentials:"include"},E)).then(function(z){return z.ok||z.status===204})}function N(){return fetch("/api/v1/pages"+o+"/media",{credentials:"include",headers:{Accept:"application/json"}}).then(function(K){if(!K.ok)throw new Error("HTTP "+K.status);return K.json()}).then(function(K){return(K&&K.data||[]).filter(function(E){return E&&typeof E.filename=="string"&&Eg.test(E.filename)}).map(function(E){return E.filename}).sort(Ag)})}function P(K){return O("/api/v1/entry/"+encodeURIComponent(s)+"/photos/order",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({order:K})}).then(function(E){if(!E)throw new Error("reorder failed")})}function I(K){if(C=(K||[]).slice(),S&&(S.destroy(),S=null),h.innerHTML="",!C.length){h.innerHTML='

No photos yet \u2014 add some.

';return}var E=++_;C.forEach(function(z){var R=document.createElement("div");R.className="photo-editor__cell",R.setAttribute("data-filename",z);var Z=document.createElement("img");Z.className="photo-editor__img",Z.loading="lazy",Z.alt=z,Z.src=o+"/"+encodeURIComponent(z)+"?v="+E;var ue=document.createElement("button");ue.type="button",ue.className="photo-editor__del",ue.setAttribute("aria-label","Delete "+z),ue.textContent="\u2715",ue.addEventListener("click",function(){me(R,z)}),R.appendChild(Z),R.appendChild(ue),h.appendChild(R)}),C.length>1&&(S=new Sc(h,{animation:150,draggable:".photo-editor__cell",filter:".photo-editor__confirm",onEnd:X}))}function q(){return Array.prototype.map.call(h.querySelectorAll(".photo-editor__cell"),function(K){return K.getAttribute("data-filename")})}function j(K,E){if(K.length!==E.length)return!1;for(var z=0;zDelete?',K.appendChild(z),K.classList.add("is-confirming"),z.querySelector(".photo-editor__confirm-no").addEventListener("click",function(){K.classList.remove("is-confirming"),z.remove()}),z.querySelector(".photo-editor__confirm-yes").addEventListener("click",function(){z.querySelector(".photo-editor__confirm-yes").disabled=!0,z.querySelector(".photo-editor__confirm-no").disabled=!0,U(E)})}}function U(K){var E=C.slice(),z=C.filter(function(R){return R!==K});T(!0),L("Deleting\u2026"),fetch("/api/v1/pages"+o+"/media/"+encodeURIComponent(K),{credentials:"include",method:"DELETE"}).then(function(R){if(!(R.ok||R.status===204||R.status===404))throw new Error("delete failed");return(z.length?P(z):Promise.resolve()).then(N).then(function(Z){L(""),I(Z)},function(){L("Photo deleted, but refreshing the list failed \u2014 reload if it looks off.",!0),I(z)})},function(){L("Couldn\u2019t delete that photo. Try again.",!0),I(E)}).then(function(){T(!1)})}function le(K){return _c(K).then(function(E){return E?import("./heic-to-CN7JBE7H.js").then(function(z){var R=z.heicTo||z.default&&z.default.heicTo;return R({blob:K,type:"image/jpeg",quality:.85})}).then(function(z){return{blob:z,name:Lc(K.name,!0)}}):{blob:K,name:Lc(K.name,!1)}})}y.addEventListener("click",function(){F||x.click()}),x.addEventListener("change",function(){var K=Array.prototype.slice.call(x.files||[]);x.value="",K.length&&ie(K)});function ie(K){T(!0);var E=K.length,z=0,R=0,Z=C.slice(),ue=Promise.resolve();K.forEach(function(De){ue=ue.then(function(){return z++,L("Uploading "+z+" of "+E+"\u2026"),le(De).then(function(Ue){var A=new FormData;return A.append("file",Ue.blob,Ue.name),O("/api/v1/pages"+o+"/media",{method:"POST",body:A})}).then(function(Ue){Ue||R++},function(){R++})})}),ue.then(function(){return L("Finishing\u2026"),N()}).then(function(De){var Ue=Z.filter(function(ee){return De.indexOf(ee)!==-1}),A=De.filter(function(ee){return Z.indexOf(ee)===-1}),D=Ue.concat(A);return D.length?P(D).catch(function(){return P(D)}).catch(function(){return Promise.all(A.map(function(ee){return O("/api/v1/pages"+o+"/media/"+encodeURIComponent(ee),{method:"DELETE"}).catch(function(){})})).then(function(){var ee=new Error("reorder failed");throw ee.rolledBack=!0,ee})}).then(N):(I([]),null)}).then(function(De){De&&I(De),L(R?R+" photo"+(R>1?"s":"")+" couldn\u2019t be added.":"",!!R)}).catch(function(De){return L(De&&De.rolledBack?"Couldn\u2019t finish adding photos \u2014 changes were rolled back. Try again.":"Couldn\u2019t add photos. Please try again.",!0),N().then(I,function(){I(Z)})}).then(function(){T(!1)})}h.innerHTML='

Loading photos\u2026

',N().then(I).catch(function(){L("Couldn\u2019t load photos.",!0),I([])})}function Tg(){var o=document.querySelector('form[name="new-entry"]'),l=document.querySelector(".post-form-wrap");if(!(!o||!l)){var s=Ac("edit");if(s){Xo=!0;var a=l.querySelector("h1");a&&(a.textContent="Edit entry");var f=o.querySelector('button[type="submit"], input[type="submit"]'),p=f?f.tagName==="INPUT"?f.value:f.textContent:"Save changes";Fc(o,!0),Hl(f,"Loading entry\u2026");var c=Ac("return")||l.getAttribute("data-trip-url")||"";o.setAttribute("action","/post?edit="+encodeURIComponent(s)+(c?"&return="+encodeURIComponent(c):"")),fetch("/api/v1/pages"+s,{credentials:"include",headers:{Accept:"application/json"}}).then(function(h){if(!h.ok){var b=new Error("HTTP "+h.status);throw b.status=h.status,b}return h.json()}).then(function(h){var b=h&&h.data||{},y=b.header||{};hr("title",y.title!=null?y.title:b.title),hr("date",y.date?String(y.date).replace(" ","T"):""),kg(b.content),hr("lat",y.lat),hr("lng",y.lng),hr("location_city",y.location_city),hr("location_country",y.location_country),hr("weather_desc",y.weather_desc),hr("weather_temp_c",y.weather_temp_c),hr("transport_mode",y.transport_mode),zl("featured",y.featured),zl("force_connect",y.force_connect),zl("published",y.published!==void 0?y.published:b.published);var x=Ot("edit_path");x&&(x.value=s+"/entry.md"),Fc(o,!1),Hl(f,"Save changes");var C=o.querySelector(".more-options");C&&(C.open=!0),Fg(s)}).catch(function(h){var b=h&&h.status===404?"This entry no longer exists \u2014 it may have been deleted. Head back to the journal.":"Sorry \u2014 this entry couldn\u2019t be loaded for editing. Check your connection and try again.";Sg(l,b),Hl(f,p)})}}}function Mc(){window.postFormEditor=fg(),Cg(),Tg(),wg(),pg(),gg(),mg(),yg()}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",Mc):Mc(); /*! Bundled license information: sortablejs/modular/sortable.esm.js: diff --git a/themes/intotheeast/js/src/post-form.js b/themes/intotheeast/js/src/post-form.js index 459d41a..c5e3fd0 100644 --- a/themes/intotheeast/js/src/post-form.js +++ b/themes/intotheeast/js/src/post-form.js @@ -155,7 +155,7 @@ function initPhotoConversion() { // current visual order into a hidden input. Its name is a TOP-LEVEL POST key // ("photo_order", not "data[...]") so Grav's form never captures it into the // page data — the server reads it straight from $_POST and renames the - // copied files photo-1..N to match, with nothing leaking into frontmatter. + // copied files photo-01..NN to match, with nothing leaking into frontmatter. form.addEventListener('submit', function () { if (!orderPond) return; var files = orderPond.getFiles(); @@ -277,7 +277,7 @@ function initPhotoConversion() { if (pond && !pond._heicHooked) { pond._heicHooked = true; // allowReorder: drag thumbnails to set the order. The server - // (cache-on-save) renames the copied files photo-1..N in the + // (cache-on-save) renames the copied files photo-01..NN in the // submitted order so the published entry honours it (entry media // is filename-ordered; hero = first). pond.setOptions({ beforeAddFile: makeBeforeAddFile(pond), allowReorder: true, itemInsertLocation: 'after' }); @@ -745,10 +745,10 @@ function editSetContent(value) { // // The photos/FilePond control is deliberately EXCLUDED: FilePond reads the // disabled state of its underlying input when the form plugin creates it and -// never re-enables (removing its browse button, so the owner can't add photos on -// edit — U7). Photos are also safe to leave live during the D1 prefill window: -// they load additively (editLoadPhotos), not by overwrite, so early interaction -// can't be clobbered the way an empty text field could. +// never re-enables. In edit mode FilePond is decommissioned anyway — the live +// photo editor (initPhotoEditor) hides it and manages add/delete/reorder against +// the media API independently of this form's Save — so its disabled state during +// the D1 prefill window is irrelevant. function editFormDisabled(form, disabled) { var els = form.querySelectorAll('input, textarea, select, button'); Array.prototype.forEach.call(els, function (el) { @@ -951,14 +951,18 @@ function initPhotoEditor(route) { var lastGood = photos.slice(); setBusy(true); setStatus('Saving order…'); - reorder(next) - .then(function () { return mediaList(); }) - .then(function (list) { setStatus(''); render(list); }) - .catch(function () { - setStatus('Couldn’t save the new order — reverted. Try again.', true); - render(lastGood); // revert the SortableJS move to last-known-good - }) - .then(function () { setBusy(false); }); + // Split the two failure stages: a failed SAVE reverts the drag; a failed + // REFRESH after a successful save must NOT revert (the order did persist) + // — show the saved order and reconcile on the next op. + reorder(next).then(function () { + return mediaList().then( + function (list) { setStatus(''); render(list); }, + function () { setStatus(''); render(next); } // saved; DOM already shows it + ); + }, function () { + setStatus('Couldn’t save the new order — reverted. Try again.', true); + render(lastGood); // revert the SortableJS move to last-known-good + }).then(function () { setBusy(false); }); } // ✕ swaps the cell to an inline "Delete? [Confirm] [Cancel]" (option a). @@ -985,17 +989,26 @@ function initPhotoEditor(route) { function doDelete(name) { var lastGood = photos.slice(); + var remaining = photos.filter(function (p) { return p !== name; }); setBusy(true); setStatus('Deleting…'); - apiOk('/api/v1/pages' + route + '/media/' + encodeURIComponent(name), { method: 'DELETE' }) - .then(function (ok) { - if (!ok) throw new Error('delete failed'); - // Renumber the survivors so cover=first stays correct (idempotent). - var remaining = photos.filter(function (p) { return p !== name; }); - return (remaining.length ? reorder(remaining) : Promise.resolve()).then(mediaList); - }) - .then(function (list) { setStatus(''); render(list); }) - .catch(function () { + // A 404 means the file is already gone — treat it as success so retrying + // a ghost cell converges instead of looping on "couldn't delete". + fetch('/api/v1/pages' + route + '/media/' + encodeURIComponent(name), { credentials: 'include', method: 'DELETE' }) + .then(function (r) { + if (!(r.ok || r.status === 204 || r.status === 404)) throw new Error('delete failed'); + // Deleted. Renumber survivors (cover=first), then refresh. A failure + // AFTER this point must NOT resurrect the deleted photo — show the + // survivor set, never lastGood. + return (remaining.length ? reorder(remaining) : Promise.resolve()).then(mediaList).then( + function (list) { setStatus(''); render(list); }, + function () { + setStatus('Photo deleted, but refreshing the list failed — reload if it looks off.', true); + render(remaining); + } + ); + }, function () { + // The DELETE request itself failed — nothing changed on disk. setStatus('Couldn’t delete that photo. Try again.', true); render(lastGood); })