From a7c484205b2229b73003f8492db23f5ff3fe6497 Mon Sep 17 00:00:00 2001 From: Piyush Date: Wed, 3 Jun 2026 07:29:37 +0000 Subject: [PATCH] suppression of bulk operations in mobile view is now possible --- css/CollectionsList-q-liS-Eo.chunk.css | 1 - css/FaceContent-Bdbzv9Pd.chunk.css | 1 - css/FaceCover-CriYllrK.chunk.css | 1 - css/FaceMergeForm-DL6EU9Jq.chunk.css | 1 - css/FacesView-Gits2579.chunk.css | 1 - css/FoldersView-BC1tXPDF.chunk.css | 1 - css/NcEmptyContent-BC9mI1uc.chunk.css | 1 - css/NcProgressBar-D7zYeXBH-B3qS3u7h.chunk.css | 1 - css/PhotosFiltersInput-B5iZrGH_.chunk.css | 1 - css/PhotosTab-DGphhlff.chunk.css | 1 - css/PlaceContent-Dr0VitMb.chunk.css | 1 - css/TagContent-Bvp0UERJ.chunk.css | 1 - css/TagsView-BI4e7UBA.chunk.css | 1 - css/UnassignedFaces-uVbioLgS.chunk.css | 1 - css/dashboard-Dk7DoScS.chunk.css | 1 - css/photos-dashboard.css | 10 +- css/photos-main.css | 22 +- css/photos-public.css | 6 +- css/public-BqRc5ISL.chunk.css | 1 - js/photos-dashboard.mjs | 79 +- js/photos-dashboard.mjs.license | 7 - js/photos-dashboard.mjs.map | 2 +- js/photos-main.mjs | 584 ++- js/photos-main.mjs.license | 11 - js/photos-main.mjs.map | 2 +- js/photos-public.mjs | 71 +- js/photos-public.mjs.license | 7 - js/photos-public.mjs.map | 2 +- js/photos-service-worker.js | 3116 ++++++++++++++++- js/photos-sidebar.mjs | 59 +- js/photos-sidebar.mjs.license | 12 - js/photos-sidebar.mjs.map | 2 +- js/preload-helper-DxYC2qmj.chunk.mjs | 2 - js/preload-helper-DxYC2qmj.chunk.mjs.license | 7 - js/preload-helper-DxYC2qmj.chunk.mjs.map | 1 - src/views/AlbumContent.vue | 26 +- 36 files changed, 3951 insertions(+), 93 deletions(-) delete mode 100644 css/CollectionsList-q-liS-Eo.chunk.css delete mode 100644 css/FaceContent-Bdbzv9Pd.chunk.css delete mode 100644 css/FaceCover-CriYllrK.chunk.css delete mode 100644 css/FaceMergeForm-DL6EU9Jq.chunk.css delete mode 100644 css/FacesView-Gits2579.chunk.css delete mode 100644 css/FoldersView-BC1tXPDF.chunk.css delete mode 100644 css/NcEmptyContent-BC9mI1uc.chunk.css delete mode 100644 css/NcProgressBar-D7zYeXBH-B3qS3u7h.chunk.css delete mode 100644 css/PhotosFiltersInput-B5iZrGH_.chunk.css delete mode 100644 css/PhotosTab-DGphhlff.chunk.css delete mode 100644 css/PlaceContent-Dr0VitMb.chunk.css delete mode 100644 css/TagContent-Bvp0UERJ.chunk.css delete mode 100644 css/TagsView-BI4e7UBA.chunk.css delete mode 100644 css/UnassignedFaces-uVbioLgS.chunk.css delete mode 100644 css/dashboard-Dk7DoScS.chunk.css delete mode 100644 css/public-BqRc5ISL.chunk.css delete mode 100644 js/photos-dashboard.mjs.license delete mode 100644 js/photos-main.mjs.license delete mode 100644 js/photos-public.mjs.license delete mode 100644 js/photos-sidebar.mjs.license delete mode 100644 js/preload-helper-DxYC2qmj.chunk.mjs delete mode 100644 js/preload-helper-DxYC2qmj.chunk.mjs.license delete mode 100644 js/preload-helper-DxYC2qmj.chunk.mjs.map diff --git a/css/CollectionsList-q-liS-Eo.chunk.css b/css/CollectionsList-q-liS-Eo.chunk.css deleted file mode 100644 index 4259b6212c..0000000000 --- a/css/CollectionsList-q-liS-Eo.chunk.css +++ /dev/null @@ -1 +0,0 @@ -.collection-cover[data-v-719cd191]{display:flex;flex-direction:column;padding:16px;border-radius:var(--border-radius-large)}.collection-cover[data-v-719cd191]:hover,.collection-cover[data-v-719cd191]:focus{background:var(--color-background-dark)}.collection-cover__image[data-v-719cd191]{width:350px;height:350px;object-fit:cover;border-radius:var(--border-radius-large)}@media only screen and (max-width:1200px){.collection-cover__image[data-v-719cd191]{width:250px;height:250px}}.collection-cover__image--placeholder[data-v-719cd191]{background:var(--color-primary-element-light)}.collection-cover__image--placeholder[data-v-719cd191] .material-design-icon{width:100%;height:100%}.collection-cover__image--placeholder[data-v-719cd191] .material-design-icon .material-design-icon__svg{fill:var(--color-primary-element)}.collection-cover__details[data-v-719cd191]{display:flex;flex-direction:column;margin-top:16px;width:350px}@media only screen and (max-width:1200px){.collection-cover__details[data-v-719cd191]{width:250px}}.collection-cover__details__title[data-v-719cd191]{display:flex;justify-content:space-between}.collection-cover__details__subtitle[data-v-719cd191]{display:flex;color:var(--color-text-lighter)}.collections[data-v-b585220f]{display:flex;flex-direction:column;height:100%}.collections__list[data-v-b585220f]{padding:32px 48px;flex-grow:1;display:flex;flex-wrap:wrap;gap:16px;align-items:flex-start;height:calc(100% - 60px);overflow-x:scroll}@media only screen and (max-width:1200px){.collections__list[data-v-b585220f]{padding:32px 12px;justify-content:center}} diff --git a/css/FaceContent-Bdbzv9Pd.chunk.css b/css/FaceContent-Bdbzv9Pd.chunk.css deleted file mode 100644 index 95f5bcb04f..0000000000 --- a/css/FaceContent-Bdbzv9Pd.chunk.css +++ /dev/null @@ -1 +0,0 @@ -.face[data-v-f938f213]{display:flex;flex-direction:column}.face__empty[data-v-f938f213]{display:flex;flex-direction:column;align-items:center}.face__empty__button[data-v-f938f213]{margin-top:32px}.face__header[data-v-f938f213]{display:flex;min-height:60px;align-items:center;justify-content:space-between;position:sticky;z-index:3;background:var(--color-main-background);padding:0 64px}@media only screen and (max-width:1020px){.face__header[data-v-f938f213]{padding:0;padding-inline-start:64px}}.face__header__left[data-v-f938f213]{height:100%;display:flex;align-items:center}.face__header__title[data-v-f938f213]{margin-inline-start:10px}.face__header__title h2[data-v-f938f213]{margin-bottom:0}.face__header__loader[data-v-f938f213]{margin-inline-start:32px}.face__header__actions[data-v-f938f213]{display:flex;align-items:center}.face__header__actions button[data-v-f938f213]{margin-inline-start:16px}.face__photos[data-v-f938f213]{margin-top:16px;height:100%;min-height:0;padding:0 64px}@media only screen and (max-width:1020px){.face__photos[data-v-f938f213]{padding:0}}.empty-content-with-illustration[data-v-f938f213] .empty-content__icon{width:200px;height:200px}.empty-content-with-illustration[data-v-f938f213] .empty-content__icon svg{width:200px;height:200px}.rename-form[data-v-f938f213]{display:flex;flex-direction:row;align-items:center;height:70px;padding:16px}.rename-form input[data-v-f938f213]{width:100%} diff --git a/css/FaceCover-CriYllrK.chunk.css b/css/FaceCover-CriYllrK.chunk.css deleted file mode 100644 index 2b5b285dda..0000000000 --- a/css/FaceCover-CriYllrK.chunk.css +++ /dev/null @@ -1 +0,0 @@ -.face-cover[data-v-5fedd4a1]{display:flex;flex-direction:column;padding:10px;border-radius:var(--border-radius-large)}.face-cover__crop-container[data-v-5fedd4a1]{overflow:hidden;width:128px;height:128px;border-radius:128px;position:relative;background:var(--color-background-darker);--photos-face-width: 128px}@media only screen and (max-width:1020px){.face-cover__crop-container[data-v-5fedd4a1]{width:95px;height:95px;--photos-face-width: 95px}}.face-cover[data-v-5fedd4a1]:hover,.face-cover[data-v-5fedd4a1]:focus{background:var(--color-background-hover)}.face-cover__details[data-v-5fedd4a1]{display:flex;flex-direction:column;width:128px;margin-top:4px;text-align:center}@media only screen and (max-width:1020px){.face-cover__details[data-v-5fedd4a1]{width:95px}}.face-cover__details__first-line[data-v-5fedd4a1]{display:flex;height:2em;overflow:hidden;text-overflow:ellipsis}.face-cover__details__second-line[data-v-5fedd4a1]{margin-top:6px;color:var(--color-text-maxcontrast)}.face-cover__details__name[data-v-5fedd4a1]{flex-grow:1;margin:0;font-weight:700;font-size:20px;line-height:30px;color:var(--color-main-text)}.face-cover--small *[data-v-5fedd4a1]{font-size:15px!important}.face-cover--small .face-cover__details[data-v-5fedd4a1]{width:60px!important}.face-cover--small .face-cover__crop-container[data-v-5fedd4a1]{width:60px!important;height:60px!important;--photos-face-width: 60px !important} diff --git a/css/FaceMergeForm-DL6EU9Jq.chunk.css b/css/FaceMergeForm-DL6EU9Jq.chunk.css deleted file mode 100644 index 963cb696e8..0000000000 --- a/css/FaceMergeForm-DL6EU9Jq.chunk.css +++ /dev/null @@ -1 +0,0 @@ -.face-list[data-v-b48e014f]{display:flex;flex-direction:row;height:350px;flex-wrap:wrap;padding:12px}.loader[data-v-b48e014f]{margin:25% auto} diff --git a/css/FacesView-Gits2579.chunk.css b/css/FacesView-Gits2579.chunk.css deleted file mode 100644 index 3eea180952..0000000000 --- a/css/FacesView-Gits2579.chunk.css +++ /dev/null @@ -1 +0,0 @@ -.face-cover[data-v-ef4bdf27]{display:flex;flex-direction:column;padding:10px;border-radius:var(--border-radius-large)}.face-cover__crop-container[data-v-ef4bdf27]{overflow:hidden;width:128px;height:128px;border-radius:128px;position:relative;background:var(--color-background-darker);--photos-face-width: 128px}@media only screen and (max-width:1020px){.face-cover__crop-container[data-v-ef4bdf27]{width:95px;height:95px;--photos-face-width: 95px}}.face-cover[data-v-ef4bdf27]:hover,.face-cover[data-v-ef4bdf27]:focus{background:var(--color-background-hover)}.face-cover__details[data-v-ef4bdf27]{display:flex;flex-direction:column;width:128px;margin-top:4px;text-align:center}@media only screen and (max-width:1020px){.face-cover__details[data-v-ef4bdf27]{width:95px}}.face-cover__details__first-line[data-v-ef4bdf27]{display:flex;height:2em;overflow:hidden;text-overflow:ellipsis}.face-cover__details__second-line[data-v-ef4bdf27]{margin-top:6px;color:var(--color-text-maxcontrast)}.face-cover__details__name[data-v-ef4bdf27]{flex-grow:1;margin:0;font-weight:700;font-size:20px;line-height:30px;color:var(--color-main-text)}.face-cover--small *[data-v-ef4bdf27]{font-size:15px!important}.face-cover--small .face-cover__details[data-v-ef4bdf27]{width:60px!important}.face-cover--small .face-cover__crop-container[data-v-ef4bdf27]{width:60px!important;height:60px!important;--photos-face-width: 60px !important}.faces[data-v-d27b108f]{display:flex;flex-direction:column;height:calc(100vh - var(--header-height));padding-inline-start:64px}@media only screen and (max-width:1020px){.faces[data-v-d27b108f]{padding:0}}.faces__header[data-v-d27b108f]{display:flex;min-height:60px;align-items:center}.faces__header button[data-v-d27b108f]{margin-inline-end:32px}.faces__list[data-v-d27b108f]{padding-top:24px;padding-bottom:32px;flex-grow:1;display:flex;flex-wrap:wrap;gap:32px;align-content:flex-start}.faces__empty[data-v-d27b108f]{display:flex;flex-direction:column;align-items:center}.faces__empty__button[data-v-d27b108f]{margin-top:32px}.empty-content-with-illustration[data-v-d27b108f] .empty-content__icon{width:200px;height:200px}.empty-content-with-illustration[data-v-d27b108f] .empty-content__icon svg{width:200px;height:200px} diff --git a/css/FoldersView-BC1tXPDF.chunk.css b/css/FoldersView-BC1tXPDF.chunk.css deleted file mode 100644 index fb6ee6f82e..0000000000 --- a/css/FoldersView-BC1tXPDF.chunk.css +++ /dev/null @@ -1 +0,0 @@ -.file[data-v-ab762322]{position:relative;display:flex;align-items:center;justify-content:center;-webkit-user-select:none;user-select:none;border-radius:var(--border-radius);overflow:hidden}.file .cover[data-v-ab762322]{z-index:2;width:100%;padding-bottom:100%;transition:opacity var(--animation-quick) ease-in-out;opacity:0;background-color:var(--color-main-text)}.file.active .cover[data-v-ab762322],.file:active .cover[data-v-ab762322],.file:hover .cover[data-v-ab762322],.file:focus .cover[data-v-ab762322]{opacity:.3}.file--clear.active .cover[data-v-ab762322],.file--clear:active .cover[data-v-ab762322],.file--clear:hover .cover[data-v-ab762322],.file--clear:focus .cover[data-v-ab762322]{opacity:.1}.fade-enter-active[data-v-ab762322],.fade-leave-active[data-v-ab762322]{transition:opacity var(--animation-quick) ease-in-out}.fade-enter[data-v-ab762322],.fade-leave-to[data-v-ab762322]{opacity:0}.transition-group[data-v-ab762322]{display:contents}.icon-video-white[data-v-ab762322]{position:absolute;top:10px;inset-inline-end:10px;z-index:20}img[data-v-ab762322]{position:absolute;width:100%;height:100%;z-index:10;color:transparent;object-fit:contain}.file--cropped img[data-v-ab762322]{object-fit:cover}svg[data-v-ab762322]{position:absolute;width:70%;height:70%}.folder[data-v-0660a5ac]{display:flex;flex-direction:column;padding:16px;border-radius:var(--border-radius-large)}.folder[data-v-0660a5ac]:hover,.folder[data-v-0660a5ac]:focus{background-color:var(--color-background-dark)}.folder__image[data-v-0660a5ac]{width:200px;height:200px;object-fit:cover;border-radius:var(--border-radius-large)}.folder__image--placeholder[data-v-0660a5ac]{background-color:var(--color-primary-element-light)}.folder__icon[data-v-0660a5ac]{width:100%;height:100%}.folder__details[data-v-0660a5ac]{display:flex;align-items:center;gap:12px;margin-top:16px;width:200px}.folder__title[data-v-0660a5ac]{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font-size:20px;margin-bottom:2px;line-height:30px;color:var(--color-main-text)}.file[data-v-056e4011]{position:relative;display:flex;align-items:center;justify-content:center;-webkit-user-select:none;user-select:none;border-radius:var(--border-radius);overflow:hidden}.file .cover[data-v-056e4011]{z-index:2;width:100%;padding-bottom:100%;transition:opacity var(--animation-quick) ease-in-out;opacity:0;background-color:var(--color-main-text)}.file.active .cover[data-v-056e4011],.file:active .cover[data-v-056e4011],.file:hover .cover[data-v-056e4011],.file:focus .cover[data-v-056e4011]{opacity:.3}.file--clear.active .cover[data-v-056e4011],.file--clear:active .cover[data-v-056e4011],.file--clear:hover .cover[data-v-056e4011],.file--clear:focus .cover[data-v-056e4011]{opacity:.1}.fade-enter-active[data-v-056e4011],.fade-leave-active[data-v-056e4011]{transition:opacity var(--animation-quick) ease-in-out}.fade-enter[data-v-056e4011],.fade-leave-to[data-v-056e4011]{opacity:0}.folder-content[data-v-056e4011]{position:absolute;display:grid;width:100%;height:100%}.folder-content--grid-1[data-v-056e4011]{grid-template-columns:1fr;grid-template-rows:1fr}.folder-content--grid-2[data-v-056e4011]{grid-template-columns:1fr;grid-template-rows:1fr 1fr}.folder-content--grid-3[data-v-056e4011]{grid-template-columns:1fr 1fr;grid-template-rows:1fr 1fr}.folder-content--grid-3 img[data-v-056e4011]:first-child{grid-column:span 2}.folder-content--grid-4[data-v-056e4011]{grid-template-columns:1fr 1fr;grid-template-rows:1fr 1fr}.folder-content img[data-v-056e4011]{width:100%;height:100%;object-fit:cover}.folder-name[data-v-056e4011]{position:absolute;z-index:3;display:flex;overflow:hidden;flex-direction:column;width:100%;height:100%;transition:opacity var(--animation-quick) ease-in-out;opacity:1}.folder-name__icon[data-v-056e4011]{height:40%;margin-top:calc(30% - .5rem);background-size:40%}.folder-name__name[data-v-056e4011]{overflow:hidden;height:1rem;padding:0 10px;text-align:center;white-space:nowrap;text-overflow:ellipsis;color:var(--color-main-background);text-shadow:0 0 8px var(--color-main-text);font-size:1rem;line-height:1rem}.folder--clear .folder-name__icon[data-v-056e4011]{opacity:.3}.folder--clear .folder-name__name[data-v-056e4011]{color:var(--color-main-text);text-shadow:0 0 8px var(--color-main-background)}.folder:not(.folder--clear) .cover[data-v-056e4011]{opacity:.3}.folder:not(.folder--clear).active .folder-name[data-v-056e4011],.folder:not(.folder--clear).active .cover[data-v-056e4011],.folder:not(.folder--clear):active .folder-name[data-v-056e4011],.folder:not(.folder--clear):active .cover[data-v-056e4011],.folder:not(.folder--clear):hover .folder-name[data-v-056e4011],.folder:not(.folder--clear):hover .cover[data-v-056e4011],.folder:not(.folder--clear):focus .folder-name[data-v-056e4011],.folder:not(.folder--clear):focus .cover[data-v-056e4011]{opacity:0}@media(min-width:0px)and (max-width:400px){.grid-container[data-v-8c8a8b95]{padding:0 8px 256px}}@media(min-width:400px)and (max-width:700px){.grid-container[data-v-8c8a8b95]{padding:0 8px 256px}}@media(min-width:700px)and (max-width:1024px){.grid-container[data-v-8c8a8b95]{padding:0 44px 256px}}@media(min-width:1024px)and (max-width:1280px){.grid-container[data-v-8c8a8b95]{padding:0 44px 256px}}@media(min-width:1280px)and (max-width:1440px){.grid-container[data-v-8c8a8b95]{padding:0 66px 256px}}@media(min-width:1440px)and (max-width:1600px){.grid-container[data-v-8c8a8b95]{padding:0 66px 256px}}@media(min-width:1600px)and (max-width:2048px){.grid-container[data-v-8c8a8b95]{padding:0 66px 256px}}@media(min-width:2048px)and (max-width:2560px){.grid-container[data-v-8c8a8b95]{padding:0 88px 256px}}@media(min-width:2560px)and (max-width:3440px){.grid-container[data-v-8c8a8b95]{padding:0 88px 256px}}@media(min-width:3440px){.grid-container[data-v-8c8a8b95]{padding:0 88px 256px}}.grid-container--folders[data-v-8c8a8b95]{padding:32px 48px}@media only screen and (max-width:400px){.grid-container--folders[data-v-8c8a8b95]{display:flex;justify-content:center;width:100%}}@media only screen and (min-width:400px){.grid-container--folders[data-v-8c8a8b95]{width:fit-content}}.photos-navigation[data-v-8c8a8b95]{position:relative}.photos-navigation--uploading[data-v-8c8a8b95]{margin-bottom:30px}.photos-navigation[data-v-8c8a8b95] .upload-picker .upload-picker__progress{position:absolute;bottom:-30px;inset-inline-start:64px;margin:0}.photos-navigation[data-v-8c8a8b95] .upload-picker .upload-picker__cancel{position:absolute;bottom:-24px;inset-inline-end:50px} diff --git a/css/NcEmptyContent-BC9mI1uc.chunk.css b/css/NcEmptyContent-BC9mI1uc.chunk.css deleted file mode 100644 index 98a6dc9dfc..0000000000 --- a/css/NcEmptyContent-BC9mI1uc.chunk.css +++ /dev/null @@ -1 +0,0 @@ -.material-design-icon[data-v-c3123941]{display:flex;align-self:center;justify-self:center;align-items:center;justify-content:center}.empty-content[data-v-c3123941]{display:flex;align-items:center;flex-direction:column;justify-content:center;flex-grow:1;padding:var(--default-grid-baseline)}.modal-wrapper .empty-content[data-v-c3123941]{margin-top:5vh;margin-bottom:5vh}.empty-content__icon[data-v-c3123941]{display:flex;align-items:center;justify-content:center;width:64px;height:64px;margin:0 auto 15px;opacity:.4;background-repeat:no-repeat;background-position:center;background-size:64px}.empty-content__icon[data-v-c3123941] svg{width:64px!important;height:64px!important;max-width:64px!important;max-height:64px!important}.empty-content__name[data-v-c3123941]{margin-bottom:10px;text-align:center;font-weight:700;font-size:20px;line-height:30px}.empty-content__description[data-v-c3123941]{color:var(--color-text-maxcontrast);text-align:center;text-wrap-style:balance}.empty-content__action[data-v-c3123941]{margin-top:8px}.modal-wrapper .empty-content__action[data-v-c3123941]{margin-top:20px;display:flex} diff --git a/css/NcProgressBar-D7zYeXBH-B3qS3u7h.chunk.css b/css/NcProgressBar-D7zYeXBH-B3qS3u7h.chunk.css deleted file mode 100644 index 0e09c20ae6..0000000000 --- a/css/NcProgressBar-D7zYeXBH-B3qS3u7h.chunk.css +++ /dev/null @@ -1 +0,0 @@ -.material-design-icon[data-v-7bf21eca]{display:flex;align-self:center;justify-self:center;align-items:center;justify-content:center}.app-navigation-caption[data-v-7bf21eca]{color:var(--color-text-maxcontrast);line-height:var(--default-clickable-area);white-space:nowrap;text-overflow:ellipsis;box-shadow:none!important;-webkit-user-select:none;user-select:none;pointer-events:none;margin-inline-start:12px;padding-inline-end:14px;height:var(--default-clickable-area);display:flex;align-items:center}.material-design-icon[data-v-3e2324b7]{display:flex;align-self:center;justify-self:center;align-items:center;justify-content:center}.action-separator[data-v-3e2324b7]{height:0;margin:5px 10px 5px 15px;border-bottom:1px solid var(--color-border-dark);cursor:default}.material-design-icon[data-v-06c9abdc]{display:flex;align-self:center;justify-self:center;align-items:center;justify-content:center}.progress-bar[data-v-06c9abdc]{display:block;height:var(--progress-bar-height);--progress-bar-color: var(--15a054de)}.progress-bar--linear[data-v-06c9abdc]{width:100%;overflow:hidden;border:0;padding:0;background:var(--color-background-dark);border-radius:calc(var(--progress-bar-height) / 2)}.progress-bar--linear[data-v-06c9abdc]::-webkit-progress-bar{height:var(--progress-bar-height);background-color:transparent}.progress-bar--linear[data-v-06c9abdc]::-webkit-progress-value{background:var(--progress-bar-color, var(--gradient-primary-background));border-radius:calc(var(--progress-bar-height) / 2)}.progress-bar--linear[data-v-06c9abdc]::-moz-progress-bar{background:var(--progress-bar-color, var(--gradient-primary-background));border-radius:calc(var(--progress-bar-height) / 2)}.progress-bar--circular[data-v-06c9abdc]{width:var(--progress-bar-height);color:var(--progress-bar-color, var(--color-primary-element))}.progress-bar--error[data-v-06c9abdc]{color:var(--color-text-error, var(--color-error))!important}.progress-bar--error[data-v-06c9abdc]::-moz-progress-bar{background:var(--color-text-error, var(--color-error))!important}.progress-bar--error[data-v-06c9abdc]::-webkit-progress-value{background:var(--color-text-error, var(--color-error))!important} diff --git a/css/PhotosFiltersInput-B5iZrGH_.chunk.css b/css/PhotosFiltersInput-B5iZrGH_.chunk.css deleted file mode 100644 index f8e0ed7689..0000000000 --- a/css/PhotosFiltersInput-B5iZrGH_.chunk.css +++ /dev/null @@ -1 +0,0 @@ -.date-range-picker-dialog[data-v-3b73070f]{height:400px;display:flex;justify-content:center;align-items:flex-start}.date-range-picker-dialog__picker[data-v-3b73070f]{flex-grow:1}.material-design-icon[data-v-c8e429a5]{display:flex;align-self:center;justify-self:center;align-items:center;justify-content:center}.nc-chip[data-v-c8e429a5]{--chip-size: 24px;--chip-radius: calc(var(--chip-size) / 2);height:var(--chip-size);max-width:fit-content;display:flex;flex-direction:row;align-items:center;border-radius:var(--chip-radius);background-color:var(--color-background-hover)}.nc-chip--primary[data-v-c8e429a5]{background-color:var(--color-primary-element);color:var(--color-primary-element-text)}.nc-chip--secondary[data-v-c8e429a5]{background-color:var(--color-primary-element-light);color:var(--color-primary-element-light-text)}.nc-chip--error[data-v-c8e429a5]{background-color:var(--color-error);color:var(--color-error-text)}.nc-chip--warning[data-v-c8e429a5]{background-color:var(--color-warning);color:var(--color-warning-text)}.nc-chip--success[data-v-c8e429a5]{background-color:var(--color-success);color:var(--color-success-text)}.nc-chip--no-actions .nc-chip__text[data-v-c8e429a5]{padding-inline-end:calc(2 * var(--default-grid-baseline))}.nc-chip--no-icon .nc-chip__text[data-v-c8e429a5]{padding-inline-start:calc(2 * var(--default-grid-baseline))}.nc-chip__text[data-v-c8e429a5]{flex:1 auto;overflow:hidden;text-overflow:ellipsis;text-wrap:nowrap}.nc-chip__icon[data-v-c8e429a5]{flex:0 0 var(--chip-size);margin-inline-end:var(--default-grid-baseline);line-height:1;display:flex;align-items:center;justify-content:center;overflow:hidden;height:var(--chip-size);width:var(--chip-size)}.nc-chip__actions[data-v-c8e429a5]{flex:0 0 var(--chip-size);--default-clickable-area: var(--chip-size);--border-radius-element: var(--chip-radius)}.place__preview[data-v-e05d44dd]{width:20px;height:20px;border-radius:100%}.photos-filters-display__filter[data-v-db72611f]{display:flex;align-items:flex-start}.photos-filters-display__filter__options-container[data-v-db72611f]{display:flex;flex-wrap:wrap;gap:4px}.photos-filters-display__filter__options-container__option[data-v-db72611f]{margin:4px 0}.photos-filters-input[data-v-cd233c90]{display:flex;flex-direction:column;justify-content:center;padding:8px 8px 0}[data-v-cd233c90] .vs__dropdown-toggle{background-color:var(--color-main-background)} diff --git a/css/PhotosTab-DGphhlff.chunk.css b/css/PhotosTab-DGphhlff.chunk.css deleted file mode 100644 index 39e77afbd7..0000000000 --- a/css/PhotosTab-DGphhlff.chunk.css +++ /dev/null @@ -1 +0,0 @@ -.leaflet-default-icon-icon{background-image:url(~leaflet/dist/images/marker-icon.png),url(~leaflet/dist/images/marker-icon-2x.png);cursor:url(~leaflet/dist/images/marker-icon.png),url(~leaflet/dist/images/marker-icon-2x.png),auto;width:25px;height:41px;margin:-41px -12px}.leaflet-default-icon-shadow{background-image:url(~leaflet/dist/images/marker-shadow.png);cursor:url(~leaflet/dist/images/marker-shadow.png),auto;width:41px;height:41px;margin:-41px -12px}.leaflet-default-icon-popup{margin:-34px 1px}.leaflet-default-icon-tooltip{margin:-28px 16px}.leaflet-pane,.leaflet-tile,.leaflet-marker-icon,.leaflet-marker-shadow,.leaflet-tile-container,.leaflet-pane>svg,.leaflet-pane>canvas,.leaflet-zoom-box,.leaflet-image-layer,.leaflet-layer{position:absolute;left:0;top:0}.leaflet-container{overflow:hidden}.leaflet-tile,.leaflet-marker-icon,.leaflet-marker-shadow{-webkit-user-select:none;user-select:none;-webkit-user-drag:none}.leaflet-tile::selection{background:transparent}.leaflet-safari .leaflet-tile{image-rendering:-webkit-optimize-contrast}.leaflet-safari .leaflet-tile-container{width:1600px;height:1600px;-webkit-transform-origin:0 0}.leaflet-marker-icon,.leaflet-marker-shadow{display:block}.leaflet-container .leaflet-overlay-pane svg{max-width:none!important;max-height:none!important}.leaflet-container .leaflet-marker-pane img,.leaflet-container .leaflet-shadow-pane img,.leaflet-container .leaflet-tile-pane img,.leaflet-container img.leaflet-image-layer,.leaflet-container .leaflet-tile{max-width:none!important;max-height:none!important;width:auto;padding:0}.leaflet-container img.leaflet-tile{mix-blend-mode:plus-lighter}.leaflet-container.leaflet-touch-zoom{touch-action:pan-x pan-y}.leaflet-container.leaflet-touch-drag{touch-action:none;touch-action:pinch-zoom}.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom{touch-action:none}.leaflet-container{-webkit-tap-highlight-color:transparent}.leaflet-container a{-webkit-tap-highlight-color:rgba(51,181,229,.4)}.leaflet-tile{filter:inherit;visibility:hidden}.leaflet-tile-loaded{visibility:inherit}.leaflet-zoom-box{width:0;height:0;box-sizing:border-box;z-index:800}.leaflet-overlay-pane svg{-moz-user-select:none}.leaflet-pane{z-index:400}.leaflet-tile-pane{z-index:200}.leaflet-overlay-pane{z-index:400}.leaflet-shadow-pane{z-index:500}.leaflet-marker-pane{z-index:600}.leaflet-tooltip-pane{z-index:650}.leaflet-popup-pane{z-index:700}.leaflet-map-pane canvas{z-index:100}.leaflet-map-pane svg{z-index:200}.leaflet-vml-shape{width:1px;height:1px}.lvml{behavior:url(#default#VML);display:inline-block;position:absolute}.leaflet-control{position:relative;z-index:800;pointer-events:visiblePainted;pointer-events:auto}.leaflet-top,.leaflet-bottom{position:absolute;z-index:1000;pointer-events:none}.leaflet-top{top:0}.leaflet-right{right:0}.leaflet-bottom{bottom:0}.leaflet-left{left:0}.leaflet-control{float:left;clear:both}.leaflet-right .leaflet-control{float:right}.leaflet-top .leaflet-control{margin-top:10px}.leaflet-bottom .leaflet-control{margin-bottom:10px}.leaflet-left .leaflet-control{margin-left:10px}.leaflet-right .leaflet-control{margin-right:10px}.leaflet-fade-anim .leaflet-popup{opacity:0;transition:opacity .2s linear}.leaflet-fade-anim .leaflet-map-pane .leaflet-popup{opacity:1}.leaflet-zoom-animated{transform-origin:0 0}svg.leaflet-zoom-animated{will-change:transform}.leaflet-zoom-anim .leaflet-zoom-animated{transition:transform .25s cubic-bezier(0,0,.25,1)}.leaflet-zoom-anim .leaflet-tile,.leaflet-pan-anim .leaflet-tile{transition:none}.leaflet-zoom-anim .leaflet-zoom-hide{visibility:hidden}.leaflet-interactive{cursor:pointer}.leaflet-grab{cursor:grab}.leaflet-crosshair,.leaflet-crosshair .leaflet-interactive{cursor:crosshair}.leaflet-popup-pane,.leaflet-control{cursor:auto}.leaflet-dragging .leaflet-grab,.leaflet-dragging .leaflet-grab .leaflet-interactive,.leaflet-dragging .leaflet-marker-draggable{cursor:move;cursor:grabbing}.leaflet-marker-icon,.leaflet-marker-shadow,.leaflet-image-layer,.leaflet-pane>svg path,.leaflet-tile-container{pointer-events:none}.leaflet-marker-icon.leaflet-interactive,.leaflet-image-layer.leaflet-interactive,.leaflet-pane>svg path.leaflet-interactive,svg.leaflet-image-layer.leaflet-interactive path{pointer-events:visiblePainted;pointer-events:auto}.leaflet-container{background:#ddd;outline-offset:1px}.leaflet-container a{color:#0078a8}.leaflet-zoom-box{border:2px dotted #38f;background:#ffffff80}.leaflet-container{font-family:Helvetica Neue,Arial,Helvetica,sans-serif;font-size:12px;font-size:.75rem;line-height:1.5}.leaflet-bar{box-shadow:0 1px 5px #000000a6;border-radius:4px}.leaflet-bar a{background-color:#fff;border-bottom:1px solid #ccc;width:26px;height:26px;line-height:26px;display:block;text-align:center;text-decoration:none;color:#000}.leaflet-bar a,.leaflet-control-layers-toggle{background-position:50% 50%;background-repeat:no-repeat;display:block}.leaflet-bar a:hover,.leaflet-bar a:focus{background-color:#f4f4f4}.leaflet-bar a:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.leaflet-bar a:last-child{border-bottom-left-radius:4px;border-bottom-right-radius:4px;border-bottom:none}.leaflet-bar a.leaflet-disabled{cursor:default;background-color:#f4f4f4;color:#bbb}.leaflet-touch .leaflet-bar a{width:30px;height:30px;line-height:30px}.leaflet-touch .leaflet-bar a:first-child{border-top-left-radius:2px;border-top-right-radius:2px}.leaflet-touch .leaflet-bar a:last-child{border-bottom-left-radius:2px;border-bottom-right-radius:2px}.leaflet-control-zoom-in,.leaflet-control-zoom-out{font:700 18px Lucida Console,Monaco,monospace;text-indent:1px}.leaflet-touch .leaflet-control-zoom-in,.leaflet-touch .leaflet-control-zoom-out{font-size:22px}.leaflet-control-layers{box-shadow:0 1px 5px #0006;background:#fff;border-radius:5px}.leaflet-control-layers-toggle{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAQAAAADQ4RFAAACf0lEQVR4AY1UM3gkARTePdvdoTxXKc+qTl3aU5U6b2Kbkz3Gtq3Zw6ziLGNPzrYx7946Tr6/ee/XeCQ4D3ykPtL5tHno4n0d/h3+xfuWHGLX81cn7r0iTNzjr7LrlxCqPtkbTQEHeqOrTy4Yyt3VCi/IOB0v7rVC7q45Q3Gr5K6jt+3Gl5nCoDD4MtO+j96Wu8atmhGqcNGHObuf8OM/x3AMx38+4Z2sPqzCxRFK2aF2e5Jol56XTLyggAMTL56XOMoS1W4pOyjUcGGQdZxU6qRh7B9Zp+PfpOFlqt0zyDZckPi1ttmIp03jX8gyJ8a/PG2yutpS/Vol7peZIbZcKBAEEheEIAgFbDkz5H6Zrkm2hVWGiXKiF4Ycw0RWKdtC16Q7qe3X4iOMxruonzegJzWaXFrU9utOSsLUmrc0YjeWYjCW4PDMADElpJSSQ0vQvA1Tm6/JlKnqFs1EGyZiFCqnRZTEJJJiKRYzVYzJck2Rm6P4iH+cmSY0YzimYa8l0EtTODFWhcMIMVqdsI2uiTvKmTisIDHJ3od5GILVhBCarCfVRmo4uTjkhrhzkiBV7SsaqS+TzrzM1qpGGUFt28pIySQHR6h7F6KSwGWm97ay+Z+ZqMcEjEWebE7wxCSQwpkhJqoZA5ivCdZDjJepuJ9IQjGGUmuXJdBFUygxVqVsxFsLMbDe8ZbDYVCGKxs+W080max1hFCarCfV+C1KATwcnvE9gRRuMP2prdbWGowm1KB1y+zwMMENkM755cJ2yPDtqhTI6ED1M/82yIDtC/4j4BijjeObflpO9I9MwXTCsSX8jWAFeHr05WoLTJ5G8IQVS/7vwR6ohirYM7f6HzYpogfS3R2OAAAAAElFTkSuQmCC);width:36px;height:36px}.leaflet-retina .leaflet-control-layers-toggle{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADQAAAA0CAQAAABvcdNgAAAEsklEQVR4AWL4TydIhpZK1kpWOlg0w3ZXP6D2soBtG42jeI6ZmQTHzAxiTbSJsYLjO9HhP+WOmcuhciVnmHVQcJnp7DFvScowZorad/+V/fVzMdMT2g9Cv9guXGv/7pYOrXh2U+RRR3dSd9JRx6bIFc/ekqHI29JC6pJ5ZEh1yWkhkbcFeSjxgx3L2m1cb1C7bceyxA+CNjT/Ifff+/kDk2u/w/33/IeCMOSaWZ4glosqT3DNnNZQ7Cs58/3Ce5HL78iZH/vKVIaYlqzfdLu8Vi7dnvUbEza5Idt36tquZFldl6N5Z/POLof0XLK61mZCmJSWjVF9tEjUluu74IUXvgttuVIHE7YxSkaYhJZam7yiM9Pv82JYfl9nptxZaxMJE4YSPty+vF0+Y2up9d3wwijfjZbabqm/3bZ9ecKHsiGmRflnn1MW4pjHf9oLufyn2z3y1D6n8g8TZhxyzipLNPnAUpsOiuWimg52psrTZYnOWYNDTMuWBWa0tJb4rgq1UvmutpaYEbZlwU3CLJm/ayYjHW5/h7xWLn9Hh1vepDkyf7dE7MtT5LR4e7yYpHrkhOUpEfssBLq2pPhAqoSWKUkk7EDqkmK6RrCEzqDjhNDWNE+XSMvkJRDWlZTmCW0l0PHQGRZY5t1L83kT0Y3l2SItk5JAWHl2dCOBm+fPu3fo5/3v61RMCO9Jx2EEYYhb0rmNQMX/vm7gqOEJLcXTGw3CAuRNeyaPWwjR8PRqKQ1PDA/dpv+on9Shox52WFnx0KY8onHayrJzm87i5h9xGw/tfkev0jGsQizqezUKjk12hBMKJ4kbCqGPVNXudyyrShovGw5CgxsRICxF6aRmSjlBnHRzg7Gx8fKqEubI2rahQYdR1YgDIRQO7JvQyD52hoIQx0mxa0ODtW2Iozn1le2iIRdzwWewedyZzewidueOGqlsn1MvcnQpuVwLGG3/IR1hIKxCjelIDZ8ldqWz25jWAsnldEnK0Zxro19TGVb2ffIZEsIO89EIEDvKMPrzmBOQcKQ+rroye6NgRRxqR4U8EAkz0CL6uSGOm6KQCdWjvjRiSP1BPalCRS5iQYiEIvxuBMJEWgzSoHADcVMuN7IuqqTeyUPq22qFimFtxDyBBJEwNyt6TM88blFHao/6tWWhuuOM4SAK4EI4QmFHA+SEyWlp4EQoJ13cYGzMu7yszEIBOm2rVmHUNqwAIQabISNMRstmdhNWcFLsSm+0tjJH1MdRxO5Nx0WDMhCtgD6OKgZeljJqJKc9po8juskR9XN0Y1lZ3mWjLR9JCO1jRDMd0fpYC2VnvjBSEFg7wBENc0R9HFlb0xvF1+TBEpF68d+DHR6IOWVv2BECtxo46hOFUBd/APU57WIoEwJhIi2CdpyZX0m93BZicktMj1AS9dClteUFAUNUIEygRZCtik5zSxI9MubTBH1GOiHsiLJ3OCoSZkILa9PxiN0EbvhsAo8tdAf9Seepd36lGWHmtNANTv5Jd0z4QYyeo/UEJqxKRpg5LZx6btLPsOaEmdMyxYdlc8LMaJnikDlhclqmPiQnTEpLUIZEwkRagjYkEibQErwhkTAKCLQEbUgkzJQWc/0PstHHcfEdQ+UAAAAASUVORK5CYII=);background-size:26px 26px}.leaflet-touch .leaflet-control-layers-toggle{width:44px;height:44px}.leaflet-control-layers .leaflet-control-layers-list,.leaflet-control-layers-expanded .leaflet-control-layers-toggle{display:none}.leaflet-control-layers-expanded .leaflet-control-layers-list{display:block;position:relative}.leaflet-control-layers-expanded{padding:6px 10px 6px 6px;color:#333;background:#fff}.leaflet-control-layers-scrollbar{overflow-y:scroll;overflow-x:hidden;padding-right:5px}.leaflet-control-layers-selector{margin-top:2px;position:relative;top:1px}.leaflet-control-layers label{display:block;font-size:13px;font-size:1.08333em}.leaflet-control-layers-separator{height:0;border-top:1px solid #ddd;margin:5px -10px 5px -6px}.leaflet-default-icon-path{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAApCAYAAADAk4LOAAAFgUlEQVR4Aa1XA5BjWRTN2oW17d3YaZtr2962HUzbDNpjszW24mRt28p47v7zq/bXZtrp/lWnXr337j3nPCe85NcypgSFdugCpW5YoDAMRaIMqRi6aKq5E3YqDQO3qAwjVWrD8Ncq/RBpykd8oZUb/kaJutow8r1aP9II0WmLKLIsJyv1w/kqw9Ch2MYdB++12Onxee/QMwvf4/Dk/Lfp/i4nxTXtOoQ4pW5Aj7wpici1A9erdAN2OH64x8OSP9j3Ft3b7aWkTg/Fm91siTra0f9on5sQr9INejH6CUUUpavjFNq1B+Oadhxmnfa8RfEmN8VNAsQhPqF55xHkMzz3jSmChWU6f7/XZKNH+9+hBLOHYozuKQPxyMPUKkrX/K0uWnfFaJGS1QPRtZsOPtr3NsW0uyh6NNCOkU3Yz+bXbT3I8G3xE5EXLXtCXbbqwCO9zPQYPRTZ5vIDXD7U+w7rFDEoUUf7ibHIR4y6bLVPXrz8JVZEql13trxwue/uDivd3fkWRbS6/IA2bID4uk0UpF1N8qLlbBlXs4Ee7HLTfV1j54APvODnSfOWBqtKVvjgLKzF5YdEk5ewRkGlK0i33Eofffc7HT56jD7/6U+qH3Cx7SBLNntH5YIPvODnyfIXZYRVDPqgHtLs5ABHD3YzLuespb7t79FY34DjMwrVrcTuwlT55YMPvOBnRrJ4VXTdNnYug5ucHLBjEpt30701A3Ts+HEa73u6dT3FNWwflY86eMHPk+Yu+i6pzUpRrW7SNDg5JHR4KapmM5Wv2E8Tfcb1HoqqHMHU+uWDD7zg54mz5/2BSnizi9T1Dg4QQXLToGNCkb6tb1NU+QAlGr1++eADrzhn/u8Q2YZhQVlZ5+CAOtqfbhmaUCS1ezNFVm2imDbPmPng5wmz+gwh+oHDce0eUtQ6OGDIyR0uUhUsoO3vfDmmgOezH0mZN59x7MBi++WDL1g/eEiU3avlidO671bkLfwbw5XV2P8Pzo0ydy4t2/0eu33xYSOMOD8hTf4CrBtGMSoXfPLchX+J0ruSePw3LZeK0juPJbYzrhkH0io7B3k164hiGvawhOKMLkrQLyVpZg8rHFW7E2uHOL888IBPlNZ1FPzstSJM694fWr6RwpvcJK60+0HCILTBzZLFNdtAzJaohze60T8qBzyh5ZuOg5e7uwQppofEmf2++DYvmySqGBuKaicF1blQjhuHdvCIMvp8whTTfZzI7RldpwtSzL+F1+wkdZ2TBOW2gIF88PBTzD/gpeREAMEbxnJcaJHNHrpzji0gQCS6hdkEeYt9DF/2qPcEC8RM28Hwmr3sdNyht00byAut2k3gufWNtgtOEOFGUwcXWNDbdNbpgBGxEvKkOQsxivJx33iow0Vw5S6SVTrpVq11ysA2Rp7gTfPfktc6zhtXBBC+adRLshf6sG2RfHPZ5EAc4sVZ83yCN00Fk/4kggu40ZTvIEm5g24qtU4KjBrx/BTTH8ifVASAG7gKrnWxJDcU7x8X6Ecczhm3o6YicvsLXWfh3Ch1W0k8x0nXF+0fFxgt4phz8QvypiwCCFKMqXCnqXExjq10beH+UUA7+nG6mdG/Pu0f3LgFcGrl2s0kNNjpmoJ9o4B29CMO8dMT4Q5ox8uitF6fqsrJOr8qnwNbRzv6hSnG5wP+64C7h9lp30hKNtKdWjtdkbuPA19nJ7Tz3zR/ibgARbhb4AlhavcBebmTHcFl2fvYEnW0ox9xMxKBS8btJ+KiEbq9zA4RthQXDhPa0T9TEe69gWupwc6uBUphquXgf+/FrIjweHQS4/pduMe5ERUMHUd9xv8ZR98CxkS4F2n3EUrUZ10EYNw7BWm9x1GiPssi3GgiGRDKWRYZfXlON+dfNbM+GgIwYdwAAAAASUVORK5CYII=)}.leaflet-container .leaflet-control-attribution{background:#fff;background:#fffc;margin:0}.leaflet-control-attribution,.leaflet-control-scale-line{padding:0 5px;color:#333;line-height:1.4}.leaflet-control-attribution a{text-decoration:none}.leaflet-control-attribution a:hover,.leaflet-control-attribution a:focus{text-decoration:underline}.leaflet-attribution-flag{display:inline!important;vertical-align:baseline!important;width:1em;height:.6669em}.leaflet-left .leaflet-control-scale{margin-left:5px}.leaflet-bottom .leaflet-control-scale{margin-bottom:5px}.leaflet-control-scale-line{border:2px solid #777;border-top:none;line-height:1.1;padding:2px 5px 1px;white-space:nowrap;box-sizing:border-box;background:#fffc;text-shadow:1px 1px #fff}.leaflet-control-scale-line:not(:first-child){border-top:2px solid #777;border-bottom:none;margin-top:-2px}.leaflet-control-scale-line:not(:first-child):not(:last-child){border-bottom:2px solid #777}.leaflet-touch .leaflet-control-attribution,.leaflet-touch .leaflet-control-layers,.leaflet-touch .leaflet-bar{box-shadow:none}.leaflet-touch .leaflet-control-layers,.leaflet-touch .leaflet-bar{border:2px solid rgba(0,0,0,.2);background-clip:padding-box}.leaflet-popup{position:absolute;text-align:center;margin-bottom:20px}.leaflet-popup-content-wrapper{padding:1px;text-align:left;border-radius:12px}.leaflet-popup-content{margin:13px 24px 13px 20px;line-height:1.3;font-size:13px;font-size:1.08333em;min-height:1px}.leaflet-popup-content p{margin:1.3em 0}.leaflet-popup-tip-container{width:40px;height:20px;position:absolute;left:50%;margin-top:-1px;margin-left:-20px;overflow:hidden;pointer-events:none}.leaflet-popup-tip{width:17px;height:17px;padding:1px;margin:-10px auto 0;pointer-events:auto;transform:rotate(45deg)}.leaflet-popup-content-wrapper,.leaflet-popup-tip{background:#fff;color:#333;box-shadow:0 3px 14px #0006}.leaflet-container a.leaflet-popup-close-button{position:absolute;top:0;right:0;border:none;text-align:center;width:24px;height:24px;font:16px/24px Tahoma,Verdana,sans-serif;color:#757575;text-decoration:none;background:transparent}.leaflet-container a.leaflet-popup-close-button:hover,.leaflet-container a.leaflet-popup-close-button:focus{color:#585858}.leaflet-popup-scrolled{overflow:auto}.leaflet-oldie .leaflet-popup-content-wrapper{-ms-zoom:1}.leaflet-oldie .leaflet-popup-tip{width:24px;margin:0 auto;-ms-filter:"progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";filter:progid:DXImageTransform.Microsoft.Matrix(M11=.70710678,M12=.70710678,M21=-.70710678,M22=.70710678)}.leaflet-oldie .leaflet-control-zoom,.leaflet-oldie .leaflet-control-layers,.leaflet-oldie .leaflet-popup-content-wrapper,.leaflet-oldie .leaflet-popup-tip{border:1px solid #999}.leaflet-div-icon{background:#fff;border:1px solid #666}.leaflet-tooltip{position:absolute;padding:6px;background-color:#fff;border:1px solid #fff;border-radius:3px;color:#222;white-space:nowrap;-webkit-user-select:none;user-select:none;pointer-events:none;box-shadow:0 1px 3px #0006}.leaflet-tooltip.leaflet-interactive{cursor:pointer;pointer-events:auto}.leaflet-tooltip-top:before,.leaflet-tooltip-bottom:before,.leaflet-tooltip-left:before,.leaflet-tooltip-right:before{position:absolute;pointer-events:none;border:6px solid transparent;background:transparent;content:""}.leaflet-tooltip-bottom{margin-top:6px}.leaflet-tooltip-top{margin-top:-6px}.leaflet-tooltip-bottom:before,.leaflet-tooltip-top:before{left:50%;margin-left:-6px}.leaflet-tooltip-top:before{bottom:0;margin-bottom:-12px;border-top-color:#fff}.leaflet-tooltip-bottom:before{top:0;margin-top:-12px;margin-left:-6px;border-bottom-color:#fff}.leaflet-tooltip-left{margin-left:-6px}.leaflet-tooltip-right{margin-left:6px}.leaflet-tooltip-left:before,.leaflet-tooltip-right:before{top:50%;margin-top:-6px}.leaflet-tooltip-left:before{right:0;margin-right:-12px;border-left-color:#fff}.leaflet-tooltip-right:before{left:0;margin-left:-12px;border-right-color:#fff}@media print{.leaflet-control{-webkit-print-color-adjust:exact;print-color-adjust:exact}}.location-map[data-v-72cd10d3]{position:relative;margin:16px;border-radius:var(--border-radius-large);height:250px;width:90%}.photo-details-container[data-v-48b4ba63]{padding:8px}.photo-details-container .photo-detail[data-v-48b4ba63]{margin:16px 0;display:flex;flex-direction:row}.photo-details-container .photo-detail--secondary[data-v-48b4ba63]{color:var(--color-text-lighter)}.photo-details-container .photo-detail__gps[data-v-48b4ba63]{flex-direction:column}.photo-details-container .photo-detail__gps__title[data-v-48b4ba63],.photo-details-container .photo-detail__gps__map[data-v-48b4ba63]{display:flex}.photo-details-container .photo-detail .material-design-icon[data-v-48b4ba63]{margin-inline-end:8px} diff --git a/css/PlaceContent-Dr0VitMb.chunk.css b/css/PlaceContent-Dr0VitMb.chunk.css deleted file mode 100644 index a3e251b5ca..0000000000 --- a/css/PlaceContent-Dr0VitMb.chunk.css +++ /dev/null @@ -1 +0,0 @@ -.place[data-v-30000657]{display:flex;flex-direction:column}.place__title[data-v-30000657]{width:100%}.place__name[data-v-30000657]{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.place__place[data-v-30000657]{margin-inline-start:-4px;display:flex;color:var(--color-text-lighter)} diff --git a/css/TagContent-Bvp0UERJ.chunk.css b/css/TagContent-Bvp0UERJ.chunk.css deleted file mode 100644 index 737b19737b..0000000000 --- a/css/TagContent-Bvp0UERJ.chunk.css +++ /dev/null @@ -1 +0,0 @@ -.loader[data-v-f993cbc7]{margin-top:30vh}.photos-navigation[data-v-f993cbc7]{display:flex;height:44px;padding:0 40px;align-items:center;max-width:100%}.photos-navigation h2[data-v-f993cbc7]{padding:0;margin:0}.heading-subline[data-v-f993cbc7]{margin-inline-start:85px;margin-top:-11px;color:var(--color-text-maxcontrast)}.tag__photos[data-v-f993cbc7]{padding:0 64px} diff --git a/css/TagsView-BI4e7UBA.chunk.css b/css/TagsView-BI4e7UBA.chunk.css deleted file mode 100644 index bb215240ff..0000000000 --- a/css/TagsView-BI4e7UBA.chunk.css +++ /dev/null @@ -1 +0,0 @@ -.tag-cover[data-v-4e0e61e1]{display:flex;flex-direction:column;padding:16px;border-radius:12px}.tag-cover[data-v-4e0e61e1]:hover,.tag-cover[data-v-4e0e61e1]:focus{background:var(--color-background-dark)}.tag-cover__image[data-v-4e0e61e1]{width:350px;height:350px;object-fit:cover;border-radius:12px}@media only screen and (max-width:1200px){.tag-cover__image[data-v-4e0e61e1]{width:250px;height:250px}}.tag-cover__image--placeholder[data-v-4e0e61e1]{background:var(--color-primary-element-light)}.tag-cover__image--placeholder[data-v-4e0e61e1] .material-design-icon{width:100%;height:100%}.tag-cover__image--placeholder[data-v-4e0e61e1] .material-design-icon .material-design-icon__svg{fill:var(--color-primary-element)}.tag-cover__details[data-v-4e0e61e1]{display:flex;flex-direction:column;margin-top:16px;width:350px}@media only screen and (max-width:1200px){.tag-cover__details[data-v-4e0e61e1]{width:250px}}.tag-cover__details__first-line[data-v-4e0e61e1]{display:flex}.tag-cover__details__second-line[data-v-4e0e61e1]{display:flex;color:var(--color-text-lighter)}.tag-cover__details__name[data-v-4e0e61e1]{flex-grow:1;margin:0;font-weight:400;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.loader[data-v-cb8dfce8]{margin-top:30vh}.container[data-v-cb8dfce8]{padding-inline-start:44px}.container>h2[data-v-cb8dfce8]{margin-inline-start:14px;margin-top:40px}.popular-tags[data-v-cb8dfce8],.tags[data-v-cb8dfce8]{display:flex;flex-direction:row;gap:8px;flex-wrap:wrap} diff --git a/css/UnassignedFaces-uVbioLgS.chunk.css b/css/UnassignedFaces-uVbioLgS.chunk.css deleted file mode 100644 index 679c5ff35a..0000000000 --- a/css/UnassignedFaces-uVbioLgS.chunk.css +++ /dev/null @@ -1 +0,0 @@ -.face[data-v-2c344404]{display:flex;flex-direction:column}.face__empty[data-v-2c344404]{display:flex;flex-direction:column;align-items:center}.face__empty__button[data-v-2c344404]{margin-top:32px}.face__header[data-v-2c344404]{display:flex;min-height:60px;align-items:center;justify-content:space-between;position:sticky;z-index:3;background:var(--color-main-background);padding:0 64px}@media only screen and (max-width:1020px){.face__header[data-v-2c344404]{padding:0;padding-inline-start:64px}}.face__header__left[data-v-2c344404]{height:100%;display:flex;align-items:center}.face__header__title[data-v-2c344404]{margin-inline-start:10px}.face__header__title h2[data-v-2c344404]{margin-bottom:0}.face__header__loader[data-v-2c344404]{margin-inline-start:32px}.face__header__actions[data-v-2c344404]{display:flex;align-items:center}.face__header__actions button[data-v-2c344404]{margin-inline-start:16px}.face__photos[data-v-2c344404]{margin-top:16px;height:100%;min-height:0;padding:0 64px}@media only screen and (max-width:1020px){.face__photos[data-v-2c344404]{padding:0}}.empty-content-with-illustration[data-v-2c344404] .empty-content__icon{width:200px;height:200px}.empty-content-with-illustration[data-v-2c344404] .empty-content__icon svg{width:200px;height:200px}.rename-form[data-v-2c344404]{display:flex;flex-direction:row;align-items:center;height:70px;padding:16px}.rename-form input[data-v-2c344404]{width:100%} diff --git a/css/dashboard-Dk7DoScS.chunk.css b/css/dashboard-Dk7DoScS.chunk.css deleted file mode 100644 index af60075d42..0000000000 --- a/css/dashboard-Dk7DoScS.chunk.css +++ /dev/null @@ -1 +0,0 @@ -.on-this-day-dashboard[data-v-4ab77429]{display:flex;flex-direction:column;align-items:center;height:100%;gap:16px}.on-this-day-dashboard .file-container[data-v-4ab77429]{flex-grow:1;border:none} diff --git a/css/photos-dashboard.css b/css/photos-dashboard.css index f68bacec47..d71af3e8e3 100644 --- a/css/photos-dashboard.css +++ b/css/photos-dashboard.css @@ -1,6 +1,6 @@ /* extracted by css-entry-points-plugin */ -@import './dashboard-Dk7DoScS.chunk.css'; -@import './index-BKgSQvuc.chunk.css'; -@import './NcEmptyContent-BC9mI1uc.chunk.css'; -@import './NcCheckboxRadioSwitch-CX3HXCEk-35V8jJy1.chunk.css'; -@import './FileComponent-DB63U6mi.chunk.css'; \ No newline at end of file +@import './dashboard-CKW1KlC8.chunk.css'; +@import './index-DDV9aAWC.chunk.css'; +@import './NcEmptyContent-CUFc_Dds.chunk.css'; +@import './NcCheckboxRadioSwitch-CX3HXCEk-Dyu25sel.chunk.css'; +@import './FileComponent-D2ojNVhV.chunk.css'; \ No newline at end of file diff --git a/css/photos-main.css b/css/photos-main.css index ea5805ad57..3235503c08 100644 --- a/css/photos-main.css +++ b/css/photos-main.css @@ -1,12 +1,12 @@ /* extracted by css-entry-points-plugin */ -@import './main-J25klMHn.chunk.css'; -@import './index-BKgSQvuc.chunk.css'; -@import './video-sO_36FNw.chunk.css'; -@import './NcActionButton-CECxOkhK-Dc3ra1Np.chunk.css'; -@import './NcAvatar-4h0wo9uv-BU6yBQGm.chunk.css'; -@import './NcSelect-CkB50N9T-BigDypkm.chunk.css'; -@import './NcCheckboxRadioSwitch-CX3HXCEk-35V8jJy1.chunk.css'; -@import './NcDateTimePicker-DpgrQHPd.chunk.css'; -@import './PhotosFiltersInput-B5iZrGH_.chunk.css'; -@import './filters-BekTT58-.chunk.css'; -@import './NcAppSettingsSection-Yg4NYCih-BTNc7e8I.chunk.css'; \ No newline at end of file +@import './main-BmiRzVWy.chunk.css'; +@import './index-DDV9aAWC.chunk.css'; +@import './video-BkrHBFpL.chunk.css'; +@import './NcActionButton-CECxOkhK-CG4V9b5b.chunk.css'; +@import './NcAvatar-4h0wo9uv-Dr7yFHRW.chunk.css'; +@import './NcSelect-CkB50N9T-Bw9b5jQ6.chunk.css'; +@import './NcCheckboxRadioSwitch-CX3HXCEk-Dyu25sel.chunk.css'; +@import './NcDateTimePicker-B_OrmVPI.chunk.css'; +@import './PhotosFiltersInput-CNCnqYX1.chunk.css'; +@import './filters-CySE7c_B.chunk.css'; +@import './NcAppSettingsSection-Yg4NYCih-rXmyWTry.chunk.css'; \ No newline at end of file diff --git a/css/photos-public.css b/css/photos-public.css index 87dad0bf03..2c3d8ff87e 100644 --- a/css/photos-public.css +++ b/css/photos-public.css @@ -1,4 +1,4 @@ /* extracted by css-entry-points-plugin */ -@import './public-BqRc5ISL.chunk.css'; -@import './index-BKgSQvuc.chunk.css'; -@import './video-sO_36FNw.chunk.css'; \ No newline at end of file +@import './public-DU8vPjpG.chunk.css'; +@import './index-DDV9aAWC.chunk.css'; +@import './video-BkrHBFpL.chunk.css'; \ No newline at end of file diff --git a/css/public-BqRc5ISL.chunk.css b/css/public-BqRc5ISL.chunk.css deleted file mode 100644 index e87cc2a973..0000000000 --- a/css/public-BqRc5ISL.chunk.css +++ /dev/null @@ -1 +0,0 @@ -.app-content{display:flex;flex-grow:1;flex-direction:column;align-content:space-between}.app-navigation__photos:deep(.app-navigation-entry-icon.icon-photos){background-size:20px} diff --git a/js/photos-dashboard.mjs b/js/photos-dashboard.mjs index 29c3acc64e..0d854d5c0c 100644 --- a/js/photos-dashboard.mjs +++ b/js/photos-dashboard.mjs @@ -1,2 +1,79 @@ -import{t as a,g as e,V as s,c as r,o as n}from"./vue.runtime.esm-DCKfRL7V.chunk.mjs";import{r as i,e as p,a as m,l as d,p as c}from"./index-CUpYykB9.chunk.mjs";import{N as h}from"./NcEmptyContent-C14HhGUQ.chunk.mjs";import{m as l,n as y}from"./icons-BRqI-hCR.chunk.mjs";import{F as u}from"./FileComponent-9oW6MjxP.chunk.mjs";import{g as f}from"./PhotoSearch-BmMVXfNE.chunk.mjs";import"./index-H-n78F4h.chunk.mjs";import"./NcCheckboxRadioSwitch-CX3HXCEk-BZtFu2HT.chunk.mjs";import"./NcDialog-8ipQ69_t-BntQO4mh.chunk.mjs";const g={name:"DashboardOnThisDay",components:{FileComponent:u,NcButton:p,NcLoadingIcon:i,NcEmptyContent:h,ImageOutlineIcon:l},data(){return{loading:!0,items:[]}},computed:{moreUrl(){return e("/apps/photos/thisday")}},async created(){try{this.items=await f({firstResult:0,nbResults:1,mimesType:m,onThisDay:!0})}catch(t){d.error("Failed to load on this day pictures",{error:t})}finally{this.loading=!1}},methods:{t:a}};var w=function(){var t=this,o=t._self._c;return o("div",{staticClass:"on-this-day-dashboard"},[t.loading?o("NcLoadingIcon",{attrs:{size:48}}):t.items.length===0?o("NcEmptyContent",{attrs:{name:t.t("photos","No picture for this day"),description:t.t("photos","Picture taken on this day will show up here.")},scopedSlots:t._u([{key:"icon",fn:function(){return[o("ImageOutlineIcon")]},proxy:!0}])}):[o("FileComponent",{staticClass:"on-this-day-dashboard__file",attrs:{file:t.items[0],"allow-selection":!1}}),o("NcButton",{attrs:{href:t.moreUrl}},[t._v(" "+t._s(t.t("photos","More photos from this day"))+" ")])]],2)},C=[],N=y(g,w,C,!1,null,"4ab77429");const _=N.exports;s.prototype.t=a,s.prototype.n=r,window.addEventListener("DOMContentLoaded",()=>{window.OCA.Dashboard.register("photos-onthisday",t=>{n.PhotosOnThisDay=new s({el:t,store:c,render:o=>o(_)})})}); +const appName = "photos"; +const appVersion = "5.0.2"; +import { t as translate, g as generateUrl, V as Vue, c as translatePlural, o as global } from "./vue.runtime.esm-D0MRZEe4.chunk.mjs"; +import { r as NcLoadingIcon, e as NcButton, a as allMimes, l as logger, p as photosStore } from "./index-CZNqUxm0.chunk.mjs"; +import { N as NcEmptyContent } from "./NcEmptyContent-BBz98Y_d.chunk.mjs"; +import { m as ImageOutlineIcon, n as normalizeComponent } from "./icons-DpGfY1yM.chunk.mjs"; +import { F as FileComponent } from "./FileComponent-B5RazorU.chunk.mjs"; +import { g as getPhotos } from "./PhotoSearch-Bwow9NGf.chunk.mjs"; +import "./index-CEGJzzBP.chunk.mjs"; +import "./NcCheckboxRadioSwitch-CX3HXCEk-DHCH3k5i.chunk.mjs"; +import "./NcDialog-8ipQ69_t-Bi5MKXbp.chunk.mjs"; +const _sfc_main = { + name: "DashboardOnThisDay", + components: { + FileComponent, + NcButton, + NcLoadingIcon, + NcEmptyContent, + ImageOutlineIcon + }, + data() { + return { + loading: true, + items: [] + }; + }, + computed: { + moreUrl() { + return generateUrl("/apps/photos/thisday"); + } + }, + async created() { + try { + this.items = await getPhotos({ + firstResult: 0, + nbResults: 1, + mimesType: allMimes, + onThisDay: true + }); + } catch (error) { + logger.error("Failed to load on this day pictures", { error }); + } finally { + this.loading = false; + } + }, + methods: { + t: translate + } +}; +var _sfc_render = function render() { + var _vm = this, _c = _vm._self._c; + return _c("div", { staticClass: "on-this-day-dashboard" }, [_vm.loading ? _c("NcLoadingIcon", { attrs: { "size": 48 } }) : _vm.items.length === 0 ? _c("NcEmptyContent", { attrs: { "name": _vm.t("photos", "No picture for this day"), "description": _vm.t("photos", "Picture taken on this day will show up here.") }, scopedSlots: _vm._u([{ key: "icon", fn: function() { + return [_c("ImageOutlineIcon")]; + }, proxy: true }]) }) : [_c("FileComponent", { staticClass: "on-this-day-dashboard__file", attrs: { "file": _vm.items[0], "allow-selection": false } }), _c("NcButton", { attrs: { "href": _vm.moreUrl } }, [_vm._v(" " + _vm._s(_vm.t("photos", "More photos from this day")) + " ")])]], 2); +}; +var _sfc_staticRenderFns = []; +_sfc_render._withStripped = true; +var __component__ = /* @__PURE__ */ normalizeComponent( + _sfc_main, + _sfc_render, + _sfc_staticRenderFns, + false, + null, + "f34a5053" +); +__component__.options.__file = "/var/www/html/customapps/photos/src/components/Dashboard/DashboardOnThisDay.vue"; +const DashboardOnThisDay = __component__.exports; +Vue.prototype.t = translate; +Vue.prototype.n = translatePlural; +window.addEventListener("DOMContentLoaded", () => { + window.OCA.Dashboard.register("photos-onthisday", (el) => { + global.PhotosOnThisDay = new Vue({ + el, + store: photosStore, + render: (h) => h(DashboardOnThisDay) + }); + }); +}); //# sourceMappingURL=photos-dashboard.mjs.map diff --git a/js/photos-dashboard.mjs.license b/js/photos-dashboard.mjs.license deleted file mode 100644 index c25829ba48..0000000000 --- a/js/photos-dashboard.mjs.license +++ /dev/null @@ -1,7 +0,0 @@ -SPDX-License-Identifier: AGPL-3.0-or-later -SPDX-FileCopyrightText: John Molakvoæ - -This file is generated from multiple sources. Included packages: -- photos - - version: 5.0.0-dev.1 - - license: AGPL-3.0-or-later diff --git a/js/photos-dashboard.mjs.map b/js/photos-dashboard.mjs.map index 5395d1dd79..8c8f8d2834 100644 --- a/js/photos-dashboard.mjs.map +++ b/js/photos-dashboard.mjs.map @@ -1 +1 @@ -{"version":3,"file":"photos-dashboard.mjs","sources":["../src/components/Dashboard/DashboardOnThisDay.vue","../src/dashboard.ts"],"sourcesContent":["\n\n\n\n\n\n","/**\n * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport { translate, translatePlural } from '@nextcloud/l10n'\nimport Vue from 'vue'\nimport DashboardOnThisDay from './components/Dashboard/DashboardOnThisDay.vue'\nimport store from './store/index.js'\n\nVue.prototype.t = translate\nVue.prototype.n = translatePlural\n\nwindow.addEventListener('DOMContentLoaded', () => {\n\twindow.OCA.Dashboard.register('photos-onthisday', (el) => {\n\t\tglobal.PhotosOnThisDay = new Vue({\n\t\t\tel,\n\t\t\tstore,\n\t\t\trender: (h) => h(DashboardOnThisDay),\n\t\t})\n\t})\n})\n"],"names":["_sfc_main","FileComponent","NcButton","NcLoadingIcon","NcEmptyContent","ImageOutlineIcon","generateUrl","getPhotos","allMimes","error","logger","t","Vue","translate","translatePlural","el","global","store","h","DashboardOnThisDay"],"mappings":"wgBAuCA,MAAAA,EAAA,CACA,KAAA,qBACA,WAAA,CACA,cAAAC,EACA,SAAAC,EACA,cAAAC,EACA,eAAAC,EACA,iBAAAC,CAAA,EAGA,MAAA,CACA,MAAA,CACA,QAAA,GACA,MAAA,CAAA,CAAA,CAEA,EAEA,SAAA,CACA,SAAA,CACA,OAAAC,EAAA,sBAAA,CACA,CAAA,EAGA,MAAA,SAAA,CACA,GAAA,CACA,KAAA,MAAA,MAAAC,EAAA,CACA,YAAA,EACA,UAAA,EACA,UAAAC,EACA,UAAA,EAAA,CACA,CACA,OAAAC,EAAA,CACAC,EAAA,MAAA,sCAAA,CAAA,MAAAD,CAAA,CAAA,CACA,QAAA,CACA,KAAA,QAAA,EACA,CACA,EAEA,QAAA,CAAA,EACAE,CAAA,CAEA,6pBCtEAC,EAAI,UAAU,EAAIC,EAClBD,EAAI,UAAU,EAAIE,EAElB,OAAO,iBAAiB,mBAAoB,IAAM,CACjD,OAAO,IAAI,UAAU,SAAS,mBAAqBC,GAAO,CACzDC,EAAO,gBAAkB,IAAIJ,EAAI,CAChC,GAAAG,EAAA,MACAE,EACA,OAASC,GAAMA,EAAEC,CAAkB,CAAA,CACnC,CACF,CAAC,CACF,CAAC"} \ No newline at end of file +{"version":3,"file":"photos-dashboard.mjs","sources":["../src/components/Dashboard/DashboardOnThisDay.vue","../src/dashboard.ts"],"sourcesContent":["\n\n\n\n\n\n","/**\n * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport { translate, translatePlural } from '@nextcloud/l10n'\nimport Vue from 'vue'\nimport DashboardOnThisDay from './components/Dashboard/DashboardOnThisDay.vue'\nimport store from './store/index.js'\n\nVue.prototype.t = translate\nVue.prototype.n = translatePlural\n\nwindow.addEventListener('DOMContentLoaded', () => {\n\twindow.OCA.Dashboard.register('photos-onthisday', (el) => {\n\t\tglobal.PhotosOnThisDay = new Vue({\n\t\t\tel,\n\t\t\tstore,\n\t\t\trender: (h) => h(DashboardOnThisDay),\n\t\t})\n\t})\n})\n"],"names":["t","store"],"mappings":";;;;;;;;;;;AAuCA,MAAA,YAAA;AAAA,EACA,MAAA;AAAA,EACA,YAAA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAAA,EAGA,OAAA;AACA,WAAA;AAAA,MACA,SAAA;AAAA,MACA,OAAA,CAAA;AAAA,IAAA;AAAA,EAEA;AAAA,EAEA,UAAA;AAAA,IACA,UAAA;AACA,aAAA,YAAA,sBAAA;AAAA,IACA;AAAA,EAAA;AAAA,EAGA,MAAA,UAAA;AACA,QAAA;AACA,WAAA,QAAA,MAAA,UAAA;AAAA,QACA,aAAA;AAAA,QACA,WAAA;AAAA,QACA,WAAA;AAAA,QACA,WAAA;AAAA,MAAA,CACA;AAAA,IACA,SAAA,OAAA;AACA,aAAA,MAAA,uCAAA,EAAA,MAAA,CAAA;AAAA,IACA,UAAA;AACA,WAAA,UAAA;AAAA,IACA;AAAA,EACA;AAAA,EAEA,SAAA;AAAA,IAAA,GACAA;AAAAA,EAAA;AAEA;;;;;;;;;;;;;;;;;;;ACtEA,IAAI,UAAU,IAAI;AAClB,IAAI,UAAU,IAAI;AAElB,OAAO,iBAAiB,oBAAoB,MAAM;AACjD,SAAO,IAAI,UAAU,SAAS,oBAAoB,CAAC,OAAO;AACzD,WAAO,kBAAkB,IAAI,IAAI;AAAA,MAChC;AAAA,MAAA,OACAC;AAAAA,MACA,QAAQ,CAAC,MAAM,EAAE,kBAAkB;AAAA,IAAA,CACnC;AAAA,EACF,CAAC;AACF,CAAC;"} \ No newline at end of file diff --git a/js/photos-main.mjs b/js/photos-main.mjs index ed768defc2..e902c79778 100644 --- a/js/photos-main.mjs +++ b/js/photos-main.mjs @@ -1,2 +1,584 @@ -import{V as s,K as d,u as P,s as L,d as _,a5 as M,D as O,h as T,J as m,E as z,a4 as $,t as a,g as u,l as n,c as x,e as r}from"./vue.runtime.esm-DCKfRL7V.chunk.mjs";import{P as E,u as B,s as V,a as W,c as D}from"./filters-Cq5hykR3.chunk.mjs";import{a as U,N as H,b as R,f as K,m as G,h as j,v as q,i as J,s as Y,c as Q,r as v}from"./video-DpTSoI-p.chunk.mjs";import{n as g,ae as X,H as N,af as Z,ag as tt,e as S,l as i,Y as h,p as f}from"./index-CUpYykB9.chunk.mjs";import{N as et,u as ot,A as at,a as st,b as it}from"./NcAppSettingsSection-Yg4NYCih-Ax3cNENC.chunk.mjs";import{u as nt}from"./useHotKey-Cex-BQWj.chunk.mjs";import{n as p,B as C,H as rt,M as pt,J as lt,K as ct,L as dt,y as ut,N as ht,T as gt,O as mt,f as vt,g as ft,S as yt,Q as _t,m as Nt,R as St,d as Ct,U as bt,W as Ft,X as At,Y as kt,Z as wt,_ as It,$ as Pt,a0 as Lt,a1 as Mt,i as Ot,a2 as Tt}from"./icons-BRqI-hCR.chunk.mjs";import{P as zt,a as $t}from"./PhotosFiltersInput-6gHsa828.chunk.mjs";import{N as xt}from"./NcNoteCard-CtA1U4Ik.chunk.mjs";import{N as Et}from"./NcCheckboxRadioSwitch-CX3HXCEk-BZtFu2HT.chunk.mjs";import{g as Bt}from"./index-BDGwHs7O.chunk.mjs";import{d as Vt}from"./index-BANVoKjP.chunk.mjs";import"./index-H-n78F4h.chunk.mjs";import"./preload-helper-DxYC2qmj.chunk.mjs";import"./NcSelect-CkB50N9T-CVeroTeG.chunk.mjs";import"./NcAvatar-4h0wo9uv-CmUeGzZH.chunk.mjs";import"./NcActionButton-CECxOkhK-1r8FTTFv.chunk.mjs";import"./NcDialog-8ipQ69_t-BntQO4mh.chunk.mjs";import"./NcDateTimePicker-BLKS9gcT.chunk.mjs";import"./collectionFetcher-C0KusW9b.chunk.mjs";const Wt={name:"NcAppNavigationList"};var Dt=function(){var t=this,e=t._self._c;return e("ul",{staticClass:"app-navigation-list"},[t._t("default")],2)},Ut=[],Ht=g(Wt,Dt,Ut,!1,null,"058e6060");const Rt=Ht.exports,Kt={name:"NcAppNavigation",components:{NcAppNavigationList:Rt,NcAppNavigationToggle:et},inject:{setHasAppNavigation:{default:()=>()=>s.util.warn("NcAppNavigation is not mounted inside NcContent, this is probably an error."),from:"NcContent:setHasAppNavigation"}},props:{ariaLabel:{type:String,default:""},ariaLabelledby:{type:String,default:""}},setup(){return{isMobile:U()}},data(){return{open:!this.isMobile,focusTrap:null}},watch:{isMobile(){this.open=!this.isMobile,this.toggleFocusTrap()},open(){this.toggleFocusTrap()}},mounted(){this.setHasAppNavigation(!0),L("toggle-navigation",this.toggleNavigationByEventBus),d("navigation-toggled",{open:this.open}),this.focusTrap=Z(this.$refs.appNavigationContainer,{allowOutsideClick:!0,fallbackFocus:this.$refs.appNavigationContainer,trapStack:tt(),escapeDeactivates:!1}),this.toggleFocusTrap(),nt("n",this.onKeyDown,{prevent:!0,stop:!0})},unmounted(){this.setHasAppNavigation(!1),P("toggle-navigation",this.toggleNavigationByEventBus),this.focusTrap.deactivate()},methods:{async toggleNavigation(t){if(this.open===t){d("navigation-toggled",{open:this.open});return}this.open=typeof t>"u"?!this.open:t;const e=getComputedStyle(document.body),o=parseInt(e.getPropertyValue("--animation-quick"))||100;this.open&&(await this.$nextTick(),this.focusFirstElement()),setTimeout(()=>{d("navigation-toggled",{open:this.open})},1.5*o)},toggleNavigationByEventBus({open:t}){this.toggleNavigation(t)},toggleFocusTrap(){this.isMobile&&this.open?this.focusTrap.activate():this.focusTrap.deactivate()},handleEsc(){this.isMobile&&this.open&&this.toggleNavigation(!1)},focusFirstElement(){const t=X(this.$refs.appNavigationContainer)[0];t&&(t.focus(),N.debug("Focusing first element in the navigation",{element:t}))},onKeyDown(t){if(t.key==="n"){if(!this.open){this.toggleNavigation(!0);return}this.isFocusWithinNavigation()&&this.toggleNavigation(!1)}},isFocusWithinNavigation(){const t=document.activeElement;return this.$refs.appNavigationContainer?.contains(t)}}};var Gt=function(){var t=this,e=t._self._c;return e("div",{ref:"appNavigationContainer",staticClass:"app-navigation",class:{"app-navigation--close":!t.open}},[e("nav",{staticClass:"app-navigation__content",attrs:{id:"app-navigation-vue","aria-hidden":t.open?"false":"true","aria-label":t.ariaLabel||void 0,"aria-labelledby":t.ariaLabelledby||void 0,inert:!t.open||void 0},on:{keydown:function(o){return!o.type.indexOf("key")&&t._k(o.keyCode,"esc",27,o.key,["Esc","Escape"])?null:t.handleEsc.apply(null,arguments)}}},[e("div",{staticClass:"app-navigation__search"},[t._t("search")],2),e("div",{staticClass:"app-navigation__body",class:{"app-navigation__body--no-list":!t.$scopedSlots.list}},[t._t("default")],2),t.$scopedSlots.list?e("NcAppNavigationList",{staticClass:"app-navigation__list"},[t._t("list")],2):t._e(),t._t("footer")],2),e("NcAppNavigationToggle",{attrs:{open:t.open},on:{"update:open":t.toggleNavigation}})],1)},jt=[],qt=g(Kt,Gt,jt,!1,null,"119f2aad");const Jt=qt.exports,Yt=_({__name:"NcAppSettingsSection",props:{name:null,description:null,id:null,order:null},setup(t){const e=t,o=M(),{registerSection:l,unregisterSection:c}=ot(),b=O(at),F=T(()=>"settings-section_"+e.id);return m(()=>e.id,()=>{/^[a-z0-9\-_]+$/.test(e.id)||N.warn(`Invalid id prop: ${e.id}. Only alphanumeric, dash and underscore are allowed.`)},{immediate:!0}),m([()=>e.id,()=>e.name,()=>e.order],([A,k,w],[I,,])=>{c(I),l(A,k,w,o?.icon?.())}),z(()=>{l(e.id,e.name,e.order,o?.icon?.())}),$(()=>{c(e.id)}),{__sfc:!0,props:e,slots:o,registerSection:l,unregisterSection:c,legacy:b,htmlId:F}}});var Qt=function(){var t=this,e=t._self._c,o=t._self._setupProxy;return e("section",{staticClass:"app-settings-section",class:{"app-settings-section__legacy":o.legacy},attrs:{id:o.htmlId,"aria-labelledby":`${o.htmlId}--label`}},[e("h3",{staticClass:"app-settings-section__name",attrs:{id:`${o.htmlId}--label`}},[t._v(" "+t._s(t.name)+" ")]),e("div",{staticClass:"app-settings-section__description"},[t._v(" "+t._s(t.description)+" ")]),e("div",{staticClass:"app-settings-section__content"},[t._t("default")],2),t._e()],2)},Xt=[],Zt=g(Yt,Qt,Xt,!1,null,"06cd755d");const te=Zt.exports,ee={name:"CroppedLayoutSettings",components:{NcCheckboxRadioSwitch:Et},computed:{croppedLayout(){return this.$store.state.userConfig.croppedLayout}},methods:{updateSetting(t){this.$store.dispatch("updateUserConfig",{key:"croppedLayout",value:t})}}};var oe=function(){var t=this,e=t._self._c;return e("NcCheckboxRadioSwitch",{attrs:{"model-value":t.croppedLayout,type:"switch"},on:{"update:model-value":t.updateSetting}},[t._v(" "+t._s(t.t("photos","Enable squared photos view"))+" ")])},ae=[],se=p(ee,oe,ae,!1,null,null);const ie=se.exports,ne=_({name:"PhotosUploadLocationSettings",components:{NcButton:S,FolderOutline:C},emits:["folders-update"],data(){return{HomeOutline:rt}},computed:{photosLocation(){return this.$store.state.userConfig.photosLocation},photosSourceFolders(){return this.$store.state.userConfig.photosSourceFolders},isPhotosLocationInphotosSourceFolders(){const t=this.photosLocation.replace(/\/+$/,"");return this.photosSourceFolders.some(e=>{const o=e.replace(/\/+$/,"");return t===o||t.startsWith(o+"/")})}},methods:{debounceSelectPhotosFolder:Vt(function(){this.selectPhotosFolder()}),async selectPhotosFolder(){const t=await this.openFilePicker(a("photos","Select the default upload location for your media"));this.updatePhotosFolder(t)},async openFilePicker(t){return Bt(t).setMultiSelect(!1).addMimeTypeFilter("httpd/unix-directory").allowDirectories().startAt(this.photosLocation).addButton({label:a("photos","Pick folder"),variant:"primary",callback:e=>i.debug("Picked",{nodes:e})}).build().pick()},updatePhotosFolder(t){this.$store.dispatch("updateUserConfig",{key:"photosLocation",value:t}),this.$emit("folders-update",this.isPhotosLocationInphotosSourceFolders)},t:a}});var re=function(){var t=this,e=t._self._c;return t._self._setupProxy,e("div",{staticClass:"photos-location"},[e("NcButton",{attrs:{"aria-label":t.t("photos","Choose default Photos upload and Albums location"),variant:"tertiary"},on:{click:t.debounceSelectPhotosFolder},scopedSlots:t._u([{key:"icon",fn:function(){return[e("FolderOutline",{attrs:{size:20}})]},proxy:!0}])},[t._v(" "+t._s(t.photosLocation)+" ")])],1)},pe=[],le=p(ne,re,pe,!1,null,"cc633454");const ce=le.exports,de={name:"SettingsDialog",components:{NcAppSettingsDialog:st,NcAppSettingsSection:te,NcNoteCard:xt,CroppedLayoutSettings:ie,PhotosSourceLocationsSettings:E,PhotosUploadLocationSettings:ce},props:{open:{type:Boolean,default:!1}},data(){return{showFoldersWarning:!1}},computed:{photosLocation(){return this.$store.state.userConfig.photosLocation},photosSourceFolders(){return this.$store.state.userConfig.photosSourceFolders},isPhotosLocationInphotosSourceFolders(){const t=this.photosLocation.replace(/\/+$/,"");return this.photosSourceFolders.some(e=>{const o=e.replace(/\/+$/,"");return t===o||t.startsWith(o+"/")})}},methods:{onClose(){this.$emit("update:open",!1)},handleFoldersUpdate(t){this.showFoldersWarning=!t},t:a}};var ue=function(){var t=this,e=t._self._c;return e("NcAppSettingsDialog",{attrs:{open:t.open,"show-navigation":!1,name:t.t("photos","Photos settings"),"no-version":!0},on:{"update:open":t.onClose}},[e("NcAppSettingsSection",{attrs:{id:"layout-settings",name:t.t("photos","View")}},[e("CroppedLayoutSettings")],1),e("NcAppSettingsSection",{attrs:{id:"source-directories-settings",name:t.t("photos","Media folders")}},[e("div",{staticClass:"setting-section-subline"},[t._v(" "+t._s(t.t("photos","Choose the folders from where photos and videos are shown."))+" ")]),e("PhotosSourceLocationsSettings",{on:{"folders-update":t.handleFoldersUpdate}})],1),e("NcAppSettingsSection",{attrs:{id:"upload-directory-settings",name:t.t("photos","Upload folder")}},[e("div",{staticClass:"setting-section-subline"},[t._v(" "+t._s(t.t("photos","Choose the folder where photos and albums are uploaded to."))+" ")]),e("PhotosUploadLocationSettings",{on:{"folders-update":t.handleFoldersUpdate}})],1),t.showFoldersWarning||!t.isPhotosLocationInphotosSourceFolders?e("NcNoteCard",{staticClass:"notecard",attrs:{type:"warning","show-alert":!0,heading:t.t("photos","Upload folder not part of media folder")}},[t._v(" "+t._s(t.t("photos","Uploaded items will not appear in the Photos & Videos section."))+" ")]):t._e()],1)},he=[],ge=p(de,ue,he,!1,null,null);const me=ge.exports,y=h("photos","appStoreEnabled",!1),ve={name:"PhotosApp",components:{AccountBoxMultiple:Tt,AccountBoxMultipleOutline:Ot,CogOutline:Mt,CalendarToday:Lt,CalendarTodayOutline:Pt,Camera:It,CameraOutline:wt,AccountGroup:kt,AccountGroupOutline:At,Folder:Ft,FolderOutline:C,ImageMultiple:bt,ImageMultipleOutline:Ct,ImageIcon:St,ImageOutline:Nt,ShareVariant:_t,ShareVariantOutline:yt,Star:ft,StarOutline:vt,Tag:mt,TagOutline:gt,VideoIcon:ht,VideoOutline:ut,MapIcon:dt,MapOutline:ct,MapMarker:lt,MapMarkerOutline:pt,NcAppContent:R,NcAppNavigation:Jt,NcAppNavigationItem:it,NcButton:S,NcContent:H,SettingsDialog:me,PhotosFiltersInput:$t,PhotosFiltersDisplay:zt},setup(){const t=B(),{selectedFilters:e}=V(t);return{selectedFilters:e}},data(){return{svgplaceholder:Y,imgplaceholder:J,videoplaceholder:q,areTagsInstalled:j,showLocationMenuEntry:n()===null?!1:n().isAdmin&&y||G,showPeopleMenuEntry:n()===null?!1:n().isAdmin&&h("photos","showPeopleMenuEntry",!0)&&y||K,openedSettings:!1}},computed:{isTimelineView(){return["all_media","photos","videos"].includes(this.$store.state.route.name||"")}},async beforeMount(){const t=h("photos","nomedia-paths",[]);this.$store.dispatch("setNomediaPaths",t),i.debug("Known .nomedia and .noimage paths",{files:t}),"serviceWorker"in navigator?window.addEventListener("load",()=>{navigator.serviceWorker.register(u("/apps/photos/service-worker.js",{},{noRewrite:!0}),{scope:u("/apps/photos")}).then(e=>{i.debug("SW registered: ",{registration:e})}).catch(e=>{i.error("SW registration failed: ",{registrationError:e})})}):i.debug("Service Worker is not enabled on this browser.")},beforeDestroy(){window.removeEventListener("load",()=>{navigator.serviceWorker.register(u("/apps/photos/service-worker.js",{},{noRewrite:!0}))})},methods:{showSettings(){this.openedSettings=!0},selectFilter(t){this.selectedFilters[t.filterId].push(t.value)},deselectFilter(t){const e=this.selectedFilters[t.filterId].indexOf(t.value);e!==-1&&this.selectedFilters[t.filterId].splice(e,1)},t:a}};var fe=function(){var t=this,e=t._self._c;return e("NcContent",{attrs:{"app-name":"photos"}},[e("NcAppNavigation",{attrs:{"aria-label":t.t("photos","Photos")},scopedSlots:t._u([t.isTimelineView?{key:"search",fn:function(){return[e("PhotosFiltersInput",{attrs:{"selected-filters":t.selectedFilters},on:{"select-filter":t.selectFilter}}),e("PhotosFiltersDisplay",{attrs:{"selected-filters":t.selectedFilters},on:{"deselect-filter":t.deselectFilter}})]},proxy:!0}:null,{key:"list",fn:function(){return[e("NcAppNavigationItem",{staticClass:"app-navigation__all_media",attrs:{to:{name:"all_media"},name:t.t("photos","All media"),"data-id-app-nav-item":"all-media",exact:""},scopedSlots:t._u([{key:"icon",fn:function({active:o}){return[o?e("ImageIcon",{attrs:{size:20}}):e("ImageOutline",{attrs:{size:20}})]}}])}),e("NcAppNavigationItem",{attrs:{to:"/photos",name:t.t("photos","Photos"),"data-id-app-nav-item":"photos"},scopedSlots:t._u([{key:"icon",fn:function({active:o}){return[o?e("Camera",{attrs:{size:20}}):e("CameraOutline",{attrs:{size:20}})]}}])}),e("NcAppNavigationItem",{attrs:{to:"/videos",name:t.t("photos","Videos"),"data-id-app-nav-item":"videos"},scopedSlots:t._u([{key:"icon",fn:function({active:o}){return[o?e("VideoIcon",{attrs:{size:20}}):e("VideoOutline",{attrs:{size:20}})]}}])}),e("NcAppNavigationItem",{attrs:{to:{name:"albums"},name:t.t("photos","Albums"),"data-id-app-nav-item":"albums"},scopedSlots:t._u([{key:"icon",fn:function({active:o}){return[o?e("ImageMultiple",{attrs:{size:20}}):e("ImageMultipleOutline",{attrs:{size:20}})]}}])}),e("NcAppNavigationItem",{attrs:{to:{name:"sharedAlbums"},name:t.t("photos","Collaborative albums"),"data-id-app-nav-item":"sharedalbums"},scopedSlots:t._u([{key:"icon",fn:function({active:o}){return[o?e("AccountGroup",{attrs:{size:20}}):e("AccountGroupOutline",{attrs:{size:20}})]}}])}),t.showPeopleMenuEntry?e("NcAppNavigationItem",{attrs:{to:{name:"faces"},name:t.t("photos","People"),"data-id-app-nav-item":"faces"},scopedSlots:t._u([{key:"icon",fn:function({active:o}){return[o?e("AccountBoxMultiple",{attrs:{size:20}}):e("AccountBoxMultipleOutline",{attrs:{size:20}})]}}],null,!1,3295904880)}):t._e(),e("NcAppNavigationItem",{attrs:{to:{name:"folders"},name:t.t("photos","Folders"),"data-id-app-nav-item":"folders"},scopedSlots:t._u([{key:"icon",fn:function({active:o}){return[o?e("Folder",{attrs:{size:20}}):e("FolderOutline",{attrs:{size:20}})]}}])}),e("NcAppNavigationItem",{attrs:{to:"/favorites",name:t.t("photos","Favorites"),"data-id-app-nav-item":"favorites"},scopedSlots:t._u([{key:"icon",fn:function({active:o}){return[o?e("Star",{attrs:{size:20}}):e("StarOutline",{attrs:{size:20}})]}}])}),e("NcAppNavigationItem",{attrs:{to:{name:"thisday"},name:t.t("photos","On this day"),"data-id-app-nav-item":"this-day"},scopedSlots:t._u([{key:"icon",fn:function({active:o}){return[o?e("CalendarToday",{attrs:{size:20}}):e("CalendarTodayOutline",{attrs:{size:20}})]}}])}),e("NcAppNavigationItem",{attrs:{to:{name:"shared"},name:t.t("photos","Shared with you"),"data-id-app-nav-item":"shared"},scopedSlots:t._u([{key:"icon",fn:function({active:o}){return[o?e("ShareVariant",{attrs:{size:20}}):e("ShareVariantOutline",{attrs:{size:20}})]}}])}),t.areTagsInstalled?e("NcAppNavigationItem",{attrs:{to:{name:"tags"},name:t.t("photos","Tags"),"data-id-app-nav-item":"tags"},scopedSlots:t._u([{key:"icon",fn:function({active:o}){return[o?e("Tag",{attrs:{size:20}}):e("TagOutline",{attrs:{size:20}})]}}],null,!1,346180464)}):t._e(),e("NcAppNavigationItem",{attrs:{to:{name:"places"},name:t.t("photos","Places"),"data-id-app-nav-item":"places"},scopedSlots:t._u([{key:"icon",fn:function({active:o}){return[o?e("MapMarker",{attrs:{size:20}}):e("MapMarkerOutline",{attrs:{size:20}})]}}])}),t.showLocationMenuEntry?e("NcAppNavigationItem",{attrs:{to:{name:"maps"},name:t.t("photos","Map"),"data-id-app-nav-item":"maps"},scopedSlots:t._u([{key:"icon",fn:function({active:o}){return[o?e("MapIcon",{attrs:{size:20}}):e("MapOutline",{attrs:{size:20}})]}}],null,!1,257739259)}):t._e()]},proxy:!0},{key:"footer",fn:function(){return[e("div",{staticClass:"app-navigation__footer"},[e("NcButton",{attrs:{variant:"tertiary",alignment:"start",wide:""},on:{click:t.showSettings},scopedSlots:t._u([{key:"icon",fn:function(){return[e("CogOutline",{attrs:{size:20}})]},proxy:!0}])},[t._v(" "+t._s(t.t("photos","Photos settings"))+" ")])],1)]},proxy:!0}],null,!0)}),e("NcAppContent",[e("RouterView"),e("span",{staticClass:"hidden-visually",attrs:{role:"none"},domProps:{innerHTML:t._s(t.svgplaceholder)}}),e("span",{staticClass:"hidden-visually",attrs:{role:"none"},domProps:{innerHTML:t._s(t.imgplaceholder)}}),e("span",{staticClass:"hidden-visually",attrs:{role:"none"},domProps:{innerHTML:t._s(t.videoplaceholder)}})],1),e("SettingsDialog",{attrs:{open:t.openedSettings},on:{"update:open":function(o){t.openedSettings=o}}})],1)},ye=[],_e=p(ve,fe,ye,!1,null,null);const Ne=_e.exports;Q.sync(f,v),s.prototype.t=a,s.prototype.n=x,r("nc:metadata-photos-size"),r("nc:metadata-files-live-photo"),r("nc:metadata-blurhash"),r("nc:metadata-photos-original_date_time"),s.use(W),new s({el:"#content",name:"PhotosRoot",router:v,store:f,pinia:D(),render:t=>t(Ne)}); +const appName = "photos"; +const appVersion = "5.0.2"; +import { V as Vue, K as emit, u as unsubscribe, s as subscribe, d as defineComponent, a6 as useSlots, h as computed, J as watch, E as onMounted, a5 as onBeforeUnmount, D as inject, t as translate, g as generateUrl, l as getCurrentUser, c as translatePlural, e as registerDavProperty } from "./vue.runtime.esm-D0MRZEe4.chunk.mjs"; +import { P as PhotosSourceLocationsSettings, u as useFilterStore, s as storeToRefs, a as PiniaVuePlugin, c as createPinia } from "./filters-4F1cMrc1.chunk.mjs"; +import { a as useIsMobile, N as NcContent, b as NcAppContent, f as recognize, m as maps, h as systemtags, v as videoplaceholder, i as imgplaceholder, s as svgplaceholder, c as vuexRouterSyncExports, r as router } from "./video-Bg0FISQX.chunk.mjs"; +import { n as normalizeComponent, ae as tabbable, H as logger, af as createFocusTrap, ag as getTrapStack, e as NcButton, l as logger$1, Y as loadState, p as photosStore } from "./index-CZNqUxm0.chunk.mjs"; +import { N as NcAppNavigationToggle, u as useAppSettingsDialog, A as APP_SETTINGS_LEGACY_DESIGN_KEY, a as NcAppSettingsDialog, b as NcAppNavigationItem } from "./NcAppSettingsSection-Yg4NYCih-B-Ob8j-P.chunk.mjs"; +import { u as useHotKey } from "./useHotKey-rub5T6dB.chunk.mjs"; +import { n as normalizeComponent$1, B as FolderOutline, H as HomeOutline, M as MapMarkerOutline, J as MapMarker, K as MapOutline, L as MapIcon, y as VideoOutline, N as VideoIcon, T as TagOutline, O as Tag, f as StarOutline, g as Star, S as ShareVariantOutline, Q as ShareVariant, m as ImageOutlineIcon, R as ImageIcon, d as ImageMultipleOutline, U as ImageMultiple, W as Folder, X as AccountGroupOutline, Y as AccountGroup, Z as CameraOutline, _ as Camera, $ as CalendarTodayOutline, a0 as CalendarToday, a1 as CogOutline, i as AccountBoxMultipleOutline, a2 as AccountBoxMultiple } from "./icons-DpGfY1yM.chunk.mjs"; +import { P as PhotosFiltersDisplay, a as PhotosFiltersInput } from "./PhotosFiltersInput-Ctx55noT.chunk.mjs"; +import { N as NcNoteCard } from "./NcNoteCard-BR26BEMK.chunk.mjs"; +import { N as NcCheckboxRadioSwitch } from "./NcCheckboxRadioSwitch-CX3HXCEk-DHCH3k5i.chunk.mjs"; +import { g as getFilePickerBuilder } from "./index-BkEPhjki.chunk.mjs"; +import { d as debounce } from "./index-DSExQq_6.chunk.mjs"; +import "./index-CEGJzzBP.chunk.mjs"; +import "./preload-helper-BH8-nKqv.chunk.mjs"; +import "./NcSelect-CkB50N9T-CC8Q3Hom.chunk.mjs"; +import "./NcAvatar-4h0wo9uv-5FWb6QWu.chunk.mjs"; +import "./NcActionButton-CECxOkhK-CHz3ABOK.chunk.mjs"; +import "./NcDialog-8ipQ69_t-Bi5MKXbp.chunk.mjs"; +import "./NcDateTimePicker-DGwWKLC1.chunk.mjs"; +import "./collectionFetcher-yKLM4qYg.chunk.mjs"; +const _sfc_main$6 = { + name: "NcAppNavigationList" +}; +var _sfc_render$6 = function render() { + var _vm = this, _c = _vm._self._c; + return _c("ul", { staticClass: "app-navigation-list" }, [_vm._t("default")], 2); +}; +var _sfc_staticRenderFns$6 = []; +var __component__$6 = /* @__PURE__ */ normalizeComponent( + _sfc_main$6, + _sfc_render$6, + _sfc_staticRenderFns$6, + false, + null, + "058e6060" +); +const NcAppNavigationList = __component__$6.exports; +const _sfc_main$5 = { + name: "NcAppNavigation", + components: { + NcAppNavigationList, + NcAppNavigationToggle + }, + // Injected from NcContent + inject: { + setHasAppNavigation: { + default: () => () => Vue.util.warn("NcAppNavigation is not mounted inside NcContent, this is probably an error."), + from: "NcContent:setHasAppNavigation" + } + }, + props: { + /** + * The aria label to describe the navigation + */ + ariaLabel: { + type: String, + default: "" + }, + /** + * aria-labelledby attribute to describe the navigation + */ + ariaLabelledby: { + type: String, + default: "" + } + }, + setup() { + return { + isMobile: useIsMobile() + }; + }, + data() { + return { + open: !this.isMobile, + focusTrap: null + }; + }, + watch: { + isMobile() { + this.open = !this.isMobile; + this.toggleFocusTrap(); + }, + open() { + this.toggleFocusTrap(); + } + }, + mounted() { + this.setHasAppNavigation(true); + subscribe("toggle-navigation", this.toggleNavigationByEventBus); + emit("navigation-toggled", { + open: this.open + }); + this.focusTrap = createFocusTrap(this.$refs.appNavigationContainer, { + allowOutsideClick: true, + fallbackFocus: this.$refs.appNavigationContainer, + trapStack: getTrapStack(), + escapeDeactivates: false + }); + this.toggleFocusTrap(); + useHotKey("n", this.onKeyDown, { + prevent: true, + stop: true + }); + }, + unmounted() { + this.setHasAppNavigation(false); + unsubscribe("toggle-navigation", this.toggleNavigationByEventBus); + this.focusTrap.deactivate(); + }, + methods: { + /** + * Toggle the navigation + * + * @param {boolean} [state] set the state instead of inverting the current one + */ + async toggleNavigation(state) { + if (this.open === state) { + emit("navigation-toggled", { + open: this.open + }); + return; + } + this.open = typeof state === "undefined" ? !this.open : state; + const bodyStyles = getComputedStyle(document.body); + const animationLength = parseInt(bodyStyles.getPropertyValue("--animation-quick")) || 100; + if (this.open) { + await this.$nextTick(); + this.focusFirstElement(); + } + setTimeout(() => { + emit("navigation-toggled", { + open: this.open + }); + }, 1.5 * animationLength); + }, + toggleNavigationByEventBus({ open }) { + this.toggleNavigation(open); + }, + /** + * Activate focus trap if it is currently needed, otherwise deactivate + */ + toggleFocusTrap() { + if (this.isMobile && this.open) { + this.focusTrap.activate(); + } else { + this.focusTrap.deactivate(); + } + }, + handleEsc() { + if (this.isMobile && this.open) { + this.toggleNavigation(false); + } + }, + focusFirstElement() { + const element = tabbable(this.$refs.appNavigationContainer)[0]; + if (element) { + element.focus(); + logger.debug("Focusing first element in the navigation", { element }); + } + }, + onKeyDown(event) { + if (event.key === "n") { + if (!this.open) { + this.toggleNavigation(true); + return; + } + if (this.isFocusWithinNavigation()) { + this.toggleNavigation(false); + } + } + }, + isFocusWithinNavigation() { + const activeElement = document.activeElement; + return this.$refs.appNavigationContainer?.contains(activeElement); + } + } +}; +var _sfc_render$5 = function render2() { + var _vm = this, _c = _vm._self._c; + return _c("div", { ref: "appNavigationContainer", staticClass: "app-navigation", class: { "app-navigation--close": !_vm.open } }, [_c("nav", { staticClass: "app-navigation__content", attrs: { "id": "app-navigation-vue", "aria-hidden": _vm.open ? "false" : "true", "aria-label": _vm.ariaLabel || void 0, "aria-labelledby": _vm.ariaLabelledby || void 0, "inert": !_vm.open || void 0 }, on: { "keydown": function($event) { + if (!$event.type.indexOf("key") && _vm._k($event.keyCode, "esc", 27, $event.key, ["Esc", "Escape"])) return null; + return _vm.handleEsc.apply(null, arguments); + } } }, [_c("div", { staticClass: "app-navigation__search" }, [_vm._t("search")], 2), _c("div", { staticClass: "app-navigation__body", class: { "app-navigation__body--no-list": !_vm.$scopedSlots.list } }, [_vm._t("default")], 2), _vm.$scopedSlots.list ? _c("NcAppNavigationList", { staticClass: "app-navigation__list" }, [_vm._t("list")], 2) : _vm._e(), _vm._t("footer")], 2), _c("NcAppNavigationToggle", { attrs: { "open": _vm.open }, on: { "update:open": _vm.toggleNavigation } })], 1); +}; +var _sfc_staticRenderFns$5 = []; +var __component__$5 = /* @__PURE__ */ normalizeComponent( + _sfc_main$5, + _sfc_render$5, + _sfc_staticRenderFns$5, + false, + null, + "119f2aad" +); +const NcAppNavigation = __component__$5.exports; +const _sfc_main$4 = /* @__PURE__ */ defineComponent({ + __name: "NcAppSettingsSection", + props: { + name: null, + description: null, + id: null, + order: null + }, + setup(__props) { + const props = __props; + const slots = useSlots(); + const { registerSection, unregisterSection } = useAppSettingsDialog(); + const legacy = inject(APP_SETTINGS_LEGACY_DESIGN_KEY); + const htmlId = computed(() => "settings-section_" + props.id); + watch(() => props.id, () => { + if (!/^[a-z0-9\-_]+$/.test(props.id)) { + logger.warn(`Invalid id prop: ${props.id}. Only alphanumeric, dash and underscore are allowed.`); + } + }, { immediate: true }); + watch([() => props.id, () => props.name, () => props.order], ([newId, newName, newOrder], [oldId, ,]) => { + unregisterSection(oldId); + registerSection(newId, newName, newOrder, slots?.icon?.()); + }); + onMounted(() => { + registerSection(props.id, props.name, props.order, slots?.icon?.()); + }); + onBeforeUnmount(() => { + unregisterSection(props.id); + }); + return { __sfc: true, props, slots, registerSection, unregisterSection, legacy, htmlId }; + } +}); +var _sfc_render$4 = function render3() { + var _vm = this, _c = _vm._self._c, _setup = _vm._self._setupProxy; + return _c("section", { staticClass: "app-settings-section", class: { "app-settings-section__legacy": _setup.legacy }, attrs: { "id": _setup.htmlId, "aria-labelledby": `${_setup.htmlId}--label` } }, [_c("h3", { staticClass: "app-settings-section__name", attrs: { "id": `${_setup.htmlId}--label` } }, [_vm._v(" " + _vm._s(_vm.name) + " ")]), _c("div", { staticClass: "app-settings-section__description" }, [_vm._v(" " + _vm._s(_vm.description) + " ")]), _c("div", { staticClass: "app-settings-section__content" }, [_vm._t("default")], 2), _vm._e()], 2); +}; +var _sfc_staticRenderFns$4 = []; +var __component__$4 = /* @__PURE__ */ normalizeComponent( + _sfc_main$4, + _sfc_render$4, + _sfc_staticRenderFns$4, + false, + null, + "06cd755d" +); +const NcAppSettingsSection = __component__$4.exports; +const _sfc_main$3 = { + name: "CroppedLayoutSettings", + components: { + NcCheckboxRadioSwitch + }, + computed: { + croppedLayout() { + return this.$store.state.userConfig.croppedLayout; + } + }, + methods: { + updateSetting(value) { + this.$store.dispatch("updateUserConfig", { key: "croppedLayout", value }); + } + } +}; +var _sfc_render$3 = function render4() { + var _vm = this, _c = _vm._self._c; + return _c("NcCheckboxRadioSwitch", { attrs: { "model-value": _vm.croppedLayout, "type": "switch" }, on: { "update:model-value": _vm.updateSetting } }, [_vm._v(" " + _vm._s(_vm.t("photos", "Enable squared photos view")) + " ")]); +}; +var _sfc_staticRenderFns$3 = []; +_sfc_render$3._withStripped = true; +var __component__$3 = /* @__PURE__ */ normalizeComponent$1( + _sfc_main$3, + _sfc_render$3, + _sfc_staticRenderFns$3, + false, + null, + null +); +__component__$3.options.__file = "/var/www/html/customapps/photos/src/components/Settings/CroppedLayoutSettings.vue"; +const CroppedLayoutSettings = __component__$3.exports; +const _sfc_main$2 = defineComponent({ + name: "PhotosUploadLocationSettings", + components: { + NcButton, + FolderOutline + }, + emits: ["folders-update"], + data() { + return { + HomeOutline + }; + }, + computed: { + photosLocation() { + return this.$store.state.userConfig.photosLocation; + }, + photosSourceFolders() { + return this.$store.state.userConfig.photosSourceFolders; + }, + isPhotosLocationInphotosSourceFolders() { + const normalizedPath = this.photosLocation.replace(/\/+$/, ""); + const isPhotosLocationInphotosSourceFolders = this.photosSourceFolders.some((source) => { + const normalizedSource = source.replace(/\/+$/, ""); + return normalizedPath === normalizedSource || normalizedPath.startsWith(normalizedSource + "/"); + }); + return isPhotosLocationInphotosSourceFolders; + } + }, + methods: { + debounceSelectPhotosFolder: debounce(function() { + this.selectPhotosFolder(); + }), + async selectPhotosFolder() { + const pickedFolder = await this.openFilePicker(translate("photos", "Select the default upload location for your media")); + this.updatePhotosFolder(pickedFolder); + }, + async openFilePicker(title) { + const picker = getFilePickerBuilder(title).setMultiSelect(false).addMimeTypeFilter("httpd/unix-directory").allowDirectories().startAt(this.photosLocation).addButton({ + label: translate("photos", "Pick folder"), + variant: "primary", + callback: (nodes) => logger$1.debug("Picked", { nodes }) + }).build(); + return picker.pick(); + }, + updatePhotosFolder(path) { + this.$store.dispatch("updateUserConfig", { key: "photosLocation", value: path }); + this.$emit("folders-update", this.isPhotosLocationInphotosSourceFolders); + }, + t: translate + } +}); +var _sfc_render$2 = function render5() { + var _vm = this, _c = _vm._self._c; + _vm._self._setupProxy; + return _c("div", { staticClass: "photos-location" }, [_c("NcButton", { attrs: { "aria-label": _vm.t("photos", "Choose default Photos upload and Albums location"), "variant": "tertiary" }, on: { "click": _vm.debounceSelectPhotosFolder }, scopedSlots: _vm._u([{ key: "icon", fn: function() { + return [_c("FolderOutline", { attrs: { "size": 20 } })]; + }, proxy: true }]) }, [_vm._v(" " + _vm._s(_vm.photosLocation) + " ")])], 1); +}; +var _sfc_staticRenderFns$2 = []; +_sfc_render$2._withStripped = true; +var __component__$2 = /* @__PURE__ */ normalizeComponent$1( + _sfc_main$2, + _sfc_render$2, + _sfc_staticRenderFns$2, + false, + null, + "4524a52e" +); +__component__$2.options.__file = "/var/www/html/customapps/photos/src/components/Settings/PhotosUploadLocationSettings.vue"; +const PhotosUploadLocationSettings = __component__$2.exports; +const _sfc_main$1 = { + name: "SettingsDialog", + components: { + NcAppSettingsDialog, + NcAppSettingsSection, + NcNoteCard, + CroppedLayoutSettings, + PhotosSourceLocationsSettings, + PhotosUploadLocationSettings + }, + props: { + open: { + type: Boolean, + default: false + } + }, + data() { + return { + showFoldersWarning: false + }; + }, + computed: { + photosLocation() { + return this.$store.state.userConfig.photosLocation; + }, + photosSourceFolders() { + return this.$store.state.userConfig.photosSourceFolders; + }, + isPhotosLocationInphotosSourceFolders() { + const normalizedPath = this.photosLocation.replace(/\/+$/, ""); + const isPhotosLocationInphotosSourceFolders = this.photosSourceFolders.some((source) => { + const normalizedSource = source.replace(/\/+$/, ""); + return normalizedPath === normalizedSource || normalizedPath.startsWith(normalizedSource + "/"); + }); + return isPhotosLocationInphotosSourceFolders; + } + }, + methods: { + // This can only be called if the AppSettingsDialog + // is shown. So closing only + onClose() { + this.$emit("update:open", false); + }, + handleFoldersUpdate(isPhotosLocationInphotosSourceFolders) { + this.showFoldersWarning = !isPhotosLocationInphotosSourceFolders; + }, + t: translate + } +}; +var _sfc_render$1 = function render6() { + var _vm = this, _c = _vm._self._c; + return _c("NcAppSettingsDialog", { attrs: { "open": _vm.open, "show-navigation": false, "name": _vm.t("photos", "Photos settings"), "no-version": true }, on: { "update:open": _vm.onClose } }, [_c("NcAppSettingsSection", { attrs: { "id": "layout-settings", "name": _vm.t("photos", "View") } }, [_c("CroppedLayoutSettings")], 1), _c("NcAppSettingsSection", { attrs: { "id": "source-directories-settings", "name": _vm.t("photos", "Media folders") } }, [_c("div", { staticClass: "setting-section-subline" }, [_vm._v(" " + _vm._s(_vm.t("photos", "Choose the folders from where photos and videos are shown.")) + " ")]), _c("PhotosSourceLocationsSettings", { on: { "folders-update": _vm.handleFoldersUpdate } })], 1), _c("NcAppSettingsSection", { attrs: { "id": "upload-directory-settings", "name": _vm.t("photos", "Upload folder") } }, [_c("div", { staticClass: "setting-section-subline" }, [_vm._v(" " + _vm._s(_vm.t("photos", "Choose the folder where photos and albums are uploaded to.")) + " ")]), _c("PhotosUploadLocationSettings", { on: { "folders-update": _vm.handleFoldersUpdate } })], 1), _vm.showFoldersWarning || !_vm.isPhotosLocationInphotosSourceFolders ? _c("NcNoteCard", { staticClass: "notecard", attrs: { "type": "warning", "show-alert": true, "heading": _vm.t("photos", "Upload folder not part of media folder") } }, [_vm._v(" " + _vm._s(_vm.t("photos", "Uploaded items will not appear in the Photos & Videos section.")) + " ")]) : _vm._e()], 1); +}; +var _sfc_staticRenderFns$1 = []; +_sfc_render$1._withStripped = true; +var __component__$1 = /* @__PURE__ */ normalizeComponent$1( + _sfc_main$1, + _sfc_render$1, + _sfc_staticRenderFns$1, + false, + null, + null +); +__component__$1.options.__file = "/var/www/html/customapps/photos/src/components/Settings/SettingsDialog.vue"; +const SettingsDialog = __component__$1.exports; +const appStoreEnabled = loadState("photos", "appStoreEnabled", false); +const _sfc_main = { + name: "PhotosApp", + components: { + AccountBoxMultiple, + AccountBoxMultipleOutline, + CogOutline, + CalendarToday, + CalendarTodayOutline, + Camera, + CameraOutline, + AccountGroup, + AccountGroupOutline, + Folder, + FolderOutline, + ImageMultiple, + ImageMultipleOutline, + ImageIcon, + ImageOutline: ImageOutlineIcon, + ShareVariant, + ShareVariantOutline, + Star, + StarOutline, + Tag, + TagOutline, + VideoIcon, + VideoOutline, + MapIcon, + MapOutline, + MapMarker, + MapMarkerOutline, + NcAppContent, + NcAppNavigation, + NcAppNavigationItem, + NcButton, + NcContent, + SettingsDialog, + PhotosFiltersInput, + PhotosFiltersDisplay + }, + setup() { + const filtersStore = useFilterStore(); + const { selectedFilters } = storeToRefs(filtersStore); + return { + selectedFilters + }; + }, + data() { + return { + svgplaceholder, + imgplaceholder, + videoplaceholder, + areTagsInstalled: systemtags, + showLocationMenuEntry: getCurrentUser() === null ? false : getCurrentUser().isAdmin && appStoreEnabled || maps, + showPeopleMenuEntry: getCurrentUser() === null ? false : getCurrentUser().isAdmin && loadState("photos", "showPeopleMenuEntry", true) && appStoreEnabled || recognize, + openedSettings: false + }; + }, + computed: { + isTimelineView() { + return ["all_media", "photos", "videos"].includes(this.$store.state.route.name || ""); + } + }, + async beforeMount() { + const files = loadState("photos", "nomedia-paths", []); + this.$store.dispatch("setNomediaPaths", files); + logger$1.debug("Known .nomedia and .noimage paths", { files }); + if ("serviceWorker" in navigator) { + window.addEventListener("load", () => { + navigator.serviceWorker.register(generateUrl("/apps/photos/service-worker.js", {}, { + noRewrite: true + }), { + scope: generateUrl("/apps/photos") + }).then((registration) => { + logger$1.debug("SW registered: ", { registration }); + }).catch((registrationError) => { + logger$1.error("SW registration failed: ", { registrationError }); + }); + }); + } else { + logger$1.debug("Service Worker is not enabled on this browser."); + } + }, + beforeDestroy() { + window.removeEventListener("load", () => { + navigator.serviceWorker.register(generateUrl("/apps/photos/service-worker.js", {}, { + noRewrite: true + })); + }); + }, + methods: { + showSettings() { + this.openedSettings = true; + }, + selectFilter(filterOption) { + this.selectedFilters[filterOption.filterId].push(filterOption.value); + }, + deselectFilter(filterOption) { + const index = this.selectedFilters[filterOption.filterId].indexOf(filterOption.value); + if (index !== -1) { + this.selectedFilters[filterOption.filterId].splice(index, 1); + } + }, + t: translate + } +}; +var _sfc_render = function render7() { + var _vm = this, _c = _vm._self._c; + return _c("NcContent", { attrs: { "app-name": "photos" } }, [_c("NcAppNavigation", { attrs: { "aria-label": _vm.t("photos", "Photos") }, scopedSlots: _vm._u([_vm.isTimelineView ? { key: "search", fn: function() { + return [_c("PhotosFiltersInput", { attrs: { "selected-filters": _vm.selectedFilters }, on: { "select-filter": _vm.selectFilter } }), _c("PhotosFiltersDisplay", { attrs: { "selected-filters": _vm.selectedFilters }, on: { "deselect-filter": _vm.deselectFilter } })]; + }, proxy: true } : null, { key: "list", fn: function() { + return [_c("NcAppNavigationItem", { staticClass: "app-navigation__all_media", attrs: { "to": { name: "all_media" }, "name": _vm.t("photos", "All media"), "data-id-app-nav-item": "all-media", "exact": "" }, scopedSlots: _vm._u([{ key: "icon", fn: function({ active }) { + return [active ? _c("ImageIcon", { attrs: { "size": 20 } }) : _c("ImageOutline", { attrs: { "size": 20 } })]; + } }]) }), _c("NcAppNavigationItem", { attrs: { "to": "/photos", "name": _vm.t("photos", "Photos"), "data-id-app-nav-item": "photos" }, scopedSlots: _vm._u([{ key: "icon", fn: function({ active }) { + return [active ? _c("Camera", { attrs: { "size": 20 } }) : _c("CameraOutline", { attrs: { "size": 20 } })]; + } }]) }), _c("NcAppNavigationItem", { attrs: { "to": "/videos", "name": _vm.t("photos", "Videos"), "data-id-app-nav-item": "videos" }, scopedSlots: _vm._u([{ key: "icon", fn: function({ active }) { + return [active ? _c("VideoIcon", { attrs: { "size": 20 } }) : _c("VideoOutline", { attrs: { "size": 20 } })]; + } }]) }), _c("NcAppNavigationItem", { attrs: { "to": { name: "albums" }, "name": _vm.t("photos", "Albums"), "data-id-app-nav-item": "albums" }, scopedSlots: _vm._u([{ key: "icon", fn: function({ active }) { + return [active ? _c("ImageMultiple", { attrs: { "size": 20 } }) : _c("ImageMultipleOutline", { attrs: { "size": 20 } })]; + } }]) }), _c("NcAppNavigationItem", { attrs: { "to": { name: "sharedAlbums" }, "name": _vm.t("photos", "Collaborative albums"), "data-id-app-nav-item": "sharedalbums" }, scopedSlots: _vm._u([{ key: "icon", fn: function({ active }) { + return [active ? _c("AccountGroup", { attrs: { "size": 20 } }) : _c("AccountGroupOutline", { attrs: { "size": 20 } })]; + } }]) }), _vm.showPeopleMenuEntry ? _c("NcAppNavigationItem", { attrs: { "to": { name: "faces" }, "name": _vm.t("photos", "People"), "data-id-app-nav-item": "faces" }, scopedSlots: _vm._u([{ key: "icon", fn: function({ active }) { + return [active ? _c("AccountBoxMultiple", { attrs: { "size": 20 } }) : _c("AccountBoxMultipleOutline", { attrs: { "size": 20 } })]; + } }], null, false, 3295904880) }) : _vm._e(), _c("NcAppNavigationItem", { attrs: { "to": { name: "folders" }, "name": _vm.t("photos", "Folders"), "data-id-app-nav-item": "folders" }, scopedSlots: _vm._u([{ key: "icon", fn: function({ active }) { + return [active ? _c("Folder", { attrs: { "size": 20 } }) : _c("FolderOutline", { attrs: { "size": 20 } })]; + } }]) }), _c("NcAppNavigationItem", { attrs: { "to": "/favorites", "name": _vm.t("photos", "Favorites"), "data-id-app-nav-item": "favorites" }, scopedSlots: _vm._u([{ key: "icon", fn: function({ active }) { + return [active ? _c("Star", { attrs: { "size": 20 } }) : _c("StarOutline", { attrs: { "size": 20 } })]; + } }]) }), _c("NcAppNavigationItem", { attrs: { "to": { name: "thisday" }, "name": _vm.t("photos", "On this day"), "data-id-app-nav-item": "this-day" }, scopedSlots: _vm._u([{ key: "icon", fn: function({ active }) { + return [active ? _c("CalendarToday", { attrs: { "size": 20 } }) : _c("CalendarTodayOutline", { attrs: { "size": 20 } })]; + } }]) }), _c("NcAppNavigationItem", { attrs: { "to": { name: "shared" }, "name": _vm.t("photos", "Shared with you"), "data-id-app-nav-item": "shared" }, scopedSlots: _vm._u([{ key: "icon", fn: function({ active }) { + return [active ? _c("ShareVariant", { attrs: { "size": 20 } }) : _c("ShareVariantOutline", { attrs: { "size": 20 } })]; + } }]) }), _vm.areTagsInstalled ? _c("NcAppNavigationItem", { attrs: { "to": { name: "tags" }, "name": _vm.t("photos", "Tags"), "data-id-app-nav-item": "tags" }, scopedSlots: _vm._u([{ key: "icon", fn: function({ active }) { + return [active ? _c("Tag", { attrs: { "size": 20 } }) : _c("TagOutline", { attrs: { "size": 20 } })]; + } }], null, false, 346180464) }) : _vm._e(), _c("NcAppNavigationItem", { attrs: { "to": { name: "places" }, "name": _vm.t("photos", "Places"), "data-id-app-nav-item": "places" }, scopedSlots: _vm._u([{ key: "icon", fn: function({ active }) { + return [active ? _c("MapMarker", { attrs: { "size": 20 } }) : _c("MapMarkerOutline", { attrs: { "size": 20 } })]; + } }]) }), _vm.showLocationMenuEntry ? _c("NcAppNavigationItem", { attrs: { "to": { name: "maps" }, "name": _vm.t("photos", "Map"), "data-id-app-nav-item": "maps" }, scopedSlots: _vm._u([{ key: "icon", fn: function({ active }) { + return [active ? _c("MapIcon", { attrs: { "size": 20 } }) : _c("MapOutline", { attrs: { "size": 20 } })]; + } }], null, false, 257739259) }) : _vm._e()]; + }, proxy: true }, { key: "footer", fn: function() { + return [_c("div", { staticClass: "app-navigation__footer" }, [_c("NcButton", { attrs: { "variant": "tertiary", "alignment": "start", "wide": "" }, on: { "click": _vm.showSettings }, scopedSlots: _vm._u([{ key: "icon", fn: function() { + return [_c("CogOutline", { attrs: { "size": 20 } })]; + }, proxy: true }]) }, [_vm._v(" " + _vm._s(_vm.t("photos", "Photos settings")) + " ")])], 1)]; + }, proxy: true }], null, true) }), _c("NcAppContent", [_c("RouterView"), _c("span", { staticClass: "hidden-visually", attrs: { "role": "none" }, domProps: { "innerHTML": _vm._s(_vm.svgplaceholder) } }), _c("span", { staticClass: "hidden-visually", attrs: { "role": "none" }, domProps: { "innerHTML": _vm._s(_vm.imgplaceholder) } }), _c("span", { staticClass: "hidden-visually", attrs: { "role": "none" }, domProps: { "innerHTML": _vm._s(_vm.videoplaceholder) } })], 1), _c("SettingsDialog", { attrs: { "open": _vm.openedSettings }, on: { "update:open": function($event) { + _vm.openedSettings = $event; + } } })], 1); +}; +var _sfc_staticRenderFns = []; +_sfc_render._withStripped = true; +var __component__ = /* @__PURE__ */ normalizeComponent$1( + _sfc_main, + _sfc_render, + _sfc_staticRenderFns, + false, + null, + null +); +__component__.options.__file = "/var/www/html/customapps/photos/src/PhotosApp.vue"; +const PhotosApp = __component__.exports; +vuexRouterSyncExports.sync(photosStore, router); +Vue.prototype.t = translate; +Vue.prototype.n = translatePlural; +registerDavProperty("nc:metadata-photos-size"); +registerDavProperty("nc:metadata-files-live-photo"); +registerDavProperty("nc:metadata-blurhash"); +registerDavProperty("nc:metadata-photos-original_date_time"); +Vue.use(PiniaVuePlugin); +new Vue({ + el: "#content", + name: "PhotosRoot", + router, + store: photosStore, + pinia: createPinia(), + render: (h) => h(PhotosApp) +}); //# sourceMappingURL=photos-main.mjs.map diff --git a/js/photos-main.mjs.license b/js/photos-main.mjs.license deleted file mode 100644 index 3d18728950..0000000000 --- a/js/photos-main.mjs.license +++ /dev/null @@ -1,11 +0,0 @@ -SPDX-License-Identifier: AGPL-3.0-or-later -SPDX-FileCopyrightText: John Molakvoæ -SPDX-FileCopyrightText: Nextcloud GmbH and Nextcloud contributors - -This file is generated from multiple sources. Included packages: -- @nextcloud/vue - - version: 8.35.0 - - license: AGPL-3.0-or-later -- photos - - version: 5.0.0-dev.1 - - license: AGPL-3.0-or-later diff --git a/js/photos-main.mjs.map b/js/photos-main.mjs.map index b36f77c8f9..73af0f9716 100644 --- a/js/photos-main.mjs.map +++ b/js/photos-main.mjs.map @@ -1 +1 @@ -{"version":3,"file":"photos-main.mjs","sources":["../node_modules/@nextcloud/vue/dist/Components/NcAppNavigationList.mjs","../node_modules/@nextcloud/vue/dist/chunks/NcAppNavigation-DgekTp_z.mjs","../node_modules/@nextcloud/vue/dist/chunks/NcAppSettingsSection-Cq1VIzMR.mjs","../src/components/Settings/CroppedLayoutSettings.vue","../src/components/Settings/PhotosUploadLocationSettings.vue","../src/components/Settings/SettingsDialog.vue","../src/services/IsAppStoreEnabled.ts","../src/PhotosApp.vue","../src/main.ts"],"sourcesContent":["import '../assets/NcAppNavigationList-DnKj0-Zq.css';\nimport { n as normalizeComponent } from \"../chunks/_plugin-vue2_normalizer-DU4iP6Vu.mjs\";\nconst _sfc_main = {\n name: \"NcAppNavigationList\"\n};\nvar _sfc_render = function render() {\n var _vm = this, _c = _vm._self._c;\n return _c(\"ul\", { staticClass: \"app-navigation-list\" }, [_vm._t(\"default\")], 2);\n};\nvar _sfc_staticRenderFns = [];\nvar __component__ = /* @__PURE__ */ normalizeComponent(\n _sfc_main,\n _sfc_render,\n _sfc_staticRenderFns,\n false,\n null,\n \"058e6060\"\n);\nconst NcAppNavigationList = __component__.exports;\nexport {\n NcAppNavigationList as default\n};\n//# sourceMappingURL=NcAppNavigationList.mjs.map\n","import '../assets/NcAppNavigation-Dbpqdigp.css';\nimport { emit, unsubscribe, subscribe } from \"@nextcloud/event-bus\";\nimport { createFocusTrap } from \"focus-trap\";\nimport { tabbable } from \"tabbable\";\nimport Vue from \"vue\";\nimport { useHotKey } from \"../Composables/useHotKey.mjs\";\nimport { useIsMobile } from \"../Composables/useIsMobile.mjs\";\nimport { g as getTrapStack } from \"./focusTrap-HJQ4pqHV.mjs\";\nimport { l as logger } from \"./logger-D3RVzcfQ.mjs\";\nimport NcAppNavigationList from \"../Components/NcAppNavigationList.mjs\";\nimport { N as NcAppNavigationToggle } from \"./NcAppNavigationToggle-B0N05AxP.mjs\";\nimport { n as normalizeComponent } from \"./_plugin-vue2_normalizer-DU4iP6Vu.mjs\";\nconst _sfc_main = {\n name: \"NcAppNavigation\",\n components: {\n NcAppNavigationList,\n NcAppNavigationToggle\n },\n // Injected from NcContent\n inject: {\n setHasAppNavigation: {\n default: () => () => Vue.util.warn(\"NcAppNavigation is not mounted inside NcContent, this is probably an error.\"),\n from: \"NcContent:setHasAppNavigation\"\n }\n },\n props: {\n /**\n * The aria label to describe the navigation\n */\n ariaLabel: {\n type: String,\n default: \"\"\n },\n /**\n * aria-labelledby attribute to describe the navigation\n */\n ariaLabelledby: {\n type: String,\n default: \"\"\n }\n },\n setup() {\n return {\n isMobile: useIsMobile()\n };\n },\n data() {\n return {\n open: !this.isMobile,\n focusTrap: null\n };\n },\n watch: {\n isMobile() {\n this.open = !this.isMobile;\n this.toggleFocusTrap();\n },\n open() {\n this.toggleFocusTrap();\n }\n },\n mounted() {\n this.setHasAppNavigation(true);\n subscribe(\"toggle-navigation\", this.toggleNavigationByEventBus);\n emit(\"navigation-toggled\", {\n open: this.open\n });\n this.focusTrap = createFocusTrap(this.$refs.appNavigationContainer, {\n allowOutsideClick: true,\n fallbackFocus: this.$refs.appNavigationContainer,\n trapStack: getTrapStack(),\n escapeDeactivates: false\n });\n this.toggleFocusTrap();\n useHotKey(\"n\", this.onKeyDown, {\n prevent: true,\n stop: true\n });\n },\n unmounted() {\n this.setHasAppNavigation(false);\n unsubscribe(\"toggle-navigation\", this.toggleNavigationByEventBus);\n this.focusTrap.deactivate();\n },\n methods: {\n /**\n * Toggle the navigation\n *\n * @param {boolean} [state] set the state instead of inverting the current one\n */\n async toggleNavigation(state) {\n if (this.open === state) {\n emit(\"navigation-toggled\", {\n open: this.open\n });\n return;\n }\n this.open = typeof state === \"undefined\" ? !this.open : state;\n const bodyStyles = getComputedStyle(document.body);\n const animationLength = parseInt(bodyStyles.getPropertyValue(\"--animation-quick\")) || 100;\n if (this.open) {\n await this.$nextTick();\n this.focusFirstElement();\n }\n setTimeout(() => {\n emit(\"navigation-toggled\", {\n open: this.open\n });\n }, 1.5 * animationLength);\n },\n toggleNavigationByEventBus({ open }) {\n this.toggleNavigation(open);\n },\n /**\n * Activate focus trap if it is currently needed, otherwise deactivate\n */\n toggleFocusTrap() {\n if (this.isMobile && this.open) {\n this.focusTrap.activate();\n } else {\n this.focusTrap.deactivate();\n }\n },\n handleEsc() {\n if (this.isMobile && this.open) {\n this.toggleNavigation(false);\n }\n },\n focusFirstElement() {\n const element = tabbable(this.$refs.appNavigationContainer)[0];\n if (element) {\n element.focus();\n logger.debug(\"Focusing first element in the navigation\", { element });\n }\n },\n onKeyDown(event) {\n if (event.key === \"n\") {\n if (!this.open) {\n this.toggleNavigation(true);\n return;\n }\n if (this.isFocusWithinNavigation()) {\n this.toggleNavigation(false);\n }\n }\n },\n isFocusWithinNavigation() {\n const activeElement = document.activeElement;\n return this.$refs.appNavigationContainer?.contains(activeElement);\n }\n }\n};\nvar _sfc_render = function render() {\n var _vm = this, _c = _vm._self._c;\n return _c(\"div\", { ref: \"appNavigationContainer\", staticClass: \"app-navigation\", class: { \"app-navigation--close\": !_vm.open } }, [_c(\"nav\", { staticClass: \"app-navigation__content\", attrs: { \"id\": \"app-navigation-vue\", \"aria-hidden\": _vm.open ? \"false\" : \"true\", \"aria-label\": _vm.ariaLabel || void 0, \"aria-labelledby\": _vm.ariaLabelledby || void 0, \"inert\": !_vm.open || void 0 }, on: { \"keydown\": function($event) {\n if (!$event.type.indexOf(\"key\") && _vm._k($event.keyCode, \"esc\", 27, $event.key, [\"Esc\", \"Escape\"])) return null;\n return _vm.handleEsc.apply(null, arguments);\n } } }, [_c(\"div\", { staticClass: \"app-navigation__search\" }, [_vm._t(\"search\")], 2), _c(\"div\", { staticClass: \"app-navigation__body\", class: { \"app-navigation__body--no-list\": !_vm.$scopedSlots.list } }, [_vm._t(\"default\")], 2), _vm.$scopedSlots.list ? _c(\"NcAppNavigationList\", { staticClass: \"app-navigation__list\" }, [_vm._t(\"list\")], 2) : _vm._e(), _vm._t(\"footer\")], 2), _c(\"NcAppNavigationToggle\", { attrs: { \"open\": _vm.open }, on: { \"update:open\": _vm.toggleNavigation } })], 1);\n};\nvar _sfc_staticRenderFns = [];\nvar __component__ = /* @__PURE__ */ normalizeComponent(\n _sfc_main,\n _sfc_render,\n _sfc_staticRenderFns,\n false,\n null,\n \"119f2aad\"\n);\nconst NcAppNavigation = __component__.exports;\nexport {\n NcAppNavigation as N\n};\n//# sourceMappingURL=NcAppNavigation-DgekTp_z.mjs.map\n","import '../assets/NcAppSettingsSection-Yg4NYCih.css';\nimport { defineComponent, useSlots, inject, computed, watch, onMounted, onBeforeUnmount } from \"vue\";\nimport { l as logger } from \"./logger-D3RVzcfQ.mjs\";\nimport { u as useAppSettingsDialog, A as APP_SETTINGS_LEGACY_DESIGN_KEY } from \"./useAppSettingsDialog-DbtEkXa4.mjs\";\nimport { n as normalizeComponent } from \"./_plugin-vue2_normalizer-DU4iP6Vu.mjs\";\nconst _sfc_main = /* @__PURE__ */ defineComponent({\n __name: \"NcAppSettingsSection\",\n props: {\n name: null,\n description: null,\n id: null,\n order: null\n },\n setup(__props) {\n const props = __props;\n const slots = useSlots();\n const { registerSection, unregisterSection } = useAppSettingsDialog();\n const legacy = inject(APP_SETTINGS_LEGACY_DESIGN_KEY);\n const htmlId = computed(() => \"settings-section_\" + props.id);\n watch(() => props.id, () => {\n if (!/^[a-z0-9\\-_]+$/.test(props.id)) {\n logger.warn(`Invalid id prop: ${props.id}. Only alphanumeric, dash and underscore are allowed.`);\n }\n }, { immediate: true });\n watch([() => props.id, () => props.name, () => props.order], ([newId, newName, newOrder], [oldId, ,]) => {\n unregisterSection(oldId);\n registerSection(newId, newName, newOrder, slots?.icon?.());\n });\n onMounted(() => {\n registerSection(props.id, props.name, props.order, slots?.icon?.());\n });\n onBeforeUnmount(() => {\n unregisterSection(props.id);\n });\n return { __sfc: true, props, slots, registerSection, unregisterSection, legacy, htmlId };\n }\n});\nvar _sfc_render = function render() {\n var _vm = this, _c = _vm._self._c, _setup = _vm._self._setupProxy;\n return _c(\"section\", { staticClass: \"app-settings-section\", class: { \"app-settings-section__legacy\": _setup.legacy }, attrs: { \"id\": _setup.htmlId, \"aria-labelledby\": `${_setup.htmlId}--label` } }, [_c(\"h3\", { staticClass: \"app-settings-section__name\", attrs: { \"id\": `${_setup.htmlId}--label` } }, [_vm._v(\" \" + _vm._s(_vm.name) + \" \")]), _c(\"div\", { staticClass: \"app-settings-section__description\" }, [_vm._v(\" \" + _vm._s(_vm.description) + \" \")]), _c(\"div\", { staticClass: \"app-settings-section__content\" }, [_vm._t(\"default\")], 2), _vm._e()], 2);\n};\nvar _sfc_staticRenderFns = [];\nvar __component__ = /* @__PURE__ */ normalizeComponent(\n _sfc_main,\n _sfc_render,\n _sfc_staticRenderFns,\n false,\n null,\n \"06cd755d\"\n);\nconst NcAppSettingsSection = __component__.exports;\nexport {\n NcAppSettingsSection as N\n};\n//# sourceMappingURL=NcAppSettingsSection-Cq1VIzMR.mjs.map\n","\n\n\n\n\n","\n\n\n\n\n\n\n","\n\n\n\n\n\n\n","/**\n * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport { loadState } from '@nextcloud/initial-state'\n\nconst appStoreEnabled = loadState('photos', 'appStoreEnabled', false) as boolean\nexport default appStoreEnabled\n","\n\n\n\n\n\n\n","/**\n * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport { registerDavProperty } from '@nextcloud/files/dav'\nimport { translate, translatePlural } from '@nextcloud/l10n'\nimport { createPinia, PiniaVuePlugin } from 'pinia'\nimport Vue from 'vue'\nimport { sync } from 'vuex-router-sync'\nimport PhotosApp from './PhotosApp.vue'\nimport router from './router/index.js'\nimport store from './store/index.js'\n\nsync(store, router)\n\nVue.prototype.t = translate\nVue.prototype.n = translatePlural\n\nregisterDavProperty('nc:metadata-photos-size')\nregisterDavProperty('nc:metadata-files-live-photo')\nregisterDavProperty('nc:metadata-blurhash')\nregisterDavProperty('nc:metadata-photos-original_date_time')\n\nVue.use(PiniaVuePlugin)\n\nexport default new Vue({\n\tel: '#content',\n\tname: 'PhotosRoot',\n\trouter,\n\tstore,\n\tpinia: createPinia(),\n\trender: (h) => h(PhotosApp),\n})\n"],"names":["_sfc_main","_sfc_render","_vm","_c","_sfc_staticRenderFns","__component__","normalizeComponent","NcAppNavigationList","NcAppNavigationToggle","Vue","useIsMobile","subscribe","emit","createFocusTrap","getTrapStack","useHotKey","unsubscribe","state","bodyStyles","animationLength","open","element","tabbable","logger","event","activeElement","$event","NcAppNavigation","defineComponent","__props","props","slots","useSlots","registerSection","unregisterSection","useAppSettingsDialog","legacy","inject","APP_SETTINGS_LEGACY_DESIGN_KEY","htmlId","computed","watch","newId","newName","newOrder","oldId","onMounted","onBeforeUnmount","_setup","NcAppSettingsSection","_sfc_main$3","NcCheckboxRadioSwitch","value","_sfc_main$2","NcButton","FolderOutline","HomeOutline","normalizedPath","source","normalizedSource","debounce","pickedFolder","t","title","getFilePickerBuilder","nodes","path","_sfc_main$1","NcAppSettingsDialog","NcNoteCard","CroppedLayoutSettings","PhotosSourceLocationsSettings","PhotosUploadLocationSettings","isPhotosLocationInphotosSourceFolders","appStoreEnabled","loadState","AccountBoxMultiple","AccountBoxMultipleOutline","CogOutline","CalendarToday","CalendarTodayOutline","Camera","CameraOutline","AccountGroup","AccountGroupOutline","Folder","ImageMultiple","ImageMultipleOutline","ImageIcon","ImageOutline","ShareVariant","ShareVariantOutline","Star","StarOutline","Tag","TagOutline","VideoIcon","VideoOutline","MapIcon","MapOutline","MapMarker","MapMarkerOutline","NcAppContent","NcAppNavigationItem","NcContent","SettingsDialog","PhotosFiltersInput","PhotosFiltersDisplay","filtersStore","useFilterStore","selectedFilters","storeToRefs","svgplaceholder","imgplaceholder","videoplaceholder","areTagsInstalled","getCurrentUser","isAppStoreEnabled","isMapsInstalled","isRecognizeInstalled","files","generateUrl","registration","registrationError","filterOption","index","sync","store","router","translate","translatePlural","registerDavProperty","PiniaVuePlugin","createPinia","h","PhotosApp"],"mappings":"+gDAEA,MAAMA,GAAY,CAChB,KAAM,qBACR,EACA,IAAIC,GAAc,UAAkB,CAClC,IAAIC,EAAM,KAAMC,EAAKD,EAAI,MAAM,GAC/B,OAAOC,EAAG,KAAM,CAAE,YAAa,qBAAqB,EAAI,CAACD,EAAI,GAAG,SAAS,CAAC,EAAG,CAAC,CAChF,EACIE,GAAuB,CAAA,EACvBC,GAAgCC,EAClCN,GACAC,GACAG,GACA,GACA,KACA,UACF,EACA,MAAMG,GAAsBF,GAAc,QCNpCL,GAAY,CAChB,KAAM,kBACN,WAAY,CACV,oBAAAO,GACA,sBAAAC,EACJ,EAEE,OAAQ,CACN,oBAAqB,CACnB,QAAS,IAAM,IAAMC,EAAI,KAAK,KAAK,6EAA6E,EAChH,KAAM,+BACZ,CACA,EACE,MAAO,CAIL,UAAW,CACT,KAAM,OACN,QAAS,EACf,EAII,eAAgB,CACd,KAAM,OACN,QAAS,EACf,CACA,EACE,OAAQ,CACN,MAAO,CACL,SAAUC,EAAW,CAC3B,CACE,EACA,MAAO,CACL,MAAO,CACL,KAAM,CAAC,KAAK,SACZ,UAAW,IACjB,CACE,EACA,MAAO,CACL,UAAW,CACT,KAAK,KAAO,CAAC,KAAK,SAClB,KAAK,gBAAe,CACtB,EACA,MAAO,CACL,KAAK,gBAAe,CACtB,CACJ,EACE,SAAU,CACR,KAAK,oBAAoB,EAAI,EAC7BC,EAAU,oBAAqB,KAAK,0BAA0B,EAC9DC,EAAK,qBAAsB,CACzB,KAAM,KAAK,IACjB,CAAK,EACD,KAAK,UAAYC,EAAgB,KAAK,MAAM,uBAAwB,CAClE,kBAAmB,GACnB,cAAe,KAAK,MAAM,uBAC1B,UAAWC,GAAY,EACvB,kBAAmB,EACzB,CAAK,EACD,KAAK,gBAAe,EACpBC,GAAU,IAAK,KAAK,UAAW,CAC7B,QAAS,GACT,KAAM,EACZ,CAAK,CACH,EACA,WAAY,CACV,KAAK,oBAAoB,EAAK,EAC9BC,EAAY,oBAAqB,KAAK,0BAA0B,EAChE,KAAK,UAAU,WAAU,CAC3B,EACA,QAAS,CAMP,MAAM,iBAAiBC,EAAO,CAC5B,GAAI,KAAK,OAASA,EAAO,CACvBL,EAAK,qBAAsB,CACzB,KAAM,KAAK,IACrB,CAAS,EACD,MACF,CACA,KAAK,KAAO,OAAOK,EAAU,IAAc,CAAC,KAAK,KAAOA,EACxD,MAAMC,EAAa,iBAAiB,SAAS,IAAI,EAC3CC,EAAkB,SAASD,EAAW,iBAAiB,mBAAmB,CAAC,GAAK,IAClF,KAAK,OACP,MAAM,KAAK,UAAS,EACpB,KAAK,kBAAiB,GAExB,WAAW,IAAM,CACfN,EAAK,qBAAsB,CACzB,KAAM,KAAK,IACrB,CAAS,CACH,EAAG,IAAMO,CAAe,CAC1B,EACA,2BAA2B,CAAE,KAAAC,GAAQ,CACnC,KAAK,iBAAiBA,CAAI,CAC5B,EAIA,iBAAkB,CACZ,KAAK,UAAY,KAAK,KACxB,KAAK,UAAU,SAAQ,EAEvB,KAAK,UAAU,WAAU,CAE7B,EACA,WAAY,CACN,KAAK,UAAY,KAAK,MACxB,KAAK,iBAAiB,EAAK,CAE/B,EACA,mBAAoB,CAClB,MAAMC,EAAUC,EAAS,KAAK,MAAM,sBAAsB,EAAE,CAAC,EACzDD,IACFA,EAAQ,MAAK,EACbE,EAAO,MAAM,2CAA4C,CAAE,QAAAF,CAAO,CAAE,EAExE,EACA,UAAUG,EAAO,CACf,GAAIA,EAAM,MAAQ,IAAK,CACrB,GAAI,CAAC,KAAK,KAAM,CACd,KAAK,iBAAiB,EAAI,EAC1B,MACF,CACI,KAAK,2BACP,KAAK,iBAAiB,EAAK,CAE/B,CACF,EACA,yBAA0B,CACxB,MAAMC,EAAgB,SAAS,cAC/B,OAAO,KAAK,MAAM,wBAAwB,SAASA,CAAa,CAClE,CACJ,CACA,EACA,IAAIxB,GAAc,UAAkB,CAClC,IAAIC,EAAM,KAAMC,EAAKD,EAAI,MAAM,GAC/B,OAAOC,EAAG,MAAO,CAAE,IAAK,yBAA0B,YAAa,iBAAkB,MAAO,CAAE,wBAAyB,CAACD,EAAI,IAAI,CAAE,EAAI,CAACC,EAAG,MAAO,CAAE,YAAa,0BAA2B,MAAO,CAAE,GAAM,qBAAsB,cAAeD,EAAI,KAAO,QAAU,OAAQ,aAAcA,EAAI,WAAa,OAAQ,kBAAmBA,EAAI,gBAAkB,OAAQ,MAAS,CAACA,EAAI,MAAQ,MAAM,EAAI,GAAI,CAAE,QAAW,SAASwB,EAAQ,CACha,MAAI,CAACA,EAAO,KAAK,QAAQ,KAAK,GAAKxB,EAAI,GAAGwB,EAAO,QAAS,MAAO,GAAIA,EAAO,IAAK,CAAC,MAAO,QAAQ,CAAC,EAAU,KACrGxB,EAAI,UAAU,MAAM,KAAM,SAAS,CAC5C,CAAC,CAAE,EAAI,CAACC,EAAG,MAAO,CAAE,YAAa,wBAAwB,EAAI,CAACD,EAAI,GAAG,QAAQ,CAAC,EAAG,CAAC,EAAGC,EAAG,MAAO,CAAE,YAAa,uBAAwB,MAAO,CAAE,gCAAiC,CAACD,EAAI,aAAa,IAAI,CAAE,EAAI,CAACA,EAAI,GAAG,SAAS,CAAC,EAAG,CAAC,EAAGA,EAAI,aAAa,KAAOC,EAAG,sBAAuB,CAAE,YAAa,sBAAsB,EAAI,CAACD,EAAI,GAAG,MAAM,CAAC,EAAG,CAAC,EAAIA,EAAI,GAAE,EAAIA,EAAI,GAAG,QAAQ,CAAC,EAAG,CAAC,EAAGC,EAAG,wBAAyB,CAAE,MAAO,CAAE,KAAQD,EAAI,IAAI,EAAI,GAAI,CAAE,cAAeA,EAAI,gBAAgB,CAAE,CAAE,CAAC,EAAG,CAAC,CACve,EACIE,GAAuB,CAAA,EACvBC,GAAgCC,EAClCN,GACAC,GACAG,GACA,GACA,KACA,UACF,EACA,MAAMuB,GAAkBtB,GAAc,QCnKhCL,GAA4B4B,EAAgB,CAChD,OAAQ,uBACR,MAAO,CACL,KAAM,KACN,YAAa,KACb,GAAI,KACJ,MAAO,IACX,EACE,MAAMC,EAAS,CACb,MAAMC,EAAQD,EACRE,EAAQC,EAAQ,EAChB,CAAE,gBAAAC,EAAiB,kBAAAC,CAAiB,EAAKC,GAAoB,EAC7DC,EAASC,EAAOC,EAA8B,EAC9CC,EAASC,EAAS,IAAM,oBAAsBV,EAAM,EAAE,EAC5D,OAAAW,EAAM,IAAMX,EAAM,GAAI,IAAM,CACrB,iBAAiB,KAAKA,EAAM,EAAE,GACjCP,EAAO,KAAK,oBAAoBO,EAAM,EAAE,uDAAuD,CAEnG,EAAG,CAAE,UAAW,GAAM,EACtBW,EAAM,CAAC,IAAMX,EAAM,GAAI,IAAMA,EAAM,KAAM,IAAMA,EAAM,KAAK,EAAG,CAAC,CAACY,EAAOC,EAASC,CAAQ,EAAG,CAACC,OAAc,CACvGX,EAAkBW,CAAK,EACvBZ,EAAgBS,EAAOC,EAASC,EAAUb,GAAO,OAAI,CAAI,CAC3D,CAAC,EACDe,EAAU,IAAM,CACdb,EAAgBH,EAAM,GAAIA,EAAM,KAAMA,EAAM,MAAOC,GAAO,QAAQ,CACpE,CAAC,EACDgB,EAAgB,IAAM,CACpBb,EAAkBJ,EAAM,EAAE,CAC5B,CAAC,EACM,CAAE,MAAO,GAAM,MAAAA,EAAO,MAAAC,EAAO,gBAAAE,EAAiB,kBAAAC,EAAmB,OAAAE,EAAQ,OAAAG,CAAM,CACxF,CACF,CAAC,EACD,IAAItC,GAAc,UAAkB,CAClC,IAAIC,EAAM,KAAMC,EAAKD,EAAI,MAAM,GAAI8C,EAAS9C,EAAI,MAAM,YACtD,OAAOC,EAAG,UAAW,CAAE,YAAa,uBAAwB,MAAO,CAAE,+BAAgC6C,EAAO,MAAM,EAAI,MAAO,CAAE,GAAMA,EAAO,OAAQ,kBAAmB,GAAGA,EAAO,MAAM,SAAS,CAAE,EAAI,CAAC7C,EAAG,KAAM,CAAE,YAAa,6BAA8B,MAAO,CAAE,GAAM,GAAG6C,EAAO,MAAM,SAAS,GAAM,CAAC9C,EAAI,GAAG,IAAMA,EAAI,GAAGA,EAAI,IAAI,EAAI,GAAG,CAAC,CAAC,EAAGC,EAAG,MAAO,CAAE,YAAa,mCAAmC,EAAI,CAACD,EAAI,GAAG,IAAMA,EAAI,GAAGA,EAAI,WAAW,EAAI,GAAG,CAAC,CAAC,EAAGC,EAAG,MAAO,CAAE,YAAa,iCAAmC,CAACD,EAAI,GAAG,SAAS,CAAC,EAAG,CAAC,EAAGA,EAAI,GAAE,CAAE,EAAG,CAAC,CACviB,EACIE,GAAuB,CAAA,EACvBC,GAAgCC,EAClCN,GACAC,GACAG,GACA,GACA,KACA,UACF,EACA,MAAM6C,GAAuB5C,GAAc,QCjC3C6C,GAAA,CACA,KAAA,wBAEA,WAAA,CACA,sBAAAC,EAAA,EAGA,SAAA,CACA,eAAA,CACA,OAAA,KAAA,OAAA,MAAA,WAAA,aACA,CAAA,EAGA,QAAA,CACA,cAAAC,EAAA,CACA,KAAA,OAAA,SAAA,mBAAA,CAAA,IAAA,gBAAA,MAAAA,EAAA,CACA,CAAA,CAEA,sSCNAC,GAAAzB,EAAA,CACA,KAAA,+BAEA,WAAA,CACA,SAAA0B,EAEA,cAAAC,CAAA,EAGA,MAAA,CAAA,gBAAA,EAEA,MAAA,CACA,MAAA,CACA,YAAAC,EAAA,CAEA,EAEA,SAAA,CACA,gBAAA,CACA,OAAA,KAAA,OAAA,MAAA,WAAA,cACA,EAEA,qBAAA,CACA,OAAA,KAAA,OAAA,MAAA,WAAA,mBACA,EAEA,uCAAA,CACA,MAAAC,EAAA,KAAA,eAAA,QAAA,OAAA,EAAA,EAMA,OALA,KAAA,oBAAA,KAAAC,GAAA,CACA,MAAAC,EAAAD,EAAA,QAAA,OAAA,EAAA,EACA,OAAAD,IAAAE,GACAF,EAAA,WAAAE,EAAA,GAAA,CACA,CAAA,CAEA,CAAA,EAGA,QAAA,CACA,2BAAAC,GAAA,UAAA,CACA,KAAA,mBAAA,CACA,CAAA,EAEA,MAAA,oBAAA,CACA,MAAAC,EAAA,MAAA,KAAA,eAAAC,EAAA,SAAA,mDAAA,CAAA,EACA,KAAA,mBAAAD,CAAA,CACA,EAEA,MAAA,eAAAE,EAAA,CAaA,OAZAC,GAAAD,CAAA,EACA,eAAA,EAAA,EACA,kBAAA,sBAAA,EACA,mBACA,QAAA,KAAA,cAAA,EACA,UAAA,CACA,MAAAD,EAAA,SAAA,aAAA,EACA,QAAA,UACA,SAAAG,GAAA1C,EAAA,MAAA,SAAA,CAAA,MAAA0C,EAAA,CAAA,CACA,EACA,MAAA,EAEA,KAAA,CACA,EAEA,mBAAAC,EAAA,CACA,KAAA,OAAA,SAAA,mBAAA,CAAA,IAAA,iBAAA,MAAAA,EAAA,EACA,KAAA,MAAA,iBAAA,KAAA,qCAAA,CACA,EAAA,EAEAJ,CAAA,CAEA,CAAA,+dC/CAK,GAAA,CACA,KAAA,iBAEA,WAAA,CACA,oBAAAC,GACA,qBAAAnB,GACA,WAAAoB,GACA,sBAAAC,GACA,8BAAAC,EACA,6BAAAC,EAAA,EAGA,MAAA,CACA,KAAA,CACA,KAAA,QACA,QAAA,EAAA,CACA,EAGA,MAAA,CACA,MAAA,CACA,mBAAA,EAAA,CAEA,EAEA,SAAA,CACA,gBAAA,CACA,OAAA,KAAA,OAAA,MAAA,WAAA,cACA,EAEA,qBAAA,CACA,OAAA,KAAA,OAAA,MAAA,WAAA,mBACA,EAEA,uCAAA,CACA,MAAAf,EAAA,KAAA,eAAA,QAAA,OAAA,EAAA,EAMA,OALA,KAAA,oBAAA,KAAAC,GAAA,CACA,MAAAC,EAAAD,EAAA,QAAA,OAAA,EAAA,EACA,OAAAD,IAAAE,GACAF,EAAA,WAAAE,EAAA,GAAA,CACA,CAAA,CAEA,CAAA,EAGA,QAAA,CAGA,SAAA,CACA,KAAA,MAAA,cAAA,EAAA,CACA,EAEA,oBAAAc,EAAA,CACA,KAAA,mBAAA,CAAAA,CACA,EAAA,EAEAX,CAAA,CAEA,20CCvGMY,EAAkBC,EAAU,SAAU,kBAAmB,EAAK,EC2NpE3E,GAAA,CACA,KAAA,YACA,WAAA,CACA,mBAAA4E,GACA,0BAAAC,GACA,WAAAC,GACA,cAAAC,GACA,qBAAAC,GACA,OAAAC,GACA,cAAAC,GACA,aAAAC,GACA,oBAAAC,GACA,OAAAC,GACA,cAAA9B,EACA,cAAA+B,GACA,qBAAAC,GACA,UAAAC,GAAA,aACAC,GACA,aAAAC,GACA,oBAAAC,GACA,KAAAC,GACA,YAAAC,GACA,IAAAC,GACA,WAAAC,GACA,UAAAC,GACA,aAAAC,GACA,QAAAC,GACA,WAAAC,GACA,UAAAC,GACA,iBAAAC,GACA,aAAAC,EACA,gBAAA3E,GACA,oBAAA4E,GACA,SAAAjD,EACA,UAAAkD,EACA,eAAAC,GACA,mBAAAC,GACA,qBAAAC,EAAA,EAGA,OAAA,CACA,MAAAC,EAAAC,EAAA,EACA,CAAA,gBAAAC,CAAA,EAAAC,EAAAH,CAAA,EAEA,MAAA,CACA,gBAAAE,CAAA,CAEA,EAEA,MAAA,CACA,MAAA,CACA,eAAAE,EACA,eAAAC,EACA,iBAAAC,EAAA,iBACAC,EAEA,sBAAAC,MAAA,KACA,GACAA,IAAA,SAAAC,GAAAC,EAEA,oBAAAF,EAAA,IAAA,KACA,GACAA,EAAA,EAAA,SAAAzC,EAAA,SAAA,sBAAA,EAAA,GAAA0C,GAAAE,EAEA,eAAA,EAAA,CAEA,EAEA,SAAA,CACA,gBAAA,CACA,MAAA,CAAA,YAAA,SAAA,QAAA,EAAA,SAAA,KAAA,OAAA,MAAA,MAAA,MAAA,EAAA,CACA,CAAA,EAGA,MAAA,aAAA,CAEA,MAAAC,EAAA7C,EAAA,SAAA,gBAAA,CAAA,CAAA,EACA,KAAA,OAAA,SAAA,kBAAA6C,CAAA,EACAjG,EAAA,MAAA,qCAAA,CAAA,MAAAiG,CAAA,CAAA,EAEA,kBAAA,UAEA,OAAA,iBAAA,OAAA,IAAA,CACA,UAAA,cAAA,SAAAC,EAAA,iCAAA,CAAA,EAAA,CACA,UAAA,EAAA,CACA,EAAA,CACA,MAAAA,EAAA,cAAA,CAAA,CACA,EAAA,KAAAC,GAAA,CACAnG,EAAA,MAAA,kBAAA,CAAA,aAAAmG,CAAA,CAAA,CACA,CAAA,EAAA,MAAAC,GAAA,CACApG,EAAA,MAAA,2BAAA,CAAA,kBAAAoG,CAAA,CAAA,CACA,CAAA,CACA,CAAA,EAEApG,EAAA,MAAA,gDAAA,CAEA,EAEA,eAAA,CACA,OAAA,oBAAA,OAAA,IAAA,CACA,UAAA,cAAA,SAAAkG,EAAA,iCAAA,CAAA,EAAA,CACA,UAAA,EAAA,CACA,CAAA,CACA,CAAA,CACA,EAEA,QAAA,CACA,cAAA,CACA,KAAA,eAAA,EACA,EAEA,aAAAG,EAAA,CACA,KAAA,gBAAAA,EAAA,QAAA,EAAA,KAAAA,EAAA,KAAA,CACA,EAEA,eAAAA,EAAA,CACA,MAAAC,EAAA,KAAA,gBAAAD,EAAA,QAAA,EAAA,QAAAA,EAAA,KAAA,EAEAC,IAAA,IACA,KAAA,gBAAAD,EAAA,QAAA,EAAA,OAAAC,EAAA,CAAA,CAEA,EAAA,EAEA/D,CAAA,CAEA,4zJCjVAgE,EAAAA,KAAKC,EAAOC,CAAM,EAElBvH,EAAI,UAAU,EAAIwH,EAClBxH,EAAI,UAAU,EAAIyH,EAElBC,EAAoB,yBAAyB,EAC7CA,EAAoB,8BAA8B,EAClDA,EAAoB,sBAAsB,EAC1CA,EAAoB,uCAAuC,EAE3D1H,EAAI,IAAI2H,CAAc,EAEP,IAAI3H,EAAI,CACtB,GAAI,WACJ,KAAM,aACN,OAAAuH,EAAA,MACAD,EACA,MAAOM,EAAA,EACP,OAASC,GAAMA,EAAEC,EAAS,CAC3B,CAAC","x_google_ignoreList":[0,1,2]} \ No newline at end of file +{"version":3,"file":"photos-main.mjs","sources":["../node_modules/@nextcloud/vue/dist/Components/NcAppNavigationList.mjs","../node_modules/@nextcloud/vue/dist/chunks/NcAppNavigation-DgekTp_z.mjs","../node_modules/@nextcloud/vue/dist/chunks/NcAppSettingsSection-Cq1VIzMR.mjs","../src/components/Settings/CroppedLayoutSettings.vue","../src/components/Settings/PhotosUploadLocationSettings.vue","../src/components/Settings/SettingsDialog.vue","../src/services/IsAppStoreEnabled.ts","../src/PhotosApp.vue","../src/main.ts"],"sourcesContent":["import '../assets/NcAppNavigationList-DnKj0-Zq.css';\nimport { n as normalizeComponent } from \"../chunks/_plugin-vue2_normalizer-DU4iP6Vu.mjs\";\nconst _sfc_main = {\n name: \"NcAppNavigationList\"\n};\nvar _sfc_render = function render() {\n var _vm = this, _c = _vm._self._c;\n return _c(\"ul\", { staticClass: \"app-navigation-list\" }, [_vm._t(\"default\")], 2);\n};\nvar _sfc_staticRenderFns = [];\nvar __component__ = /* @__PURE__ */ normalizeComponent(\n _sfc_main,\n _sfc_render,\n _sfc_staticRenderFns,\n false,\n null,\n \"058e6060\"\n);\nconst NcAppNavigationList = __component__.exports;\nexport {\n NcAppNavigationList as default\n};\n//# sourceMappingURL=NcAppNavigationList.mjs.map\n","import '../assets/NcAppNavigation-Dbpqdigp.css';\nimport { emit, unsubscribe, subscribe } from \"@nextcloud/event-bus\";\nimport { createFocusTrap } from \"focus-trap\";\nimport { tabbable } from \"tabbable\";\nimport Vue from \"vue\";\nimport { useHotKey } from \"../Composables/useHotKey.mjs\";\nimport { useIsMobile } from \"../Composables/useIsMobile.mjs\";\nimport { g as getTrapStack } from \"./focusTrap-HJQ4pqHV.mjs\";\nimport { l as logger } from \"./logger-D3RVzcfQ.mjs\";\nimport NcAppNavigationList from \"../Components/NcAppNavigationList.mjs\";\nimport { N as NcAppNavigationToggle } from \"./NcAppNavigationToggle-B0N05AxP.mjs\";\nimport { n as normalizeComponent } from \"./_plugin-vue2_normalizer-DU4iP6Vu.mjs\";\nconst _sfc_main = {\n name: \"NcAppNavigation\",\n components: {\n NcAppNavigationList,\n NcAppNavigationToggle\n },\n // Injected from NcContent\n inject: {\n setHasAppNavigation: {\n default: () => () => Vue.util.warn(\"NcAppNavigation is not mounted inside NcContent, this is probably an error.\"),\n from: \"NcContent:setHasAppNavigation\"\n }\n },\n props: {\n /**\n * The aria label to describe the navigation\n */\n ariaLabel: {\n type: String,\n default: \"\"\n },\n /**\n * aria-labelledby attribute to describe the navigation\n */\n ariaLabelledby: {\n type: String,\n default: \"\"\n }\n },\n setup() {\n return {\n isMobile: useIsMobile()\n };\n },\n data() {\n return {\n open: !this.isMobile,\n focusTrap: null\n };\n },\n watch: {\n isMobile() {\n this.open = !this.isMobile;\n this.toggleFocusTrap();\n },\n open() {\n this.toggleFocusTrap();\n }\n },\n mounted() {\n this.setHasAppNavigation(true);\n subscribe(\"toggle-navigation\", this.toggleNavigationByEventBus);\n emit(\"navigation-toggled\", {\n open: this.open\n });\n this.focusTrap = createFocusTrap(this.$refs.appNavigationContainer, {\n allowOutsideClick: true,\n fallbackFocus: this.$refs.appNavigationContainer,\n trapStack: getTrapStack(),\n escapeDeactivates: false\n });\n this.toggleFocusTrap();\n useHotKey(\"n\", this.onKeyDown, {\n prevent: true,\n stop: true\n });\n },\n unmounted() {\n this.setHasAppNavigation(false);\n unsubscribe(\"toggle-navigation\", this.toggleNavigationByEventBus);\n this.focusTrap.deactivate();\n },\n methods: {\n /**\n * Toggle the navigation\n *\n * @param {boolean} [state] set the state instead of inverting the current one\n */\n async toggleNavigation(state) {\n if (this.open === state) {\n emit(\"navigation-toggled\", {\n open: this.open\n });\n return;\n }\n this.open = typeof state === \"undefined\" ? !this.open : state;\n const bodyStyles = getComputedStyle(document.body);\n const animationLength = parseInt(bodyStyles.getPropertyValue(\"--animation-quick\")) || 100;\n if (this.open) {\n await this.$nextTick();\n this.focusFirstElement();\n }\n setTimeout(() => {\n emit(\"navigation-toggled\", {\n open: this.open\n });\n }, 1.5 * animationLength);\n },\n toggleNavigationByEventBus({ open }) {\n this.toggleNavigation(open);\n },\n /**\n * Activate focus trap if it is currently needed, otherwise deactivate\n */\n toggleFocusTrap() {\n if (this.isMobile && this.open) {\n this.focusTrap.activate();\n } else {\n this.focusTrap.deactivate();\n }\n },\n handleEsc() {\n if (this.isMobile && this.open) {\n this.toggleNavigation(false);\n }\n },\n focusFirstElement() {\n const element = tabbable(this.$refs.appNavigationContainer)[0];\n if (element) {\n element.focus();\n logger.debug(\"Focusing first element in the navigation\", { element });\n }\n },\n onKeyDown(event) {\n if (event.key === \"n\") {\n if (!this.open) {\n this.toggleNavigation(true);\n return;\n }\n if (this.isFocusWithinNavigation()) {\n this.toggleNavigation(false);\n }\n }\n },\n isFocusWithinNavigation() {\n const activeElement = document.activeElement;\n return this.$refs.appNavigationContainer?.contains(activeElement);\n }\n }\n};\nvar _sfc_render = function render() {\n var _vm = this, _c = _vm._self._c;\n return _c(\"div\", { ref: \"appNavigationContainer\", staticClass: \"app-navigation\", class: { \"app-navigation--close\": !_vm.open } }, [_c(\"nav\", { staticClass: \"app-navigation__content\", attrs: { \"id\": \"app-navigation-vue\", \"aria-hidden\": _vm.open ? \"false\" : \"true\", \"aria-label\": _vm.ariaLabel || void 0, \"aria-labelledby\": _vm.ariaLabelledby || void 0, \"inert\": !_vm.open || void 0 }, on: { \"keydown\": function($event) {\n if (!$event.type.indexOf(\"key\") && _vm._k($event.keyCode, \"esc\", 27, $event.key, [\"Esc\", \"Escape\"])) return null;\n return _vm.handleEsc.apply(null, arguments);\n } } }, [_c(\"div\", { staticClass: \"app-navigation__search\" }, [_vm._t(\"search\")], 2), _c(\"div\", { staticClass: \"app-navigation__body\", class: { \"app-navigation__body--no-list\": !_vm.$scopedSlots.list } }, [_vm._t(\"default\")], 2), _vm.$scopedSlots.list ? _c(\"NcAppNavigationList\", { staticClass: \"app-navigation__list\" }, [_vm._t(\"list\")], 2) : _vm._e(), _vm._t(\"footer\")], 2), _c(\"NcAppNavigationToggle\", { attrs: { \"open\": _vm.open }, on: { \"update:open\": _vm.toggleNavigation } })], 1);\n};\nvar _sfc_staticRenderFns = [];\nvar __component__ = /* @__PURE__ */ normalizeComponent(\n _sfc_main,\n _sfc_render,\n _sfc_staticRenderFns,\n false,\n null,\n \"119f2aad\"\n);\nconst NcAppNavigation = __component__.exports;\nexport {\n NcAppNavigation as N\n};\n//# sourceMappingURL=NcAppNavigation-DgekTp_z.mjs.map\n","import '../assets/NcAppSettingsSection-Yg4NYCih.css';\nimport { defineComponent, useSlots, inject, computed, watch, onMounted, onBeforeUnmount } from \"vue\";\nimport { l as logger } from \"./logger-D3RVzcfQ.mjs\";\nimport { u as useAppSettingsDialog, A as APP_SETTINGS_LEGACY_DESIGN_KEY } from \"./useAppSettingsDialog-DbtEkXa4.mjs\";\nimport { n as normalizeComponent } from \"./_plugin-vue2_normalizer-DU4iP6Vu.mjs\";\nconst _sfc_main = /* @__PURE__ */ defineComponent({\n __name: \"NcAppSettingsSection\",\n props: {\n name: null,\n description: null,\n id: null,\n order: null\n },\n setup(__props) {\n const props = __props;\n const slots = useSlots();\n const { registerSection, unregisterSection } = useAppSettingsDialog();\n const legacy = inject(APP_SETTINGS_LEGACY_DESIGN_KEY);\n const htmlId = computed(() => \"settings-section_\" + props.id);\n watch(() => props.id, () => {\n if (!/^[a-z0-9\\-_]+$/.test(props.id)) {\n logger.warn(`Invalid id prop: ${props.id}. Only alphanumeric, dash and underscore are allowed.`);\n }\n }, { immediate: true });\n watch([() => props.id, () => props.name, () => props.order], ([newId, newName, newOrder], [oldId, ,]) => {\n unregisterSection(oldId);\n registerSection(newId, newName, newOrder, slots?.icon?.());\n });\n onMounted(() => {\n registerSection(props.id, props.name, props.order, slots?.icon?.());\n });\n onBeforeUnmount(() => {\n unregisterSection(props.id);\n });\n return { __sfc: true, props, slots, registerSection, unregisterSection, legacy, htmlId };\n }\n});\nvar _sfc_render = function render() {\n var _vm = this, _c = _vm._self._c, _setup = _vm._self._setupProxy;\n return _c(\"section\", { staticClass: \"app-settings-section\", class: { \"app-settings-section__legacy\": _setup.legacy }, attrs: { \"id\": _setup.htmlId, \"aria-labelledby\": `${_setup.htmlId}--label` } }, [_c(\"h3\", { staticClass: \"app-settings-section__name\", attrs: { \"id\": `${_setup.htmlId}--label` } }, [_vm._v(\" \" + _vm._s(_vm.name) + \" \")]), _c(\"div\", { staticClass: \"app-settings-section__description\" }, [_vm._v(\" \" + _vm._s(_vm.description) + \" \")]), _c(\"div\", { staticClass: \"app-settings-section__content\" }, [_vm._t(\"default\")], 2), _vm._e()], 2);\n};\nvar _sfc_staticRenderFns = [];\nvar __component__ = /* @__PURE__ */ normalizeComponent(\n _sfc_main,\n _sfc_render,\n _sfc_staticRenderFns,\n false,\n null,\n \"06cd755d\"\n);\nconst NcAppSettingsSection = __component__.exports;\nexport {\n NcAppSettingsSection as N\n};\n//# sourceMappingURL=NcAppSettingsSection-Cq1VIzMR.mjs.map\n","\n\n\n\n\n","\n\n\n\n\n\n\n","\n\n\n\n\n\n\n","/**\n * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport { loadState } from '@nextcloud/initial-state'\n\nconst appStoreEnabled = loadState('photos', 'appStoreEnabled', false) as boolean\nexport default appStoreEnabled\n","\n\n\n\n\n\n\n","/**\n * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport { registerDavProperty } from '@nextcloud/files/dav'\nimport { translate, translatePlural } from '@nextcloud/l10n'\nimport { createPinia, PiniaVuePlugin } from 'pinia'\nimport Vue from 'vue'\nimport { sync } from 'vuex-router-sync'\nimport PhotosApp from './PhotosApp.vue'\nimport router from './router/index.js'\nimport store from './store/index.js'\n\nsync(store, router)\n\nVue.prototype.t = translate\nVue.prototype.n = translatePlural\n\nregisterDavProperty('nc:metadata-photos-size')\nregisterDavProperty('nc:metadata-files-live-photo')\nregisterDavProperty('nc:metadata-blurhash')\nregisterDavProperty('nc:metadata-photos-original_date_time')\n\nVue.use(PiniaVuePlugin)\n\nexport default new Vue({\n\tel: '#content',\n\tname: 'PhotosRoot',\n\trouter,\n\tstore,\n\tpinia: createPinia(),\n\trender: (h) => h(PhotosApp),\n})\n"],"names":["_sfc_main","_sfc_render","_sfc_staticRenderFns","__component__","render","t","logger","ImageOutline","areTagsInstalled","isAppStoreEnabled","isMapsInstalled","isRecognizeInstalled","sync","store"],"mappings":"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","x_google_ignoreList":[0,1,2]} \ No newline at end of file diff --git a/js/photos-public.mjs b/js/photos-public.mjs index d9f96a4648..d0ddae8a21 100644 --- a/js/photos-public.mjs +++ b/js/photos-public.mjs @@ -1,2 +1,71 @@ -import{g as r,t as i,V as s,c as p}from"./vue.runtime.esm-DCKfRL7V.chunk.mjs";import{N as l,b as c,v as d,i as v,s as m,c as h,r as n}from"./video-DpTSoI-p.chunk.mjs";import{l as t,p as a}from"./index-CUpYykB9.chunk.mjs";import{n as u}from"./icons-BRqI-hCR.chunk.mjs";import"./index-H-n78F4h.chunk.mjs";import"./preload-helper-DxYC2qmj.chunk.mjs";const g={name:"PhotosAppPublic",components:{NcAppContent:c,NcContent:l},data(){return{svgplaceholder:m,imgplaceholder:v,videoplaceholder:d}},async beforeMount(){"serviceWorker"in navigator?window.addEventListener("load",async()=>{try{const e=r("/apps/photos/service-worker.js",{},{noRewrite:!0}),o=await navigator.serviceWorker.register(e,{scope:r("/apps/photos")});t.debug("SW registered: ",{registration:o})}catch(e){t.error("SW registration failed: ",{error:e})}}):t.debug("Service Worker is not enabled on this browser.")},beforeDestroy(){window.removeEventListener("load",()=>{navigator.serviceWorker.register(r("/apps/photos/service-worker.js",{},{noRewrite:!0}))})}};var w=function(){var e=this,o=e._self._c;return o("NcContent",{attrs:{"app-name":"photos"}},[o("input",{attrs:{id:"isPublic",type:"hidden",name:"isPublic",value:"1"}}),o("NcAppContent",[o("router-view"),o("span",{staticClass:"hidden-visually",attrs:{role:"none"},domProps:{innerHTML:e._s(e.svgplaceholder)}}),o("span",{staticClass:"hidden-visually",attrs:{role:"none"},domProps:{innerHTML:e._s(e.imgplaceholder)}}),o("span",{staticClass:"hidden-visually",attrs:{role:"none"},domProps:{innerHTML:e._s(e.videoplaceholder)}})],1)],1)},y=[],b=u(g,w,y,!1,null,null);const f=b.exports;h.sync(a,n),s.prototype.t=i,s.prototype.n=p,new s({el:"#content",name:"PhotosRoot",router:n,store:a,render:e=>e(f)}); +const appName = "photos"; +const appVersion = "5.0.2"; +import { g as generateUrl, t as translate, V as Vue, c as translatePlural } from "./vue.runtime.esm-D0MRZEe4.chunk.mjs"; +import { N as NcContent, b as NcAppContent, v as videoplaceholder, i as imgplaceholder, s as svgplaceholder, c as vuexRouterSyncExports, r as router } from "./video-Bg0FISQX.chunk.mjs"; +import { l as logger, p as photosStore } from "./index-CZNqUxm0.chunk.mjs"; +import { n as normalizeComponent } from "./icons-DpGfY1yM.chunk.mjs"; +import "./index-CEGJzzBP.chunk.mjs"; +import "./preload-helper-BH8-nKqv.chunk.mjs"; +const _sfc_main = { + name: "PhotosAppPublic", + components: { + NcAppContent, + NcContent + }, + data() { + return { + svgplaceholder, + imgplaceholder, + videoplaceholder + }; + }, + async beforeMount() { + if ("serviceWorker" in navigator) { + window.addEventListener("load", async () => { + try { + const url = generateUrl("/apps/photos/service-worker.js", {}, { noRewrite: true }); + const registration = await navigator.serviceWorker.register(url, { scope: generateUrl("/apps/photos") }); + logger.debug("SW registered: ", { registration }); + } catch (error) { + logger.error("SW registration failed: ", { error }); + } + }); + } else { + logger.debug("Service Worker is not enabled on this browser."); + } + }, + beforeDestroy() { + window.removeEventListener("load", () => { + navigator.serviceWorker.register(generateUrl("/apps/photos/service-worker.js", {}, { + noRewrite: true + })); + }); + } +}; +var _sfc_render = function render() { + var _vm = this, _c = _vm._self._c; + return _c("NcContent", { attrs: { "app-name": "photos" } }, [_c("input", { attrs: { "id": "isPublic", "type": "hidden", "name": "isPublic", "value": "1" } }), _c("NcAppContent", [_c("router-view"), _c("span", { staticClass: "hidden-visually", attrs: { "role": "none" }, domProps: { "innerHTML": _vm._s(_vm.svgplaceholder) } }), _c("span", { staticClass: "hidden-visually", attrs: { "role": "none" }, domProps: { "innerHTML": _vm._s(_vm.imgplaceholder) } }), _c("span", { staticClass: "hidden-visually", attrs: { "role": "none" }, domProps: { "innerHTML": _vm._s(_vm.videoplaceholder) } })], 1)], 1); +}; +var _sfc_staticRenderFns = []; +_sfc_render._withStripped = true; +var __component__ = /* @__PURE__ */ normalizeComponent( + _sfc_main, + _sfc_render, + _sfc_staticRenderFns, + false, + null, + null +); +__component__.options.__file = "/var/www/html/customapps/photos/src/PhotosAppPublic.vue"; +const PhotosAppPublic = __component__.exports; +vuexRouterSyncExports.sync(photosStore, router); +Vue.prototype.t = translate; +Vue.prototype.n = translatePlural; +new Vue({ + el: "#content", + name: "PhotosRoot", + router, + store: photosStore, + render: (h) => h(PhotosAppPublic) +}); //# sourceMappingURL=photos-public.mjs.map diff --git a/js/photos-public.mjs.license b/js/photos-public.mjs.license deleted file mode 100644 index c25829ba48..0000000000 --- a/js/photos-public.mjs.license +++ /dev/null @@ -1,7 +0,0 @@ -SPDX-License-Identifier: AGPL-3.0-or-later -SPDX-FileCopyrightText: John Molakvoæ - -This file is generated from multiple sources. Included packages: -- photos - - version: 5.0.0-dev.1 - - license: AGPL-3.0-or-later diff --git a/js/photos-public.mjs.map b/js/photos-public.mjs.map index a91acaee7f..aac47bcdfc 100644 --- a/js/photos-public.mjs.map +++ b/js/photos-public.mjs.map @@ -1 +1 @@ -{"version":3,"file":"photos-public.mjs","sources":["../src/PhotosAppPublic.vue","../src/public.ts"],"sourcesContent":["\n\n\n\n\n\n\n","/**\n * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport { translate, translatePlural } from '@nextcloud/l10n'\nimport Vue from 'vue'\nimport { sync } from 'vuex-router-sync'\nimport PhotosAppPublic from './PhotosAppPublic.vue'\nimport router from './router/index.js'\nimport store from './store/index.js'\n\nsync(store, router)\n\nVue.prototype.t = translate\nVue.prototype.n = translatePlural\n\nexport default new Vue({\n\tel: '#content',\n\tname: 'PhotosRoot',\n\trouter,\n\tstore,\n\trender: (h) => h(PhotosAppPublic),\n})\n"],"names":["_sfc_main","NcAppContent","NcContent","svgplaceholder","imgplaceholder","videoplaceholder","url","generateUrl","registration","logger","error","sync","store","router","Vue","translate","translatePlural","h","PhotosAppPublic"],"mappings":"2VAuCA,MAAAA,EAAA,CACA,KAAA,kBACA,WAAA,CACA,aAAAC,EACA,UAAAC,CAAA,EAGA,MAAA,CACA,MAAA,CACA,eAAAC,EACA,eAAAC,EACA,iBAAAC,CAAA,CAEA,EAEA,MAAA,aAAA,CACA,kBAAA,UAEA,OAAA,iBAAA,OAAA,SAAA,CACA,GAAA,CACA,MAAAC,EAAAC,EAAA,iCAAA,CAAA,EAAA,CAAA,UAAA,GAAA,EACAC,EAAA,MAAA,UAAA,cAAA,SAAAF,EAAA,CAAA,MAAAC,EAAA,cAAA,EAAA,EACAE,EAAA,MAAA,kBAAA,CAAA,aAAAD,CAAA,CAAA,CACA,OAAAE,EAAA,CACAD,EAAA,MAAA,2BAAA,CAAA,MAAAC,CAAA,CAAA,CACA,CACA,CAAA,EAEAD,EAAA,MAAA,gDAAA,CAEA,EAEA,eAAA,CACA,OAAA,oBAAA,OAAA,IAAA,CACA,UAAA,cAAA,SAAAF,EAAA,iCAAA,CAAA,EAAA,CACA,UAAA,EAAA,CACA,CAAA,CACA,CAAA,CACA,CACA,qkBClEAI,EAAAA,KAAKC,EAAOC,CAAM,EAElBC,EAAI,UAAU,EAAIC,EAClBD,EAAI,UAAU,EAAIE,EAEH,IAAIF,EAAI,CACtB,GAAI,WACJ,KAAM,aACN,OAAAD,EAAA,MACAD,EACA,OAASK,GAAMA,EAAEC,CAAe,CACjC,CAAC"} \ No newline at end of file +{"version":3,"file":"photos-public.mjs","sources":["../src/PhotosAppPublic.vue","../src/public.ts"],"sourcesContent":["\n\n\n\n\n\n\n","/**\n * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport { translate, translatePlural } from '@nextcloud/l10n'\nimport Vue from 'vue'\nimport { sync } from 'vuex-router-sync'\nimport PhotosAppPublic from './PhotosAppPublic.vue'\nimport router from './router/index.js'\nimport store from './store/index.js'\n\nsync(store, router)\n\nVue.prototype.t = translate\nVue.prototype.n = translatePlural\n\nexport default new Vue({\n\tel: '#content',\n\tname: 'PhotosRoot',\n\trouter,\n\tstore,\n\trender: (h) => h(PhotosAppPublic),\n})\n"],"names":["sync","store"],"mappings":";;;;;;;;AAuCA,MAAA,YAAA;AAAA,EACA,MAAA;AAAA,EACA,YAAA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAAA,EAGA,OAAA;AACA,WAAA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EAEA;AAAA,EAEA,MAAA,cAAA;AACA,QAAA,mBAAA,WAAA;AAEA,aAAA,iBAAA,QAAA,YAAA;AACA,YAAA;AACA,gBAAA,MAAA,YAAA,kCAAA,CAAA,GAAA,EAAA,WAAA,MAAA;AACA,gBAAA,eAAA,MAAA,UAAA,cAAA,SAAA,KAAA,EAAA,OAAA,YAAA,cAAA,GAAA;AACA,iBAAA,MAAA,mBAAA,EAAA,aAAA,CAAA;AAAA,QACA,SAAA,OAAA;AACA,iBAAA,MAAA,4BAAA,EAAA,MAAA,CAAA;AAAA,QACA;AAAA,MACA,CAAA;AAAA,IACA,OAAA;AACA,aAAA,MAAA,gDAAA;AAAA,IACA;AAAA,EACA;AAAA,EAEA,gBAAA;AACA,WAAA,oBAAA,QAAA,MAAA;AACA,gBAAA,cAAA,SAAA,YAAA,kCAAA,CAAA,GAAA;AAAA,QACA,WAAA;AAAA,MAAA,CACA,CAAA;AAAA,IACA,CAAA;AAAA,EACA;AACA;;;;;;;;;;;;;;;;;AClEAA,sBAAAA,KAAKC,aAAO,MAAM;AAElB,IAAI,UAAU,IAAI;AAClB,IAAI,UAAU,IAAI;AAEH,IAAI,IAAI;AAAA,EACtB,IAAI;AAAA,EACJ,MAAM;AAAA,EACN;AAAA,EAAA,OACAA;AAAAA,EACA,QAAQ,CAAC,MAAM,EAAE,eAAe;AACjC,CAAC;"} \ No newline at end of file diff --git a/js/photos-service-worker.js b/js/photos-service-worker.js index 633f474751..a3d0b1d50b 100644 --- a/js/photos-service-worker.js +++ b/js/photos-service-worker.js @@ -1 +1,3115 @@ -try{self["workbox:core:7.3.0"]&&_()}catch(t){}const t=(t,...e)=>{let s=t;return e.length>0&&(s+=` :: ${JSON.stringify(e)}`),s};class e extends Error{constructor(e,s){super(t(e,s)),this.name=e,this.details=s}}try{self["workbox:routing:7.3.0"]&&_()}catch(t){}const s=t=>t&&"object"==typeof t?t:{handle:t};class n{constructor(t,e,n="GET"){this.handler=s(e),this.match=t,this.method=n}setCatchHandler(t){this.catchHandler=s(t)}}class r extends n{constructor(t,e,s){super(({url:e})=>{const s=t.exec(e.href);if(s&&(e.origin===location.origin||0===s.index))return s.slice(1)},e,s)}}class i{constructor(){this.t=new Map,this.i=new Map}get routes(){return this.t}addFetchListener(){self.addEventListener("fetch",t=>{const{request:e}=t,s=this.handleRequest({request:e,event:t});s&&t.respondWith(s)})}addCacheListener(){self.addEventListener("message",t=>{if(t.data&&"CACHE_URLS"===t.data.type){const{payload:e}=t.data,s=Promise.all(e.urlsToCache.map(e=>{"string"==typeof e&&(e=[e]);const s=new Request(...e);return this.handleRequest({request:s,event:t})}));t.waitUntil(s),t.ports&&t.ports[0]&&s.then(()=>t.ports[0].postMessage(!0))}})}handleRequest({request:t,event:e}){const s=new URL(t.url,location.href);if(!s.protocol.startsWith("http"))return;const n=s.origin===location.origin,{params:r,route:i}=this.findMatchingRoute({event:e,request:t,sameOrigin:n,url:s});let a=i&&i.handler;const o=t.method;if(!a&&this.i.has(o)&&(a=this.i.get(o)),!a)return;let c;try{c=a.handle({url:s,request:t,event:e,params:r})}catch(t){c=Promise.reject(t)}const h=i&&i.catchHandler;return c instanceof Promise&&(this.o||h)&&(c=c.catch(async n=>{if(h)try{return await h.handle({url:s,request:t,event:e,params:r})}catch(t){t instanceof Error&&(n=t)}if(this.o)return this.o.handle({url:s,request:t,event:e});throw n})),c}findMatchingRoute({url:t,sameOrigin:e,request:s,event:n}){const r=this.t.get(s.method)||[];for(const i of r){let r;const a=i.match({url:t,sameOrigin:e,request:s,event:n});if(a)return r=a,(Array.isArray(r)&&0===r.length||a.constructor===Object&&0===Object.keys(a).length||"boolean"==typeof a)&&(r=void 0),{route:i,params:r}}return{}}setDefaultHandler(t,e="GET"){this.i.set(e,s(t))}setCatchHandler(t){this.o=s(t)}registerRoute(t){this.t.has(t.method)||this.t.set(t.method,[]),this.t.get(t.method).push(t)}unregisterRoute(t){if(!this.t.has(t.method))throw new e("unregister-route-but-not-found-with-method",{method:t.method});const s=this.t.get(t.method).indexOf(t);if(!(s>-1))throw new e("unregister-route-route-not-registered");this.t.get(t.method).splice(s,1)}}let a;const o=()=>(a||(a=new i,a.addFetchListener(),a.addCacheListener()),a);const c={googleAnalytics:"googleAnalytics",precache:"precache-v2",prefix:"workbox",runtime:"runtime",suffix:"undefined"!=typeof registration?registration.scope:""},h=t=>[c.prefix,t,c.suffix].filter(t=>t&&t.length>0).join("-"),u=t=>t||h(c.runtime);function f(t){t.then(()=>{})}const l=new Set;function w(){return w=Object.assign?Object.assign.bind():function(t){for(var e=1;e(t[e]=s,!0),has:(t,e)=>t instanceof IDBTransaction&&("done"===e||"store"===e)||e in t};function q(t){return t!==IDBDatabase.prototype.transaction||"objectStoreNames"in IDBTransaction.prototype?(p||(p=[IDBCursor.prototype.advance,IDBCursor.prototype.continue,IDBCursor.prototype.continuePrimaryKey])).includes(t)?function(...e){return t.apply(x(this),e),E(m.get(this))}:function(...e){return E(t.apply(x(this),e))}:function(e,...s){const n=t.call(x(this),e,...s);return g.set(n,e.sort?e.sort():[e]),E(n)}}function R(t){return"function"==typeof t?q(t):(t instanceof IDBTransaction&&function(t){if(y.has(t))return;const e=new Promise((e,s)=>{const n=()=>{t.removeEventListener("complete",r),t.removeEventListener("error",i),t.removeEventListener("abort",i)},r=()=>{e(),n()},i=()=>{s(t.error||new DOMException("AbortError","AbortError")),n()};t.addEventListener("complete",r),t.addEventListener("error",i),t.addEventListener("abort",i)});y.set(t,e)}(t),e=t,(d||(d=[IDBDatabase,IDBObjectStore,IDBIndex,IDBCursor,IDBTransaction])).some(t=>e instanceof t)?new Proxy(t,b):t);var e}function E(t){if(t instanceof IDBRequest)return function(t){const e=new Promise((e,s)=>{const n=()=>{t.removeEventListener("success",r),t.removeEventListener("error",i)},r=()=>{e(E(t.result)),n()},i=()=>{s(t.error),n()};t.addEventListener("success",r),t.addEventListener("error",i)});return e.then(e=>{e instanceof IDBCursor&&m.set(e,t)}).catch(()=>{}),D.set(e,t),e}(t);if(v.has(t))return v.get(t);const e=R(t);return e!==t&&(v.set(t,e),D.set(e,t)),e}const x=t=>D.get(t);const I=["get","getKey","getAll","getAllKeys","count"],B=["put","add","delete","clear"],O=new Map;function C(t,e){if(!(t instanceof IDBDatabase)||e in t||"string"!=typeof e)return;if(O.get(e))return O.get(e);const s=e.replace(/FromIndex$/,""),n=e!==s,r=B.includes(s);if(!(s in(n?IDBIndex:IDBObjectStore).prototype)||!r&&!I.includes(s))return;const i=async function(t,...e){const i=this.transaction(t,r?"readwrite":"readonly");let a=i.store;return n&&(a=a.index(e.shift())),(await Promise.all([a[s](...e),r&&i.done]))[0]};return O.set(e,i),i}b=(t=>w({},t,{get:(e,s,n)=>C(e,s)||t.get(e,s,n),has:(e,s)=>!!C(e,s)||t.has(e,s)}))(b);try{self["workbox:expiration:7.3.0"]&&_()}catch(t){}const N="cache-entries",k=t=>{const e=new URL(t,location.href);return e.hash="",e.href};class j{constructor(t){this.h=null,this.u=t}l(t){const e=t.createObjectStore(N,{keyPath:"id"});e.createIndex("cacheName","cacheName",{unique:!1}),e.createIndex("timestamp","timestamp",{unique:!1})}p(t){this.l(t),this.u&&function(t,{blocked:e}={}){const s=indexedDB.deleteDatabase(t);e&&s.addEventListener("blocked",t=>e(t.oldVersion,t)),E(s).then(()=>{})}(this.u)}async setTimestamp(t,e){const s={url:t=k(t),timestamp:e,cacheName:this.u,id:this.m(t)},n=(await this.getDb()).transaction(N,"readwrite",{durability:"relaxed"});await n.store.put(s),await n.done}async getTimestamp(t){const e=await this.getDb(),s=await e.get(N,this.m(t));return null==s?void 0:s.timestamp}async expireEntries(t,e){const s=await this.getDb();let n=await s.transaction(N).store.index("timestamp").openCursor(null,"prev");const r=[];let i=0;for(;n;){const s=n.value;s.cacheName===this.u&&(t&&s.timestamp=e?r.push(n.value):i++),n=await n.continue()}const a=[];for(const t of r)await s.delete(N,t.id),a.push(t.url);return a}m(t){return this.u+"|"+k(t)}async getDb(){return this.h||(this.h=await function(t,e,{blocked:s,upgrade:n,blocking:r,terminated:i}={}){const a=indexedDB.open(t,e),o=E(a);return n&&a.addEventListener("upgradeneeded",t=>{n(E(a.result),t.oldVersion,t.newVersion,E(a.transaction),t)}),s&&a.addEventListener("blocked",t=>s(t.oldVersion,t.newVersion,t)),o.then(t=>{i&&t.addEventListener("close",()=>i()),r&&t.addEventListener("versionchange",t=>r(t.oldVersion,t.newVersion,t))}).catch(()=>{}),o}("workbox-expiration",1,{upgrade:this.p.bind(this)})),this.h}}class M{constructor(t,e={}){this.v=!1,this.D=!1,this.q=e.maxEntries,this.R=e.maxAgeSeconds,this.I=e.matchOptions,this.u=t,this.B=new j(t)}async expireEntries(){if(this.v)return void(this.D=!0);this.v=!0;const t=this.R?Date.now()-1e3*this.R:0,e=await this.B.expireEntries(t,this.q),s=await self.caches.open(this.u);for(const t of e)await s.delete(t,this.I);this.v=!1,this.D&&(this.D=!1,f(this.expireEntries()))}async updateTimestamp(t){await this.B.setTimestamp(t,Date.now())}async isURLExpired(t){if(this.R){const e=await this.B.getTimestamp(t),s=Date.now()-1e3*this.R;return void 0===e||e{this.resolve=t,this.reject=e})}}try{self["workbox:strategies:7.3.0"]&&_()}catch(t){}function A(t){return"string"==typeof t?new Request(t):t}class P{constructor(t,e){this.O={},Object.assign(this,e),this.event=e.event,this.C=t,this.N=new T,this._=[],this.k=[...t.plugins],this.j=new Map;for(const t of this.k)this.j.set(t,{});this.event.waitUntil(this.N.promise)}async fetch(t){const{event:s}=this;let n=A(t);if("navigate"===n.mode&&s instanceof FetchEvent&&s.preloadResponse){const t=await s.preloadResponse;if(t)return t}const r=this.hasCallback("fetchDidFail")?n.clone():null;try{for(const t of this.iterateCallbacks("requestWillFetch"))n=await t({request:n.clone(),event:s})}catch(t){if(t instanceof Error)throw new e("plugin-error-request-will-fetch",{thrownErrorMessage:t.message})}const i=n.clone();try{let t;t=await fetch(n,"navigate"===n.mode?void 0:this.C.fetchOptions);for(const e of this.iterateCallbacks("fetchDidSucceed"))t=await e({event:s,request:i,response:t});return t}catch(t){throw r&&await this.runCallbacks("fetchDidFail",{error:t,event:s,originalRequest:r.clone(),request:i.clone()}),t}}async fetchAndCachePut(t){const e=await this.fetch(t),s=e.clone();return this.waitUntil(this.cachePut(t,s)),e}async cacheMatch(t){const e=A(t);let s;const{cacheName:n,matchOptions:r}=this.C,i=await this.getCacheKey(e,"read"),a=Object.assign(Object.assign({},r),{cacheName:n});s=await caches.match(i,a);for(const t of this.iterateCallbacks("cachedResponseWillBeUsed"))s=await t({cacheName:n,matchOptions:r,cachedResponse:s,request:i,event:this.event})||void 0;return s}async cachePut(t,s){const n=A(t);var r;await(r=0,new Promise(t=>setTimeout(t,r)));const i=await this.getCacheKey(n,"write");if(!s)throw new e("cache-put-with-no-response",{url:(a=i.url,new URL(String(a),location.href).href.replace(new RegExp(`^${location.origin}`),""))});var a;const o=await this.M(s);if(!o)return!1;const{cacheName:c,matchOptions:h}=this.C,u=await self.caches.open(c),f=this.hasCallback("cacheDidUpdate"),w=f?await async function(t,e,s,n){const r=S(e.url,s);if(e.url===r)return t.match(e,n);const i=Object.assign(Object.assign({},n),{ignoreSearch:!0}),a=await t.keys(e,i);for(const e of a)if(r===S(e.url,s))return t.match(e,n)}(u,i.clone(),["__WB_REVISION__"],h):null;try{await u.put(i,f?o.clone():o)}catch(t){if(t instanceof Error)throw"QuotaExceededError"===t.name&&await async function(){for(const t of l)await t()}(),t}for(const t of this.iterateCallbacks("cacheDidUpdate"))await t({cacheName:c,oldResponse:w,newResponse:o.clone(),request:i,event:this.event});return!0}async getCacheKey(t,e){const s=`${t.url} | ${e}`;if(!this.O[s]){let n=t;for(const t of this.iterateCallbacks("cacheKeyWillBeUsed"))n=A(await t({mode:e,request:n,event:this.event,params:this.params}));this.O[s]=n}return this.O[s]}hasCallback(t){for(const e of this.C.plugins)if(t in e)return!0;return!1}async runCallbacks(t,e){for(const s of this.iterateCallbacks(t))await s(e)}*iterateCallbacks(t){for(const e of this.C.plugins)if("function"==typeof e[t]){const s=this.j.get(e),n=n=>{const r=Object.assign(Object.assign({},n),{state:s});return e[t](r)};yield n}}waitUntil(t){return this._.push(t),t}async doneWaiting(){for(;this._.length;){const t=this._.splice(0),e=(await Promise.allSettled(t)).find(t=>"rejected"===t.status);if(e)throw e.reason}}destroy(){this.N.resolve(null)}async M(t){let e=t,s=!1;for(const t of this.iterateCallbacks("cacheWillUpdate"))if(e=await t({request:this.request,response:e,event:this.event})||void 0,s=!0,!e)break;return s||e&&200!==e.status&&(e=void 0),e}}class U{constructor(t={}){this.cacheName=u(t.cacheName),this.plugins=t.plugins||[],this.fetchOptions=t.fetchOptions,this.matchOptions=t.matchOptions}handle(t){const[e]=this.handleAll(t);return e}handleAll(t){t instanceof FetchEvent&&(t={event:t,request:t.request});const e=t.event,s="string"==typeof t.request?new Request(t.request):t.request,n="params"in t?t.params:void 0,r=new P(this,{event:e,request:s,params:n}),i=this.S(r,s,e);return[i,this.T(i,r,s,e)]}async S(t,s,n){let r;await t.runCallbacks("handlerWillStart",{event:n,request:s});try{if(r=await this.A(s,t),!r||"error"===r.type)throw new e("no-response",{url:s.url})}catch(e){if(e instanceof Error)for(const i of t.iterateCallbacks("handlerDidError"))if(r=await i({error:e,event:n,request:s}),r)break;if(!r)throw e}for(const e of t.iterateCallbacks("handlerWillRespond"))r=await e({event:n,request:s,response:r});return r}async T(t,e,s,n){let r,i;try{r=await t}catch(i){}try{await e.runCallbacks("handlerDidRespond",{event:n,request:s,response:r}),await e.doneWaiting()}catch(t){t instanceof Error&&(i=t)}if(await e.runCallbacks("handlerDidComplete",{event:n,request:s,response:r,error:i}),e.destroy(),i)throw i}}self.skipWaiting(),self.addEventListener("activate",()=>self.clients.claim()),function(t,s,i){let a;if("string"==typeof t){const e=new URL(t,location.href);a=new n(({url:t})=>t.href===e.href,s,i)}else if(t instanceof RegExp)a=new r(t,s,i);else if("function"==typeof t)a=new n(t,s,i);else{if(!(t instanceof n))throw new e("unsupported-route-type",{moduleName:"workbox-routing",funcName:"registerRoute",paramName:"capture"});a=t}o().registerRoute(a)}(/^.*\/apps\/photos\/api\/v1\/preview\/.*/,new class extends U{async A(t,s){let n,r=await s.cacheMatch(t);if(!r)try{r=await s.fetchAndCachePut(t)}catch(t){t instanceof Error&&(n=t)}if(!r)throw new e("no-response",{url:t.url,error:n});return r}}({cacheName:"images",plugins:[new class{constructor(t={}){this.cachedResponseWillBeUsed=async({event:t,request:e,cacheName:s,cachedResponse:n})=>{if(!n)return null;const r=this.P(n),i=this.U(s);f(i.expireEntries());const a=i.updateTimestamp(e.url);if(t)try{t.waitUntil(a)}catch(t){}return r?n:null},this.cacheDidUpdate=async({cacheName:t,request:e})=>{const s=this.U(t);await s.updateTimestamp(e.url),await s.expireEntries()},this.W=t,this.R=t.maxAgeSeconds,this.L=new Map,t.purgeOnQuotaError&&function(t){l.add(t)}(()=>this.deleteCacheAndMetadata())}U(t){if(t===u())throw new e("expire-custom-caches-only");let s=this.L.get(t);return s||(s=new M(t,this.W),this.L.set(t,s)),s}P(t){if(!this.R)return!0;const e=this.F(t);if(null===e)return!0;return e>=Date.now()-1e3*this.R}F(t){if(!t.headers.has("date"))return null;const e=t.headers.get("date"),s=new Date(e).getTime();return isNaN(s)?null:s}async deleteCacheAndMetadata(){for(const[t,e]of this.L)await self.caches.delete(t),await e.delete();this.L=new Map}}({maxAgeSeconds:604800,maxEntries:1e4})]}),"GET"); +// @ts-ignore +try { + self['workbox:core:7.3.0'] && _(); +} catch (e) {} + +/* + Copyright 2019 Google LLC + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +const logger = (() => { + // Don't overwrite this value if it's already set. + // See https://github.com/GoogleChrome/workbox/pull/2284#issuecomment-560470923 + if (!('__WB_DISABLE_DEV_LOGS' in globalThis)) { + self.__WB_DISABLE_DEV_LOGS = false; + } + let inGroup = false; + const methodToColorMap = { + debug: `#7f8c8d`, + log: `#2ecc71`, + warn: `#f39c12`, + error: `#c0392b`, + groupCollapsed: `#3498db`, + groupEnd: null // No colored prefix on groupEnd + }; + const print = function (method, args) { + if (self.__WB_DISABLE_DEV_LOGS) { + return; + } + if (method === 'groupCollapsed') { + // Safari doesn't print all console.groupCollapsed() arguments: + // https://bugs.webkit.org/show_bug.cgi?id=182754 + if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) { + console[method](...args); + return; + } + } + const styles = [`background: ${methodToColorMap[method]}`, `border-radius: 0.5em`, `color: white`, `font-weight: bold`, `padding: 2px 0.5em`]; + // When in a group, the workbox prefix is not displayed. + const logPrefix = inGroup ? [] : ['%cworkbox', styles.join(';')]; + console[method](...logPrefix, ...args); + if (method === 'groupCollapsed') { + inGroup = true; + } + if (method === 'groupEnd') { + inGroup = false; + } + }; + // eslint-disable-next-line @typescript-eslint/ban-types + const api = {}; + const loggerMethods = Object.keys(methodToColorMap); + for (const key of loggerMethods) { + const method = key; + api[method] = (...args) => { + print(method, args); + }; + } + return api; +})(); + +/* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +const messages$1 = { + 'invalid-value': ({ + paramName, + validValueDescription, + value + }) => { + if (!paramName || !validValueDescription) { + throw new Error(`Unexpected input to 'invalid-value' error.`); + } + return `The '${paramName}' parameter was given a value with an ` + `unexpected value. ${validValueDescription} Received a value of ` + `${JSON.stringify(value)}.`; + }, + 'not-an-array': ({ + moduleName, + className, + funcName, + paramName + }) => { + if (!moduleName || !className || !funcName || !paramName) { + throw new Error(`Unexpected input to 'not-an-array' error.`); + } + return `The parameter '${paramName}' passed into ` + `'${moduleName}.${className}.${funcName}()' must be an array.`; + }, + 'incorrect-type': ({ + expectedType, + paramName, + moduleName, + className, + funcName + }) => { + if (!expectedType || !paramName || !moduleName || !funcName) { + throw new Error(`Unexpected input to 'incorrect-type' error.`); + } + const classNameStr = className ? `${className}.` : ''; + return `The parameter '${paramName}' passed into ` + `'${moduleName}.${classNameStr}` + `${funcName}()' must be of type ${expectedType}.`; + }, + 'incorrect-class': ({ + expectedClassName, + paramName, + moduleName, + className, + funcName, + isReturnValueProblem + }) => { + if (!expectedClassName || !moduleName || !funcName) { + throw new Error(`Unexpected input to 'incorrect-class' error.`); + } + const classNameStr = className ? `${className}.` : ''; + if (isReturnValueProblem) { + return `The return value from ` + `'${moduleName}.${classNameStr}${funcName}()' ` + `must be an instance of class ${expectedClassName}.`; + } + return `The parameter '${paramName}' passed into ` + `'${moduleName}.${classNameStr}${funcName}()' ` + `must be an instance of class ${expectedClassName}.`; + }, + 'missing-a-method': ({ + expectedMethod, + paramName, + moduleName, + className, + funcName + }) => { + if (!expectedMethod || !paramName || !moduleName || !className || !funcName) { + throw new Error(`Unexpected input to 'missing-a-method' error.`); + } + return `${moduleName}.${className}.${funcName}() expected the ` + `'${paramName}' parameter to expose a '${expectedMethod}' method.`; + }, + 'add-to-cache-list-unexpected-type': ({ + entry + }) => { + return `An unexpected entry was passed to ` + `'workbox-precaching.PrecacheController.addToCacheList()' The entry ` + `'${JSON.stringify(entry)}' isn't supported. You must supply an array of ` + `strings with one or more characters, objects with a url property or ` + `Request objects.`; + }, + 'add-to-cache-list-conflicting-entries': ({ + firstEntry, + secondEntry + }) => { + if (!firstEntry || !secondEntry) { + throw new Error(`Unexpected input to ` + `'add-to-cache-list-duplicate-entries' error.`); + } + return `Two of the entries passed to ` + `'workbox-precaching.PrecacheController.addToCacheList()' had the URL ` + `${firstEntry} but different revision details. Workbox is ` + `unable to cache and version the asset correctly. Please remove one ` + `of the entries.`; + }, + 'plugin-error-request-will-fetch': ({ + thrownErrorMessage + }) => { + if (!thrownErrorMessage) { + throw new Error(`Unexpected input to ` + `'plugin-error-request-will-fetch', error.`); + } + return `An error was thrown by a plugins 'requestWillFetch()' method. ` + `The thrown error message was: '${thrownErrorMessage}'.`; + }, + 'invalid-cache-name': ({ + cacheNameId, + value + }) => { + if (!cacheNameId) { + throw new Error(`Expected a 'cacheNameId' for error 'invalid-cache-name'`); + } + return `You must provide a name containing at least one character for ` + `setCacheDetails({${cacheNameId}: '...'}). Received a value of ` + `'${JSON.stringify(value)}'`; + }, + 'unregister-route-but-not-found-with-method': ({ + method + }) => { + if (!method) { + throw new Error(`Unexpected input to ` + `'unregister-route-but-not-found-with-method' error.`); + } + return `The route you're trying to unregister was not previously ` + `registered for the method type '${method}'.`; + }, + 'unregister-route-route-not-registered': () => { + return `The route you're trying to unregister was not previously ` + `registered.`; + }, + 'queue-replay-failed': ({ + name + }) => { + return `Replaying the background sync queue '${name}' failed.`; + }, + 'duplicate-queue-name': ({ + name + }) => { + return `The Queue name '${name}' is already being used. ` + `All instances of backgroundSync.Queue must be given unique names.`; + }, + 'expired-test-without-max-age': ({ + methodName, + paramName + }) => { + return `The '${methodName}()' method can only be used when the ` + `'${paramName}' is used in the constructor.`; + }, + 'unsupported-route-type': ({ + moduleName, + className, + funcName, + paramName + }) => { + return `The supplied '${paramName}' parameter was an unsupported type. ` + `Please check the docs for ${moduleName}.${className}.${funcName} for ` + `valid input types.`; + }, + 'not-array-of-class': ({ + value, + expectedClass, + moduleName, + className, + funcName, + paramName + }) => { + return `The supplied '${paramName}' parameter must be an array of ` + `'${expectedClass}' objects. Received '${JSON.stringify(value)},'. ` + `Please check the call to ${moduleName}.${className}.${funcName}() ` + `to fix the issue.`; + }, + 'max-entries-or-age-required': ({ + moduleName, + className, + funcName + }) => { + return `You must define either config.maxEntries or config.maxAgeSeconds` + `in ${moduleName}.${className}.${funcName}`; + }, + 'statuses-or-headers-required': ({ + moduleName, + className, + funcName + }) => { + return `You must define either config.statuses or config.headers` + `in ${moduleName}.${className}.${funcName}`; + }, + 'invalid-string': ({ + moduleName, + funcName, + paramName + }) => { + if (!paramName || !moduleName || !funcName) { + throw new Error(`Unexpected input to 'invalid-string' error.`); + } + return `When using strings, the '${paramName}' parameter must start with ` + `'http' (for cross-origin matches) or '/' (for same-origin matches). ` + `Please see the docs for ${moduleName}.${funcName}() for ` + `more info.`; + }, + 'channel-name-required': () => { + return `You must provide a channelName to construct a ` + `BroadcastCacheUpdate instance.`; + }, + 'invalid-responses-are-same-args': () => { + return `The arguments passed into responsesAreSame() appear to be ` + `invalid. Please ensure valid Responses are used.`; + }, + 'expire-custom-caches-only': () => { + return `You must provide a 'cacheName' property when using the ` + `expiration plugin with a runtime caching strategy.`; + }, + 'unit-must-be-bytes': ({ + normalizedRangeHeader + }) => { + if (!normalizedRangeHeader) { + throw new Error(`Unexpected input to 'unit-must-be-bytes' error.`); + } + return `The 'unit' portion of the Range header must be set to 'bytes'. ` + `The Range header provided was "${normalizedRangeHeader}"`; + }, + 'single-range-only': ({ + normalizedRangeHeader + }) => { + if (!normalizedRangeHeader) { + throw new Error(`Unexpected input to 'single-range-only' error.`); + } + return `Multiple ranges are not supported. Please use a single start ` + `value, and optional end value. The Range header provided was ` + `"${normalizedRangeHeader}"`; + }, + 'invalid-range-values': ({ + normalizedRangeHeader + }) => { + if (!normalizedRangeHeader) { + throw new Error(`Unexpected input to 'invalid-range-values' error.`); + } + return `The Range header is missing both start and end values. At least ` + `one of those values is needed. The Range header provided was ` + `"${normalizedRangeHeader}"`; + }, + 'no-range-header': () => { + return `No Range header was found in the Request provided.`; + }, + 'range-not-satisfiable': ({ + size, + start, + end + }) => { + return `The start (${start}) and end (${end}) values in the Range are ` + `not satisfiable by the cached response, which is ${size} bytes.`; + }, + 'attempt-to-cache-non-get-request': ({ + url, + method + }) => { + return `Unable to cache '${url}' because it is a '${method}' request and ` + `only 'GET' requests can be cached.`; + }, + 'cache-put-with-no-response': ({ + url + }) => { + return `There was an attempt to cache '${url}' but the response was not ` + `defined.`; + }, + 'no-response': ({ + url, + error + }) => { + let message = `The strategy could not generate a response for '${url}'.`; + if (error) { + message += ` The underlying error is ${error}.`; + } + return message; + }, + 'bad-precaching-response': ({ + url, + status + }) => { + return `The precaching request for '${url}' failed` + (status ? ` with an HTTP status of ${status}.` : `.`); + }, + 'non-precached-url': ({ + url + }) => { + return `createHandlerBoundToURL('${url}') was called, but that URL is ` + `not precached. Please pass in a URL that is precached instead.`; + }, + 'add-to-cache-list-conflicting-integrities': ({ + url + }) => { + return `Two of the entries passed to ` + `'workbox-precaching.PrecacheController.addToCacheList()' had the URL ` + `${url} with different integrity values. Please remove one of them.`; + }, + 'missing-precache-entry': ({ + cacheName, + url + }) => { + return `Unable to find a precached response in ${cacheName} for ${url}.`; + }, + 'cross-origin-copy-response': ({ + origin + }) => { + return `workbox-core.copyResponse() can only be used with same-origin ` + `responses. It was passed a response with origin ${origin}.`; + }, + 'opaque-streams-source': ({ + type + }) => { + const message = `One of the workbox-streams sources resulted in an ` + `'${type}' response.`; + if (type === 'opaqueredirect') { + return `${message} Please do not use a navigation request that results ` + `in a redirect as a source.`; + } + return `${message} Please ensure your sources are CORS-enabled.`; + } +}; + +/* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +const generatorFunction = (code, details = {}) => { + const message = messages$1[code]; + if (!message) { + throw new Error(`Unable to find message for code '${code}'.`); + } + return message(details); +}; +const messageGenerator = generatorFunction; + +/* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +/** + * Workbox errors should be thrown with this class. + * This allows use to ensure the type easily in tests, + * helps developers identify errors from workbox + * easily and allows use to optimise error + * messages correctly. + * + * @private + */ +class WorkboxError extends Error { + /** + * + * @param {string} errorCode The error code that + * identifies this particular error. + * @param {Object=} details Any relevant arguments + * that will help developers identify issues should + * be added as a key on the context object. + */ + constructor(errorCode, details) { + const message = messageGenerator(errorCode, details); + super(message); + this.name = errorCode; + this.details = details; + } +} + +/* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +/* + * This method throws if the supplied value is not an array. + * The destructed values are required to produce a meaningful error for users. + * The destructed and restructured object is so it's clear what is + * needed. + */ +const isArray = (value, details) => { + if (!Array.isArray(value)) { + throw new WorkboxError('not-an-array', details); + } +}; +const hasMethod = (object, expectedMethod, details) => { + const type = typeof object[expectedMethod]; + if (type !== 'function') { + details['expectedMethod'] = expectedMethod; + throw new WorkboxError('missing-a-method', details); + } +}; +const isType = (object, expectedType, details) => { + if (typeof object !== expectedType) { + details['expectedType'] = expectedType; + throw new WorkboxError('incorrect-type', details); + } +}; +const isInstance = (object, +// Need the general type to do the check later. +// eslint-disable-next-line @typescript-eslint/ban-types +expectedClass, details) => { + if (!(object instanceof expectedClass)) { + details['expectedClassName'] = expectedClass.name; + throw new WorkboxError('incorrect-class', details); + } +}; +const isOneOf = (value, validValues, details) => { + if (!validValues.includes(value)) { + details['validValueDescription'] = `Valid values are ${JSON.stringify(validValues)}.`; + throw new WorkboxError('invalid-value', details); + } +}; +const isArrayOfClass = (value, +// Need general type to do check later. +expectedClass, +// eslint-disable-line +details) => { + const error = new WorkboxError('not-array-of-class', details); + if (!Array.isArray(value)) { + throw error; + } + for (const item of value) { + if (!(item instanceof expectedClass)) { + throw error; + } + } +}; +const finalAssertExports = { + hasMethod, + isArray, + isInstance, + isOneOf, + isType, + isArrayOfClass +}; + +// @ts-ignore +try { + self['workbox:routing:7.3.0'] && _(); +} catch (e) {} + +/* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +/** + * The default HTTP method, 'GET', used when there's no specific method + * configured for a route. + * + * @type {string} + * + * @private + */ +const defaultMethod = 'GET'; +/** + * The list of valid HTTP methods associated with requests that could be routed. + * + * @type {Array} + * + * @private + */ +const validMethods = ['DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT']; + +/* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +/** + * @param {function()|Object} handler Either a function, or an object with a + * 'handle' method. + * @return {Object} An object with a handle method. + * + * @private + */ +const normalizeHandler = handler => { + if (handler && typeof handler === 'object') { + { + finalAssertExports.hasMethod(handler, 'handle', { + moduleName: 'workbox-routing', + className: 'Route', + funcName: 'constructor', + paramName: 'handler' + }); + } + return handler; + } else { + { + finalAssertExports.isType(handler, 'function', { + moduleName: 'workbox-routing', + className: 'Route', + funcName: 'constructor', + paramName: 'handler' + }); + } + return { + handle: handler + }; + } +}; + +/* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +/** + * A `Route` consists of a pair of callback functions, "match" and "handler". + * The "match" callback determine if a route should be used to "handle" a + * request by returning a non-falsy value if it can. The "handler" callback + * is called when there is a match and should return a Promise that resolves + * to a `Response`. + * + * @memberof workbox-routing + */ +class Route { + /** + * Constructor for Route class. + * + * @param {workbox-routing~matchCallback} match + * A callback function that determines whether the route matches a given + * `fetch` event by returning a non-falsy value. + * @param {workbox-routing~handlerCallback} handler A callback + * function that returns a Promise resolving to a Response. + * @param {string} [method='GET'] The HTTP method to match the Route + * against. + */ + constructor(match, handler, method = defaultMethod) { + { + finalAssertExports.isType(match, 'function', { + moduleName: 'workbox-routing', + className: 'Route', + funcName: 'constructor', + paramName: 'match' + }); + if (method) { + finalAssertExports.isOneOf(method, validMethods, { + paramName: 'method' + }); + } + } + // These values are referenced directly by Router so cannot be + // altered by minificaton. + this.handler = normalizeHandler(handler); + this.match = match; + this.method = method; + } + /** + * + * @param {workbox-routing-handlerCallback} handler A callback + * function that returns a Promise resolving to a Response + */ + setCatchHandler(handler) { + this.catchHandler = normalizeHandler(handler); + } +} + +/* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +/** + * RegExpRoute makes it easy to create a regular expression based + * {@link workbox-routing.Route}. + * + * For same-origin requests the RegExp only needs to match part of the URL. For + * requests against third-party servers, you must define a RegExp that matches + * the start of the URL. + * + * @memberof workbox-routing + * @extends workbox-routing.Route + */ +class RegExpRoute extends Route { + /** + * If the regular expression contains + * [capture groups]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#grouping-back-references}, + * the captured values will be passed to the + * {@link workbox-routing~handlerCallback} `params` + * argument. + * + * @param {RegExp} regExp The regular expression to match against URLs. + * @param {workbox-routing~handlerCallback} handler A callback + * function that returns a Promise resulting in a Response. + * @param {string} [method='GET'] The HTTP method to match the Route + * against. + */ + constructor(regExp, handler, method) { + { + finalAssertExports.isInstance(regExp, RegExp, { + moduleName: 'workbox-routing', + className: 'RegExpRoute', + funcName: 'constructor', + paramName: 'pattern' + }); + } + const match = ({ + url + }) => { + const result = regExp.exec(url.href); + // Return immediately if there's no match. + if (!result) { + return; + } + // Require that the match start at the first character in the URL string + // if it's a cross-origin request. + // See https://github.com/GoogleChrome/workbox/issues/281 for the context + // behind this behavior. + if (url.origin !== location.origin && result.index !== 0) { + { + logger.debug(`The regular expression '${regExp.toString()}' only partially matched ` + `against the cross-origin URL '${url.toString()}'. RegExpRoute's will only ` + `handle cross-origin requests if they match the entire URL.`); + } + return; + } + // If the route matches, but there aren't any capture groups defined, then + // this will return [], which is truthy and therefore sufficient to + // indicate a match. + // If there are capture groups, then it will return their values. + return result.slice(1); + }; + super(match, handler, method); + } +} + +/* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +const getFriendlyURL = url => { + const urlObj = new URL(String(url), location.href); + // See https://github.com/GoogleChrome/workbox/issues/2323 + // We want to include everything, except for the origin if it's same-origin. + return urlObj.href.replace(new RegExp(`^${location.origin}`), ''); +}; + +/* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +/** + * The Router can be used to process a `FetchEvent` using one or more + * {@link workbox-routing.Route}, responding with a `Response` if + * a matching route exists. + * + * If no route matches a given a request, the Router will use a "default" + * handler if one is defined. + * + * Should the matching Route throw an error, the Router will use a "catch" + * handler if one is defined to gracefully deal with issues and respond with a + * Request. + * + * If a request matches multiple routes, the **earliest** registered route will + * be used to respond to the request. + * + * @memberof workbox-routing + */ +class Router { + /** + * Initializes a new Router. + */ + constructor() { + this._routes = new Map(); + this._defaultHandlerMap = new Map(); + } + /** + * @return {Map>} routes A `Map` of HTTP + * method name ('GET', etc.) to an array of all the corresponding `Route` + * instances that are registered. + */ + get routes() { + return this._routes; + } + /** + * Adds a fetch event listener to respond to events when a route matches + * the event's request. + */ + addFetchListener() { + // See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705 + self.addEventListener('fetch', event => { + const { + request + } = event; + const responsePromise = this.handleRequest({ + request, + event + }); + if (responsePromise) { + event.respondWith(responsePromise); + } + }); + } + /** + * Adds a message event listener for URLs to cache from the window. + * This is useful to cache resources loaded on the page prior to when the + * service worker started controlling it. + * + * The format of the message data sent from the window should be as follows. + * Where the `urlsToCache` array may consist of URL strings or an array of + * URL string + `requestInit` object (the same as you'd pass to `fetch()`). + * + * ``` + * { + * type: 'CACHE_URLS', + * payload: { + * urlsToCache: [ + * './script1.js', + * './script2.js', + * ['./script3.js', {mode: 'no-cors'}], + * ], + * }, + * } + * ``` + */ + addCacheListener() { + // See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705 + self.addEventListener('message', event => { + // event.data is type 'any' + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + if (event.data && event.data.type === 'CACHE_URLS') { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const { + payload + } = event.data; + { + logger.debug(`Caching URLs from the window`, payload.urlsToCache); + } + const requestPromises = Promise.all(payload.urlsToCache.map(entry => { + if (typeof entry === 'string') { + entry = [entry]; + } + const request = new Request(...entry); + return this.handleRequest({ + request, + event + }); + // TODO(philipwalton): TypeScript errors without this typecast for + // some reason (probably a bug). The real type here should work but + // doesn't: `Array | undefined>`. + })); // TypeScript + event.waitUntil(requestPromises); + // If a MessageChannel was used, reply to the message on success. + if (event.ports && event.ports[0]) { + void requestPromises.then(() => event.ports[0].postMessage(true)); + } + } + }); + } + /** + * Apply the routing rules to a FetchEvent object to get a Response from an + * appropriate Route's handler. + * + * @param {Object} options + * @param {Request} options.request The request to handle. + * @param {ExtendableEvent} options.event The event that triggered the + * request. + * @return {Promise|undefined} A promise is returned if a + * registered route can handle the request. If there is no matching + * route and there's no `defaultHandler`, `undefined` is returned. + */ + handleRequest({ + request, + event + }) { + { + finalAssertExports.isInstance(request, Request, { + moduleName: 'workbox-routing', + className: 'Router', + funcName: 'handleRequest', + paramName: 'options.request' + }); + } + const url = new URL(request.url, location.href); + if (!url.protocol.startsWith('http')) { + { + logger.debug(`Workbox Router only supports URLs that start with 'http'.`); + } + return; + } + const sameOrigin = url.origin === location.origin; + const { + params, + route + } = this.findMatchingRoute({ + event, + request, + sameOrigin, + url + }); + let handler = route && route.handler; + const debugMessages = []; + { + if (handler) { + debugMessages.push([`Found a route to handle this request:`, route]); + if (params) { + debugMessages.push([`Passing the following params to the route's handler:`, params]); + } + } + } + // If we don't have a handler because there was no matching route, then + // fall back to defaultHandler if that's defined. + const method = request.method; + if (!handler && this._defaultHandlerMap.has(method)) { + { + debugMessages.push(`Failed to find a matching route. Falling ` + `back to the default handler for ${method}.`); + } + handler = this._defaultHandlerMap.get(method); + } + if (!handler) { + { + // No handler so Workbox will do nothing. If logs is set of debug + // i.e. verbose, we should print out this information. + logger.debug(`No route found for: ${getFriendlyURL(url)}`); + } + return; + } + { + // We have a handler, meaning Workbox is going to handle the route. + // print the routing details to the console. + logger.groupCollapsed(`Router is responding to: ${getFriendlyURL(url)}`); + debugMessages.forEach(msg => { + if (Array.isArray(msg)) { + logger.log(...msg); + } else { + logger.log(msg); + } + }); + logger.groupEnd(); + } + // Wrap in try and catch in case the handle method throws a synchronous + // error. It should still callback to the catch handler. + let responsePromise; + try { + responsePromise = handler.handle({ + url, + request, + event, + params + }); + } catch (err) { + responsePromise = Promise.reject(err); + } + // Get route's catch handler, if it exists + const catchHandler = route && route.catchHandler; + if (responsePromise instanceof Promise && (this._catchHandler || catchHandler)) { + responsePromise = responsePromise.catch(async err => { + // If there's a route catch handler, process that first + if (catchHandler) { + { + // Still include URL here as it will be async from the console group + // and may not make sense without the URL + logger.groupCollapsed(`Error thrown when responding to: ` + ` ${getFriendlyURL(url)}. Falling back to route's Catch Handler.`); + logger.error(`Error thrown by:`, route); + logger.error(err); + logger.groupEnd(); + } + try { + return await catchHandler.handle({ + url, + request, + event, + params + }); + } catch (catchErr) { + if (catchErr instanceof Error) { + err = catchErr; + } + } + } + if (this._catchHandler) { + { + // Still include URL here as it will be async from the console group + // and may not make sense without the URL + logger.groupCollapsed(`Error thrown when responding to: ` + ` ${getFriendlyURL(url)}. Falling back to global Catch Handler.`); + logger.error(`Error thrown by:`, route); + logger.error(err); + logger.groupEnd(); + } + return this._catchHandler.handle({ + url, + request, + event + }); + } + throw err; + }); + } + return responsePromise; + } + /** + * Checks a request and URL (and optionally an event) against the list of + * registered routes, and if there's a match, returns the corresponding + * route along with any params generated by the match. + * + * @param {Object} options + * @param {URL} options.url + * @param {boolean} options.sameOrigin The result of comparing `url.origin` + * against the current origin. + * @param {Request} options.request The request to match. + * @param {Event} options.event The corresponding event. + * @return {Object} An object with `route` and `params` properties. + * They are populated if a matching route was found or `undefined` + * otherwise. + */ + findMatchingRoute({ + url, + sameOrigin, + request, + event + }) { + const routes = this._routes.get(request.method) || []; + for (const route of routes) { + let params; + // route.match returns type any, not possible to change right now. + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const matchResult = route.match({ + url, + sameOrigin, + request, + event + }); + if (matchResult) { + { + // Warn developers that using an async matchCallback is almost always + // not the right thing to do. + if (matchResult instanceof Promise) { + logger.warn(`While routing ${getFriendlyURL(url)}, an async ` + `matchCallback function was used. Please convert the ` + `following route to use a synchronous matchCallback function:`, route); + } + } + // See https://github.com/GoogleChrome/workbox/issues/2079 + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + params = matchResult; + if (Array.isArray(params) && params.length === 0) { + // Instead of passing an empty array in as params, use undefined. + params = undefined; + } else if (matchResult.constructor === Object && + // eslint-disable-line + Object.keys(matchResult).length === 0) { + // Instead of passing an empty object in as params, use undefined. + params = undefined; + } else if (typeof matchResult === 'boolean') { + // For the boolean value true (rather than just something truth-y), + // don't set params. + // See https://github.com/GoogleChrome/workbox/pull/2134#issuecomment-513924353 + params = undefined; + } + // Return early if have a match. + return { + route, + params + }; + } + } + // If no match was found above, return and empty object. + return {}; + } + /** + * Define a default `handler` that's called when no routes explicitly + * match the incoming request. + * + * Each HTTP method ('GET', 'POST', etc.) gets its own default handler. + * + * Without a default handler, unmatched requests will go against the + * network as if there were no service worker present. + * + * @param {workbox-routing~handlerCallback} handler A callback + * function that returns a Promise resulting in a Response. + * @param {string} [method='GET'] The HTTP method to associate with this + * default handler. Each method has its own default. + */ + setDefaultHandler(handler, method = defaultMethod) { + this._defaultHandlerMap.set(method, normalizeHandler(handler)); + } + /** + * If a Route throws an error while handling a request, this `handler` + * will be called and given a chance to provide a response. + * + * @param {workbox-routing~handlerCallback} handler A callback + * function that returns a Promise resulting in a Response. + */ + setCatchHandler(handler) { + this._catchHandler = normalizeHandler(handler); + } + /** + * Registers a route with the router. + * + * @param {workbox-routing.Route} route The route to register. + */ + registerRoute(route) { + { + finalAssertExports.isType(route, 'object', { + moduleName: 'workbox-routing', + className: 'Router', + funcName: 'registerRoute', + paramName: 'route' + }); + finalAssertExports.hasMethod(route, 'match', { + moduleName: 'workbox-routing', + className: 'Router', + funcName: 'registerRoute', + paramName: 'route' + }); + finalAssertExports.isType(route.handler, 'object', { + moduleName: 'workbox-routing', + className: 'Router', + funcName: 'registerRoute', + paramName: 'route' + }); + finalAssertExports.hasMethod(route.handler, 'handle', { + moduleName: 'workbox-routing', + className: 'Router', + funcName: 'registerRoute', + paramName: 'route.handler' + }); + finalAssertExports.isType(route.method, 'string', { + moduleName: 'workbox-routing', + className: 'Router', + funcName: 'registerRoute', + paramName: 'route.method' + }); + } + if (!this._routes.has(route.method)) { + this._routes.set(route.method, []); + } + // Give precedence to all of the earlier routes by adding this additional + // route to the end of the array. + this._routes.get(route.method).push(route); + } + /** + * Unregisters a route with the router. + * + * @param {workbox-routing.Route} route The route to unregister. + */ + unregisterRoute(route) { + if (!this._routes.has(route.method)) { + throw new WorkboxError('unregister-route-but-not-found-with-method', { + method: route.method + }); + } + const routeIndex = this._routes.get(route.method).indexOf(route); + if (routeIndex > -1) { + this._routes.get(route.method).splice(routeIndex, 1); + } else { + throw new WorkboxError('unregister-route-route-not-registered'); + } + } +} + +/* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +let defaultRouter; +/** + * Creates a new, singleton Router instance if one does not exist. If one + * does already exist, that instance is returned. + * + * @private + * @return {Router} + */ +const getOrCreateDefaultRouter = () => { + if (!defaultRouter) { + defaultRouter = new Router(); + // The helpers that use the default Router assume these listeners exist. + defaultRouter.addFetchListener(); + defaultRouter.addCacheListener(); + } + return defaultRouter; +}; + +/* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +/** + * Easily register a RegExp, string, or function with a caching + * strategy to a singleton Router instance. + * + * This method will generate a Route for you if needed and + * call {@link workbox-routing.Router#registerRoute}. + * + * @param {RegExp|string|workbox-routing.Route~matchCallback|workbox-routing.Route} capture + * If the capture param is a `Route`, all other arguments will be ignored. + * @param {workbox-routing~handlerCallback} [handler] A callback + * function that returns a Promise resulting in a Response. This parameter + * is required if `capture` is not a `Route` object. + * @param {string} [method='GET'] The HTTP method to match the Route + * against. + * @return {workbox-routing.Route} The generated `Route`. + * + * @memberof workbox-routing + */ +function registerRoute(capture, handler, method) { + let route; + if (typeof capture === 'string') { + const captureUrl = new URL(capture, location.href); + { + if (!(capture.startsWith('/') || capture.startsWith('http'))) { + throw new WorkboxError('invalid-string', { + moduleName: 'workbox-routing', + funcName: 'registerRoute', + paramName: 'capture' + }); + } + // We want to check if Express-style wildcards are in the pathname only. + // TODO: Remove this log message in v4. + const valueToCheck = capture.startsWith('http') ? captureUrl.pathname : capture; + // See https://github.com/pillarjs/path-to-regexp#parameters + const wildcards = '[*:?+]'; + if (new RegExp(`${wildcards}`).exec(valueToCheck)) { + logger.debug(`The '$capture' parameter contains an Express-style wildcard ` + `character (${wildcards}). Strings are now always interpreted as ` + `exact matches; use a RegExp for partial or wildcard matches.`); + } + } + const matchCallback = ({ + url + }) => { + { + if (url.pathname === captureUrl.pathname && url.origin !== captureUrl.origin) { + logger.debug(`${capture} only partially matches the cross-origin URL ` + `${url.toString()}. This route will only handle cross-origin requests ` + `if they match the entire URL.`); + } + } + return url.href === captureUrl.href; + }; + // If `capture` is a string then `handler` and `method` must be present. + route = new Route(matchCallback, handler, method); + } else if (capture instanceof RegExp) { + // If `capture` is a `RegExp` then `handler` and `method` must be present. + route = new RegExpRoute(capture, handler, method); + } else if (typeof capture === 'function') { + // If `capture` is a function then `handler` and `method` must be present. + route = new Route(capture, handler, method); + } else if (capture instanceof Route) { + route = capture; + } else { + throw new WorkboxError('unsupported-route-type', { + moduleName: 'workbox-routing', + funcName: 'registerRoute', + paramName: 'capture' + }); + } + const defaultRouter = getOrCreateDefaultRouter(); + defaultRouter.registerRoute(route); + return route; +} + +/* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +const _cacheNameDetails = { + googleAnalytics: 'googleAnalytics', + precache: 'precache-v2', + prefix: 'workbox', + runtime: 'runtime', + suffix: typeof registration !== 'undefined' ? registration.scope : '' +}; +const _createCacheName = cacheName => { + return [_cacheNameDetails.prefix, cacheName, _cacheNameDetails.suffix].filter(value => value && value.length > 0).join('-'); +}; +const eachCacheNameDetail = fn => { + for (const key of Object.keys(_cacheNameDetails)) { + fn(key); + } +}; +const cacheNames = { + updateDetails: details => { + eachCacheNameDetail(key => { + if (typeof details[key] === 'string') { + _cacheNameDetails[key] = details[key]; + } + }); + }, + getGoogleAnalyticsName: userCacheName => { + return userCacheName || _createCacheName(_cacheNameDetails.googleAnalytics); + }, + getPrecacheName: userCacheName => { + return userCacheName || _createCacheName(_cacheNameDetails.precache); + }, + getPrefix: () => { + return _cacheNameDetails.prefix; + }, + getRuntimeName: userCacheName => { + return userCacheName || _createCacheName(_cacheNameDetails.runtime); + }, + getSuffix: () => { + return _cacheNameDetails.suffix; + } +}; + +/* + Copyright 2019 Google LLC + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +/** + * A helper function that prevents a promise from being flagged as unused. + * + * @private + **/ +function dontWaitFor(promise) { + // Effective no-op. + void promise.then(() => {}); +} + +/* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +// Callbacks to be executed whenever there's a quota error. +// Can't change Function type right now. +// eslint-disable-next-line @typescript-eslint/ban-types +const quotaErrorCallbacks = new Set(); + +/* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +/** + * Adds a function to the set of quotaErrorCallbacks that will be executed if + * there's a quota error. + * + * @param {Function} callback + * @memberof workbox-core + */ +// Can't change Function type +// eslint-disable-next-line @typescript-eslint/ban-types +function registerQuotaErrorCallback(callback) { + { + finalAssertExports.isType(callback, 'function', { + moduleName: 'workbox-core', + funcName: 'register', + paramName: 'callback' + }); + } + quotaErrorCallbacks.add(callback); + { + logger.log('Registered a callback to respond to quota errors.', callback); + } +} + +function _extends() { + return _extends = Object.assign ? Object.assign.bind() : function (n) { + for (var e = 1; e < arguments.length; e++) { + var t = arguments[e]; + for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); + } + return n; + }, _extends.apply(null, arguments); +} + +const instanceOfAny = (object, constructors) => constructors.some(c => object instanceof c); +let idbProxyableTypes; +let cursorAdvanceMethods; +// This is a function to prevent it throwing up in node environments. +function getIdbProxyableTypes() { + return idbProxyableTypes || (idbProxyableTypes = [IDBDatabase, IDBObjectStore, IDBIndex, IDBCursor, IDBTransaction]); +} +// This is a function to prevent it throwing up in node environments. +function getCursorAdvanceMethods() { + return cursorAdvanceMethods || (cursorAdvanceMethods = [IDBCursor.prototype.advance, IDBCursor.prototype.continue, IDBCursor.prototype.continuePrimaryKey]); +} +const cursorRequestMap = new WeakMap(); +const transactionDoneMap = new WeakMap(); +const transactionStoreNamesMap = new WeakMap(); +const transformCache = new WeakMap(); +const reverseTransformCache = new WeakMap(); +function promisifyRequest(request) { + const promise = new Promise((resolve, reject) => { + const unlisten = () => { + request.removeEventListener('success', success); + request.removeEventListener('error', error); + }; + const success = () => { + resolve(wrap(request.result)); + unlisten(); + }; + const error = () => { + reject(request.error); + unlisten(); + }; + request.addEventListener('success', success); + request.addEventListener('error', error); + }); + promise.then(value => { + // Since cursoring reuses the IDBRequest (*sigh*), we cache it for later retrieval + // (see wrapFunction). + if (value instanceof IDBCursor) { + cursorRequestMap.set(value, request); + } + // Catching to avoid "Uncaught Promise exceptions" + }).catch(() => {}); + // This mapping exists in reverseTransformCache but doesn't doesn't exist in transformCache. This + // is because we create many promises from a single IDBRequest. + reverseTransformCache.set(promise, request); + return promise; +} +function cacheDonePromiseForTransaction(tx) { + // Early bail if we've already created a done promise for this transaction. + if (transactionDoneMap.has(tx)) return; + const done = new Promise((resolve, reject) => { + const unlisten = () => { + tx.removeEventListener('complete', complete); + tx.removeEventListener('error', error); + tx.removeEventListener('abort', error); + }; + const complete = () => { + resolve(); + unlisten(); + }; + const error = () => { + reject(tx.error || new DOMException('AbortError', 'AbortError')); + unlisten(); + }; + tx.addEventListener('complete', complete); + tx.addEventListener('error', error); + tx.addEventListener('abort', error); + }); + // Cache it for later retrieval. + transactionDoneMap.set(tx, done); +} +let idbProxyTraps = { + get(target, prop, receiver) { + if (target instanceof IDBTransaction) { + // Special handling for transaction.done. + if (prop === 'done') return transactionDoneMap.get(target); + // Polyfill for objectStoreNames because of Edge. + if (prop === 'objectStoreNames') { + return target.objectStoreNames || transactionStoreNamesMap.get(target); + } + // Make tx.store return the only store in the transaction, or undefined if there are many. + if (prop === 'store') { + return receiver.objectStoreNames[1] ? undefined : receiver.objectStore(receiver.objectStoreNames[0]); + } + } + // Else transform whatever we get back. + return wrap(target[prop]); + }, + set(target, prop, value) { + target[prop] = value; + return true; + }, + has(target, prop) { + if (target instanceof IDBTransaction && (prop === 'done' || prop === 'store')) { + return true; + } + return prop in target; + } +}; +function replaceTraps(callback) { + idbProxyTraps = callback(idbProxyTraps); +} +function wrapFunction(func) { + // Due to expected object equality (which is enforced by the caching in `wrap`), we + // only create one new func per func. + // Edge doesn't support objectStoreNames (booo), so we polyfill it here. + if (func === IDBDatabase.prototype.transaction && !('objectStoreNames' in IDBTransaction.prototype)) { + return function (storeNames, ...args) { + const tx = func.call(unwrap(this), storeNames, ...args); + transactionStoreNamesMap.set(tx, storeNames.sort ? storeNames.sort() : [storeNames]); + return wrap(tx); + }; + } + // Cursor methods are special, as the behaviour is a little more different to standard IDB. In + // IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the + // cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense + // with real promises, so each advance methods returns a new promise for the cursor object, or + // undefined if the end of the cursor has been reached. + if (getCursorAdvanceMethods().includes(func)) { + return function (...args) { + // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use + // the original object. + func.apply(unwrap(this), args); + return wrap(cursorRequestMap.get(this)); + }; + } + return function (...args) { + // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use + // the original object. + return wrap(func.apply(unwrap(this), args)); + }; +} +function transformCachableValue(value) { + if (typeof value === 'function') return wrapFunction(value); + // This doesn't return, it just creates a 'done' promise for the transaction, + // which is later returned for transaction.done (see idbObjectHandler). + if (value instanceof IDBTransaction) cacheDonePromiseForTransaction(value); + if (instanceOfAny(value, getIdbProxyableTypes())) return new Proxy(value, idbProxyTraps); + // Return the same value back if we're not going to transform it. + return value; +} +function wrap(value) { + // We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because + // IDB is weird and a single IDBRequest can yield many responses, so these can't be cached. + if (value instanceof IDBRequest) return promisifyRequest(value); + // If we've already transformed this value before, reuse the transformed value. + // This is faster, but it also provides object equality. + if (transformCache.has(value)) return transformCache.get(value); + const newValue = transformCachableValue(value); + // Not all types are transformed. + // These may be primitive types, so they can't be WeakMap keys. + if (newValue !== value) { + transformCache.set(value, newValue); + reverseTransformCache.set(newValue, value); + } + return newValue; +} +const unwrap = value => reverseTransformCache.get(value); + +/** + * Open a database. + * + * @param name Name of the database. + * @param version Schema version. + * @param callbacks Additional callbacks. + */ +function openDB(name, version, { + blocked, + upgrade, + blocking, + terminated +} = {}) { + const request = indexedDB.open(name, version); + const openPromise = wrap(request); + if (upgrade) { + request.addEventListener('upgradeneeded', event => { + upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event); + }); + } + if (blocked) { + request.addEventListener('blocked', event => blocked( + // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405 + event.oldVersion, event.newVersion, event)); + } + openPromise.then(db => { + if (terminated) db.addEventListener('close', () => terminated()); + if (blocking) { + db.addEventListener('versionchange', event => blocking(event.oldVersion, event.newVersion, event)); + } + }).catch(() => {}); + return openPromise; +} +/** + * Delete a database. + * + * @param name Name of the database. + */ +function deleteDB(name, { + blocked +} = {}) { + const request = indexedDB.deleteDatabase(name); + if (blocked) { + request.addEventListener('blocked', event => blocked( + // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405 + event.oldVersion, event)); + } + return wrap(request).then(() => undefined); +} +const readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count']; +const writeMethods = ['put', 'add', 'delete', 'clear']; +const cachedMethods = new Map(); +function getMethod(target, prop) { + if (!(target instanceof IDBDatabase && !(prop in target) && typeof prop === 'string')) { + return; + } + if (cachedMethods.get(prop)) return cachedMethods.get(prop); + const targetFuncName = prop.replace(/FromIndex$/, ''); + const useIndex = prop !== targetFuncName; + const isWrite = writeMethods.includes(targetFuncName); + if ( + // Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge. + !(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) || !(isWrite || readMethods.includes(targetFuncName))) { + return; + } + const method = async function (storeName, ...args) { + // isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :( + const tx = this.transaction(storeName, isWrite ? 'readwrite' : 'readonly'); + let target = tx.store; + if (useIndex) target = target.index(args.shift()); + // Must reject if op rejects. + // If it's a write operation, must reject if tx.done rejects. + // Must reject with op rejection first. + // Must resolve with op value. + // Must handle both promises (no unhandled rejections) + return (await Promise.all([target[targetFuncName](...args), isWrite && tx.done]))[0]; + }; + cachedMethods.set(prop, method); + return method; +} +replaceTraps(oldTraps => _extends({}, oldTraps, { + get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver), + has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop) +})); + +// @ts-ignore +try { + self['workbox:expiration:7.3.0'] && _(); +} catch (e) {} + +/* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +const DB_NAME = 'workbox-expiration'; +const CACHE_OBJECT_STORE = 'cache-entries'; +const normalizeURL = unNormalizedUrl => { + const url = new URL(unNormalizedUrl, location.href); + url.hash = ''; + return url.href; +}; +/** + * Returns the timestamp model. + * + * @private + */ +class CacheTimestampsModel { + /** + * + * @param {string} cacheName + * + * @private + */ + constructor(cacheName) { + this._db = null; + this._cacheName = cacheName; + } + /** + * Performs an upgrade of indexedDB. + * + * @param {IDBPDatabase} db + * + * @private + */ + _upgradeDb(db) { + // TODO(philipwalton): EdgeHTML doesn't support arrays as a keyPath, so we + // have to use the `id` keyPath here and create our own values (a + // concatenation of `url + cacheName`) instead of simply using + // `keyPath: ['url', 'cacheName']`, which is supported in other browsers. + const objStore = db.createObjectStore(CACHE_OBJECT_STORE, { + keyPath: 'id' + }); + // TODO(philipwalton): once we don't have to support EdgeHTML, we can + // create a single index with the keyPath `['cacheName', 'timestamp']` + // instead of doing both these indexes. + objStore.createIndex('cacheName', 'cacheName', { + unique: false + }); + objStore.createIndex('timestamp', 'timestamp', { + unique: false + }); + } + /** + * Performs an upgrade of indexedDB and deletes deprecated DBs. + * + * @param {IDBPDatabase} db + * + * @private + */ + _upgradeDbAndDeleteOldDbs(db) { + this._upgradeDb(db); + if (this._cacheName) { + void deleteDB(this._cacheName); + } + } + /** + * @param {string} url + * @param {number} timestamp + * + * @private + */ + async setTimestamp(url, timestamp) { + url = normalizeURL(url); + const entry = { + url, + timestamp, + cacheName: this._cacheName, + // Creating an ID from the URL and cache name won't be necessary once + // Edge switches to Chromium and all browsers we support work with + // array keyPaths. + id: this._getId(url) + }; + const db = await this.getDb(); + const tx = db.transaction(CACHE_OBJECT_STORE, 'readwrite', { + durability: 'relaxed' + }); + await tx.store.put(entry); + await tx.done; + } + /** + * Returns the timestamp stored for a given URL. + * + * @param {string} url + * @return {number | undefined} + * + * @private + */ + async getTimestamp(url) { + const db = await this.getDb(); + const entry = await db.get(CACHE_OBJECT_STORE, this._getId(url)); + return entry === null || entry === void 0 ? void 0 : entry.timestamp; + } + /** + * Iterates through all the entries in the object store (from newest to + * oldest) and removes entries once either `maxCount` is reached or the + * entry's timestamp is less than `minTimestamp`. + * + * @param {number} minTimestamp + * @param {number} maxCount + * @return {Array} + * + * @private + */ + async expireEntries(minTimestamp, maxCount) { + const db = await this.getDb(); + let cursor = await db.transaction(CACHE_OBJECT_STORE).store.index('timestamp').openCursor(null, 'prev'); + const entriesToDelete = []; + let entriesNotDeletedCount = 0; + while (cursor) { + const result = cursor.value; + // TODO(philipwalton): once we can use a multi-key index, we + // won't have to check `cacheName` here. + if (result.cacheName === this._cacheName) { + // Delete an entry if it's older than the max age or + // if we already have the max number allowed. + if (minTimestamp && result.timestamp < minTimestamp || maxCount && entriesNotDeletedCount >= maxCount) { + // TODO(philipwalton): we should be able to delete the + // entry right here, but doing so causes an iteration + // bug in Safari stable (fixed in TP). Instead we can + // store the keys of the entries to delete, and then + // delete the separate transactions. + // https://github.com/GoogleChrome/workbox/issues/1978 + // cursor.delete(); + // We only need to return the URL, not the whole entry. + entriesToDelete.push(cursor.value); + } else { + entriesNotDeletedCount++; + } + } + cursor = await cursor.continue(); + } + // TODO(philipwalton): once the Safari bug in the following issue is fixed, + // we should be able to remove this loop and do the entry deletion in the + // cursor loop above: + // https://github.com/GoogleChrome/workbox/issues/1978 + const urlsDeleted = []; + for (const entry of entriesToDelete) { + await db.delete(CACHE_OBJECT_STORE, entry.id); + urlsDeleted.push(entry.url); + } + return urlsDeleted; + } + /** + * Takes a URL and returns an ID that will be unique in the object store. + * + * @param {string} url + * @return {string} + * + * @private + */ + _getId(url) { + // Creating an ID from the URL and cache name won't be necessary once + // Edge switches to Chromium and all browsers we support work with + // array keyPaths. + return this._cacheName + '|' + normalizeURL(url); + } + /** + * Returns an open connection to the database. + * + * @private + */ + async getDb() { + if (!this._db) { + this._db = await openDB(DB_NAME, 1, { + upgrade: this._upgradeDbAndDeleteOldDbs.bind(this) + }); + } + return this._db; + } +} + +/* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +/** + * The `CacheExpiration` class allows you define an expiration and / or + * limit on the number of responses stored in a + * [`Cache`](https://developer.mozilla.org/en-US/docs/Web/API/Cache). + * + * @memberof workbox-expiration + */ +class CacheExpiration { + /** + * To construct a new CacheExpiration instance you must provide at least + * one of the `config` properties. + * + * @param {string} cacheName Name of the cache to apply restrictions to. + * @param {Object} config + * @param {number} [config.maxEntries] The maximum number of entries to cache. + * Entries used the least will be removed as the maximum is reached. + * @param {number} [config.maxAgeSeconds] The maximum age of an entry before + * it's treated as stale and removed. + * @param {Object} [config.matchOptions] The [`CacheQueryOptions`](https://developer.mozilla.org/en-US/docs/Web/API/Cache/delete#Parameters) + * that will be used when calling `delete()` on the cache. + */ + constructor(cacheName, config = {}) { + this._isRunning = false; + this._rerunRequested = false; + { + finalAssertExports.isType(cacheName, 'string', { + moduleName: 'workbox-expiration', + className: 'CacheExpiration', + funcName: 'constructor', + paramName: 'cacheName' + }); + if (!(config.maxEntries || config.maxAgeSeconds)) { + throw new WorkboxError('max-entries-or-age-required', { + moduleName: 'workbox-expiration', + className: 'CacheExpiration', + funcName: 'constructor' + }); + } + if (config.maxEntries) { + finalAssertExports.isType(config.maxEntries, 'number', { + moduleName: 'workbox-expiration', + className: 'CacheExpiration', + funcName: 'constructor', + paramName: 'config.maxEntries' + }); + } + if (config.maxAgeSeconds) { + finalAssertExports.isType(config.maxAgeSeconds, 'number', { + moduleName: 'workbox-expiration', + className: 'CacheExpiration', + funcName: 'constructor', + paramName: 'config.maxAgeSeconds' + }); + } + } + this._maxEntries = config.maxEntries; + this._maxAgeSeconds = config.maxAgeSeconds; + this._matchOptions = config.matchOptions; + this._cacheName = cacheName; + this._timestampModel = new CacheTimestampsModel(cacheName); + } + /** + * Expires entries for the given cache and given criteria. + */ + async expireEntries() { + if (this._isRunning) { + this._rerunRequested = true; + return; + } + this._isRunning = true; + const minTimestamp = this._maxAgeSeconds ? Date.now() - this._maxAgeSeconds * 1000 : 0; + const urlsExpired = await this._timestampModel.expireEntries(minTimestamp, this._maxEntries); + // Delete URLs from the cache + const cache = await self.caches.open(this._cacheName); + for (const url of urlsExpired) { + await cache.delete(url, this._matchOptions); + } + { + if (urlsExpired.length > 0) { + logger.groupCollapsed(`Expired ${urlsExpired.length} ` + `${urlsExpired.length === 1 ? 'entry' : 'entries'} and removed ` + `${urlsExpired.length === 1 ? 'it' : 'them'} from the ` + `'${this._cacheName}' cache.`); + logger.log(`Expired the following ${urlsExpired.length === 1 ? 'URL' : 'URLs'}:`); + urlsExpired.forEach(url => logger.log(` ${url}`)); + logger.groupEnd(); + } else { + logger.debug(`Cache expiration ran and found no entries to remove.`); + } + } + this._isRunning = false; + if (this._rerunRequested) { + this._rerunRequested = false; + dontWaitFor(this.expireEntries()); + } + } + /** + * Update the timestamp for the given URL. This ensures the when + * removing entries based on maximum entries, most recently used + * is accurate or when expiring, the timestamp is up-to-date. + * + * @param {string} url + */ + async updateTimestamp(url) { + { + finalAssertExports.isType(url, 'string', { + moduleName: 'workbox-expiration', + className: 'CacheExpiration', + funcName: 'updateTimestamp', + paramName: 'url' + }); + } + await this._timestampModel.setTimestamp(url, Date.now()); + } + /** + * Can be used to check if a URL has expired or not before it's used. + * + * This requires a look up from IndexedDB, so can be slow. + * + * Note: This method will not remove the cached entry, call + * `expireEntries()` to remove indexedDB and Cache entries. + * + * @param {string} url + * @return {boolean} + */ + async isURLExpired(url) { + if (!this._maxAgeSeconds) { + { + throw new WorkboxError(`expired-test-without-max-age`, { + methodName: 'isURLExpired', + paramName: 'maxAgeSeconds' + }); + } + } else { + const timestamp = await this._timestampModel.getTimestamp(url); + const expireOlderThan = Date.now() - this._maxAgeSeconds * 1000; + return timestamp !== undefined ? timestamp < expireOlderThan : true; + } + } + /** + * Removes the IndexedDB object store used to keep track of cache expiration + * metadata. + */ + async delete() { + // Make sure we don't attempt another rerun if we're called in the middle of + // a cache expiration. + this._rerunRequested = false; + await this._timestampModel.expireEntries(Infinity); // Expires all. + } +} + +/* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +/** + * This plugin can be used in a `workbox-strategy` to regularly enforce a + * limit on the age and / or the number of cached requests. + * + * It can only be used with `workbox-strategy` instances that have a + * [custom `cacheName` property set](/web/tools/workbox/guides/configure-workbox#custom_cache_names_in_strategies). + * In other words, it can't be used to expire entries in strategy that uses the + * default runtime cache name. + * + * Whenever a cached response is used or updated, this plugin will look + * at the associated cache and remove any old or extra responses. + * + * When using `maxAgeSeconds`, responses may be used *once* after expiring + * because the expiration clean up will not have occurred until *after* the + * cached response has been used. If the response has a "Date" header, then + * a light weight expiration check is performed and the response will not be + * used immediately. + * + * When using `maxEntries`, the entry least-recently requested will be removed + * from the cache first. + * + * @memberof workbox-expiration + */ +class ExpirationPlugin { + /** + * @param {ExpirationPluginOptions} config + * @param {number} [config.maxEntries] The maximum number of entries to cache. + * Entries used the least will be removed as the maximum is reached. + * @param {number} [config.maxAgeSeconds] The maximum age of an entry before + * it's treated as stale and removed. + * @param {Object} [config.matchOptions] The [`CacheQueryOptions`](https://developer.mozilla.org/en-US/docs/Web/API/Cache/delete#Parameters) + * that will be used when calling `delete()` on the cache. + * @param {boolean} [config.purgeOnQuotaError] Whether to opt this cache in to + * automatic deletion if the available storage quota has been exceeded. + */ + constructor(config = {}) { + /** + * A "lifecycle" callback that will be triggered automatically by the + * `workbox-strategies` handlers when a `Response` is about to be returned + * from a [Cache](https://developer.mozilla.org/en-US/docs/Web/API/Cache) to + * the handler. It allows the `Response` to be inspected for freshness and + * prevents it from being used if the `Response`'s `Date` header value is + * older than the configured `maxAgeSeconds`. + * + * @param {Object} options + * @param {string} options.cacheName Name of the cache the response is in. + * @param {Response} options.cachedResponse The `Response` object that's been + * read from a cache and whose freshness should be checked. + * @return {Response} Either the `cachedResponse`, if it's + * fresh, or `null` if the `Response` is older than `maxAgeSeconds`. + * + * @private + */ + this.cachedResponseWillBeUsed = async ({ + event, + request, + cacheName, + cachedResponse + }) => { + if (!cachedResponse) { + return null; + } + const isFresh = this._isResponseDateFresh(cachedResponse); + // Expire entries to ensure that even if the expiration date has + // expired, it'll only be used once. + const cacheExpiration = this._getCacheExpiration(cacheName); + dontWaitFor(cacheExpiration.expireEntries()); + // Update the metadata for the request URL to the current timestamp, + // but don't `await` it as we don't want to block the response. + const updateTimestampDone = cacheExpiration.updateTimestamp(request.url); + if (event) { + try { + event.waitUntil(updateTimestampDone); + } catch (error) { + { + // The event may not be a fetch event; only log the URL if it is. + if ('request' in event) { + logger.warn(`Unable to ensure service worker stays alive when ` + `updating cache entry for ` + `'${getFriendlyURL(event.request.url)}'.`); + } + } + } + } + return isFresh ? cachedResponse : null; + }; + /** + * A "lifecycle" callback that will be triggered automatically by the + * `workbox-strategies` handlers when an entry is added to a cache. + * + * @param {Object} options + * @param {string} options.cacheName Name of the cache that was updated. + * @param {string} options.request The Request for the cached entry. + * + * @private + */ + this.cacheDidUpdate = async ({ + cacheName, + request + }) => { + { + finalAssertExports.isType(cacheName, 'string', { + moduleName: 'workbox-expiration', + className: 'Plugin', + funcName: 'cacheDidUpdate', + paramName: 'cacheName' + }); + finalAssertExports.isInstance(request, Request, { + moduleName: 'workbox-expiration', + className: 'Plugin', + funcName: 'cacheDidUpdate', + paramName: 'request' + }); + } + const cacheExpiration = this._getCacheExpiration(cacheName); + await cacheExpiration.updateTimestamp(request.url); + await cacheExpiration.expireEntries(); + }; + { + if (!(config.maxEntries || config.maxAgeSeconds)) { + throw new WorkboxError('max-entries-or-age-required', { + moduleName: 'workbox-expiration', + className: 'Plugin', + funcName: 'constructor' + }); + } + if (config.maxEntries) { + finalAssertExports.isType(config.maxEntries, 'number', { + moduleName: 'workbox-expiration', + className: 'Plugin', + funcName: 'constructor', + paramName: 'config.maxEntries' + }); + } + if (config.maxAgeSeconds) { + finalAssertExports.isType(config.maxAgeSeconds, 'number', { + moduleName: 'workbox-expiration', + className: 'Plugin', + funcName: 'constructor', + paramName: 'config.maxAgeSeconds' + }); + } + } + this._config = config; + this._maxAgeSeconds = config.maxAgeSeconds; + this._cacheExpirations = new Map(); + if (config.purgeOnQuotaError) { + registerQuotaErrorCallback(() => this.deleteCacheAndMetadata()); + } + } + /** + * A simple helper method to return a CacheExpiration instance for a given + * cache name. + * + * @param {string} cacheName + * @return {CacheExpiration} + * + * @private + */ + _getCacheExpiration(cacheName) { + if (cacheName === cacheNames.getRuntimeName()) { + throw new WorkboxError('expire-custom-caches-only'); + } + let cacheExpiration = this._cacheExpirations.get(cacheName); + if (!cacheExpiration) { + cacheExpiration = new CacheExpiration(cacheName, this._config); + this._cacheExpirations.set(cacheName, cacheExpiration); + } + return cacheExpiration; + } + /** + * @param {Response} cachedResponse + * @return {boolean} + * + * @private + */ + _isResponseDateFresh(cachedResponse) { + if (!this._maxAgeSeconds) { + // We aren't expiring by age, so return true, it's fresh + return true; + } + // Check if the 'date' header will suffice a quick expiration check. + // See https://github.com/GoogleChromeLabs/sw-toolbox/issues/164 for + // discussion. + const dateHeaderTimestamp = this._getDateHeaderTimestamp(cachedResponse); + if (dateHeaderTimestamp === null) { + // Unable to parse date, so assume it's fresh. + return true; + } + // If we have a valid headerTime, then our response is fresh iff the + // headerTime plus maxAgeSeconds is greater than the current time. + const now = Date.now(); + return dateHeaderTimestamp >= now - this._maxAgeSeconds * 1000; + } + /** + * This method will extract the data header and parse it into a useful + * value. + * + * @param {Response} cachedResponse + * @return {number|null} + * + * @private + */ + _getDateHeaderTimestamp(cachedResponse) { + if (!cachedResponse.headers.has('date')) { + return null; + } + const dateHeader = cachedResponse.headers.get('date'); + const parsedDate = new Date(dateHeader); + const headerTime = parsedDate.getTime(); + // If the Date header was invalid for some reason, parsedDate.getTime() + // will return NaN. + if (isNaN(headerTime)) { + return null; + } + return headerTime; + } + /** + * This is a helper method that performs two operations: + * + * - Deletes *all* the underlying Cache instances associated with this plugin + * instance, by calling caches.delete() on your behalf. + * - Deletes the metadata from IndexedDB used to keep track of expiration + * details for each Cache instance. + * + * When using cache expiration, calling this method is preferable to calling + * `caches.delete()` directly, since this will ensure that the IndexedDB + * metadata is also cleanly removed and open IndexedDB instances are deleted. + * + * Note that if you're *not* using cache expiration for a given cache, calling + * `caches.delete()` and passing in the cache's name should be sufficient. + * There is no Workbox-specific method needed for cleanup in that case. + */ + async deleteCacheAndMetadata() { + // Do this one at a time instead of all at once via `Promise.all()` to + // reduce the chance of inconsistency if a promise rejects. + for (const [cacheName, cacheExpiration] of this._cacheExpirations) { + await self.caches.delete(cacheName); + await cacheExpiration.delete(); + } + // Reset this._cacheExpirations to its initial state. + this._cacheExpirations = new Map(); + } +} + +/* + Copyright 2020 Google LLC + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +function stripParams(fullURL, ignoreParams) { + const strippedURL = new URL(fullURL); + for (const param of ignoreParams) { + strippedURL.searchParams.delete(param); + } + return strippedURL.href; +} +/** + * Matches an item in the cache, ignoring specific URL params. This is similar + * to the `ignoreSearch` option, but it allows you to ignore just specific + * params (while continuing to match on the others). + * + * @private + * @param {Cache} cache + * @param {Request} request + * @param {Object} matchOptions + * @param {Array} ignoreParams + * @return {Promise} + */ +async function cacheMatchIgnoreParams(cache, request, ignoreParams, matchOptions) { + const strippedRequestURL = stripParams(request.url, ignoreParams); + // If the request doesn't include any ignored params, match as normal. + if (request.url === strippedRequestURL) { + return cache.match(request, matchOptions); + } + // Otherwise, match by comparing keys + const keysOptions = Object.assign(Object.assign({}, matchOptions), { + ignoreSearch: true + }); + const cacheKeys = await cache.keys(request, keysOptions); + for (const cacheKey of cacheKeys) { + const strippedCacheKeyURL = stripParams(cacheKey.url, ignoreParams); + if (strippedRequestURL === strippedCacheKeyURL) { + return cache.match(cacheKey, matchOptions); + } + } + return; +} + +/* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +/** + * The Deferred class composes Promises in a way that allows for them to be + * resolved or rejected from outside the constructor. In most cases promises + * should be used directly, but Deferreds can be necessary when the logic to + * resolve a promise must be separate. + * + * @private + */ +class Deferred { + /** + * Creates a promise and exposes its resolve and reject functions as methods. + */ + constructor() { + this.promise = new Promise((resolve, reject) => { + this.resolve = resolve; + this.reject = reject; + }); + } +} + +/* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +/** + * Runs all of the callback functions, one at a time sequentially, in the order + * in which they were registered. + * + * @memberof workbox-core + * @private + */ +async function executeQuotaErrorCallbacks() { + { + logger.log(`About to run ${quotaErrorCallbacks.size} ` + `callbacks to clean up caches.`); + } + for (const callback of quotaErrorCallbacks) { + await callback(); + { + logger.log(callback, 'is complete.'); + } + } + { + logger.log('Finished running callbacks.'); + } +} + +/* + Copyright 2019 Google LLC + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +/** + * Returns a promise that resolves and the passed number of milliseconds. + * This utility is an async/await-friendly version of `setTimeout`. + * + * @param {number} ms + * @return {Promise} + * @private + */ +function timeout(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +// @ts-ignore +try { + self['workbox:strategies:7.3.0'] && _(); +} catch (e) {} + +/* + Copyright 2020 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +function toRequest(input) { + return typeof input === 'string' ? new Request(input) : input; +} +/** + * A class created every time a Strategy instance calls + * {@link workbox-strategies.Strategy~handle} or + * {@link workbox-strategies.Strategy~handleAll} that wraps all fetch and + * cache actions around plugin callbacks and keeps track of when the strategy + * is "done" (i.e. all added `event.waitUntil()` promises have resolved). + * + * @memberof workbox-strategies + */ +class StrategyHandler { + /** + * Creates a new instance associated with the passed strategy and event + * that's handling the request. + * + * The constructor also initializes the state that will be passed to each of + * the plugins handling this request. + * + * @param {workbox-strategies.Strategy} strategy + * @param {Object} options + * @param {Request|string} options.request A request to run this strategy for. + * @param {ExtendableEvent} options.event The event associated with the + * request. + * @param {URL} [options.url] + * @param {*} [options.params] The return value from the + * {@link workbox-routing~matchCallback} (if applicable). + */ + constructor(strategy, options) { + this._cacheKeys = {}; + /** + * The request the strategy is performing (passed to the strategy's + * `handle()` or `handleAll()` method). + * @name request + * @instance + * @type {Request} + * @memberof workbox-strategies.StrategyHandler + */ + /** + * The event associated with this request. + * @name event + * @instance + * @type {ExtendableEvent} + * @memberof workbox-strategies.StrategyHandler + */ + /** + * A `URL` instance of `request.url` (if passed to the strategy's + * `handle()` or `handleAll()` method). + * Note: the `url` param will be present if the strategy was invoked + * from a workbox `Route` object. + * @name url + * @instance + * @type {URL|undefined} + * @memberof workbox-strategies.StrategyHandler + */ + /** + * A `param` value (if passed to the strategy's + * `handle()` or `handleAll()` method). + * Note: the `param` param will be present if the strategy was invoked + * from a workbox `Route` object and the + * {@link workbox-routing~matchCallback} returned + * a truthy value (it will be that value). + * @name params + * @instance + * @type {*|undefined} + * @memberof workbox-strategies.StrategyHandler + */ + { + finalAssertExports.isInstance(options.event, ExtendableEvent, { + moduleName: 'workbox-strategies', + className: 'StrategyHandler', + funcName: 'constructor', + paramName: 'options.event' + }); + } + Object.assign(this, options); + this.event = options.event; + this._strategy = strategy; + this._handlerDeferred = new Deferred(); + this._extendLifetimePromises = []; + // Copy the plugins list (since it's mutable on the strategy), + // so any mutations don't affect this handler instance. + this._plugins = [...strategy.plugins]; + this._pluginStateMap = new Map(); + for (const plugin of this._plugins) { + this._pluginStateMap.set(plugin, {}); + } + this.event.waitUntil(this._handlerDeferred.promise); + } + /** + * Fetches a given request (and invokes any applicable plugin callback + * methods) using the `fetchOptions` (for non-navigation requests) and + * `plugins` defined on the `Strategy` object. + * + * The following plugin lifecycle methods are invoked when using this method: + * - `requestWillFetch()` + * - `fetchDidSucceed()` + * - `fetchDidFail()` + * + * @param {Request|string} input The URL or request to fetch. + * @return {Promise} + */ + async fetch(input) { + const { + event + } = this; + let request = toRequest(input); + if (request.mode === 'navigate' && event instanceof FetchEvent && event.preloadResponse) { + const possiblePreloadResponse = await event.preloadResponse; + if (possiblePreloadResponse) { + { + logger.log(`Using a preloaded navigation response for ` + `'${getFriendlyURL(request.url)}'`); + } + return possiblePreloadResponse; + } + } + // If there is a fetchDidFail plugin, we need to save a clone of the + // original request before it's either modified by a requestWillFetch + // plugin or before the original request's body is consumed via fetch(). + const originalRequest = this.hasCallback('fetchDidFail') ? request.clone() : null; + try { + for (const cb of this.iterateCallbacks('requestWillFetch')) { + request = await cb({ + request: request.clone(), + event + }); + } + } catch (err) { + if (err instanceof Error) { + throw new WorkboxError('plugin-error-request-will-fetch', { + thrownErrorMessage: err.message + }); + } + } + // The request can be altered by plugins with `requestWillFetch` making + // the original request (most likely from a `fetch` event) different + // from the Request we make. Pass both to `fetchDidFail` to aid debugging. + const pluginFilteredRequest = request.clone(); + try { + let fetchResponse; + // See https://github.com/GoogleChrome/workbox/issues/1796 + fetchResponse = await fetch(request, request.mode === 'navigate' ? undefined : this._strategy.fetchOptions); + if ("development" !== 'production') { + logger.debug(`Network request for ` + `'${getFriendlyURL(request.url)}' returned a response with ` + `status '${fetchResponse.status}'.`); + } + for (const callback of this.iterateCallbacks('fetchDidSucceed')) { + fetchResponse = await callback({ + event, + request: pluginFilteredRequest, + response: fetchResponse + }); + } + return fetchResponse; + } catch (error) { + { + logger.log(`Network request for ` + `'${getFriendlyURL(request.url)}' threw an error.`, error); + } + // `originalRequest` will only exist if a `fetchDidFail` callback + // is being used (see above). + if (originalRequest) { + await this.runCallbacks('fetchDidFail', { + error: error, + event, + originalRequest: originalRequest.clone(), + request: pluginFilteredRequest.clone() + }); + } + throw error; + } + } + /** + * Calls `this.fetch()` and (in the background) runs `this.cachePut()` on + * the response generated by `this.fetch()`. + * + * The call to `this.cachePut()` automatically invokes `this.waitUntil()`, + * so you do not have to manually call `waitUntil()` on the event. + * + * @param {Request|string} input The request or URL to fetch and cache. + * @return {Promise} + */ + async fetchAndCachePut(input) { + const response = await this.fetch(input); + const responseClone = response.clone(); + void this.waitUntil(this.cachePut(input, responseClone)); + return response; + } + /** + * Matches a request from the cache (and invokes any applicable plugin + * callback methods) using the `cacheName`, `matchOptions`, and `plugins` + * defined on the strategy object. + * + * The following plugin lifecycle methods are invoked when using this method: + * - cacheKeyWillBeUsed() + * - cachedResponseWillBeUsed() + * + * @param {Request|string} key The Request or URL to use as the cache key. + * @return {Promise} A matching response, if found. + */ + async cacheMatch(key) { + const request = toRequest(key); + let cachedResponse; + const { + cacheName, + matchOptions + } = this._strategy; + const effectiveRequest = await this.getCacheKey(request, 'read'); + const multiMatchOptions = Object.assign(Object.assign({}, matchOptions), { + cacheName + }); + cachedResponse = await caches.match(effectiveRequest, multiMatchOptions); + { + if (cachedResponse) { + logger.debug(`Found a cached response in '${cacheName}'.`); + } else { + logger.debug(`No cached response found in '${cacheName}'.`); + } + } + for (const callback of this.iterateCallbacks('cachedResponseWillBeUsed')) { + cachedResponse = (await callback({ + cacheName, + matchOptions, + cachedResponse, + request: effectiveRequest, + event: this.event + })) || undefined; + } + return cachedResponse; + } + /** + * Puts a request/response pair in the cache (and invokes any applicable + * plugin callback methods) using the `cacheName` and `plugins` defined on + * the strategy object. + * + * The following plugin lifecycle methods are invoked when using this method: + * - cacheKeyWillBeUsed() + * - cacheWillUpdate() + * - cacheDidUpdate() + * + * @param {Request|string} key The request or URL to use as the cache key. + * @param {Response} response The response to cache. + * @return {Promise} `false` if a cacheWillUpdate caused the response + * not be cached, and `true` otherwise. + */ + async cachePut(key, response) { + const request = toRequest(key); + // Run in the next task to avoid blocking other cache reads. + // https://github.com/w3c/ServiceWorker/issues/1397 + await timeout(0); + const effectiveRequest = await this.getCacheKey(request, 'write'); + { + if (effectiveRequest.method && effectiveRequest.method !== 'GET') { + throw new WorkboxError('attempt-to-cache-non-get-request', { + url: getFriendlyURL(effectiveRequest.url), + method: effectiveRequest.method + }); + } + // See https://github.com/GoogleChrome/workbox/issues/2818 + const vary = response.headers.get('Vary'); + if (vary) { + logger.debug(`The response for ${getFriendlyURL(effectiveRequest.url)} ` + `has a 'Vary: ${vary}' header. ` + `Consider setting the {ignoreVary: true} option on your strategy ` + `to ensure cache matching and deletion works as expected.`); + } + } + if (!response) { + { + logger.error(`Cannot cache non-existent response for ` + `'${getFriendlyURL(effectiveRequest.url)}'.`); + } + throw new WorkboxError('cache-put-with-no-response', { + url: getFriendlyURL(effectiveRequest.url) + }); + } + const responseToCache = await this._ensureResponseSafeToCache(response); + if (!responseToCache) { + { + logger.debug(`Response '${getFriendlyURL(effectiveRequest.url)}' ` + `will not be cached.`, responseToCache); + } + return false; + } + const { + cacheName, + matchOptions + } = this._strategy; + const cache = await self.caches.open(cacheName); + const hasCacheUpdateCallback = this.hasCallback('cacheDidUpdate'); + const oldResponse = hasCacheUpdateCallback ? await cacheMatchIgnoreParams( + // TODO(philipwalton): the `__WB_REVISION__` param is a precaching + // feature. Consider into ways to only add this behavior if using + // precaching. + cache, effectiveRequest.clone(), ['__WB_REVISION__'], matchOptions) : null; + { + logger.debug(`Updating the '${cacheName}' cache with a new Response ` + `for ${getFriendlyURL(effectiveRequest.url)}.`); + } + try { + await cache.put(effectiveRequest, hasCacheUpdateCallback ? responseToCache.clone() : responseToCache); + } catch (error) { + if (error instanceof Error) { + // See https://developer.mozilla.org/en-US/docs/Web/API/DOMException#exception-QuotaExceededError + if (error.name === 'QuotaExceededError') { + await executeQuotaErrorCallbacks(); + } + throw error; + } + } + for (const callback of this.iterateCallbacks('cacheDidUpdate')) { + await callback({ + cacheName, + oldResponse, + newResponse: responseToCache.clone(), + request: effectiveRequest, + event: this.event + }); + } + return true; + } + /** + * Checks the list of plugins for the `cacheKeyWillBeUsed` callback, and + * executes any of those callbacks found in sequence. The final `Request` + * object returned by the last plugin is treated as the cache key for cache + * reads and/or writes. If no `cacheKeyWillBeUsed` plugin callbacks have + * been registered, the passed request is returned unmodified + * + * @param {Request} request + * @param {string} mode + * @return {Promise} + */ + async getCacheKey(request, mode) { + const key = `${request.url} | ${mode}`; + if (!this._cacheKeys[key]) { + let effectiveRequest = request; + for (const callback of this.iterateCallbacks('cacheKeyWillBeUsed')) { + effectiveRequest = toRequest(await callback({ + mode, + request: effectiveRequest, + event: this.event, + // params has a type any can't change right now. + params: this.params // eslint-disable-line + })); + } + this._cacheKeys[key] = effectiveRequest; + } + return this._cacheKeys[key]; + } + /** + * Returns true if the strategy has at least one plugin with the given + * callback. + * + * @param {string} name The name of the callback to check for. + * @return {boolean} + */ + hasCallback(name) { + for (const plugin of this._strategy.plugins) { + if (name in plugin) { + return true; + } + } + return false; + } + /** + * Runs all plugin callbacks matching the given name, in order, passing the + * given param object (merged ith the current plugin state) as the only + * argument. + * + * Note: since this method runs all plugins, it's not suitable for cases + * where the return value of a callback needs to be applied prior to calling + * the next callback. See + * {@link workbox-strategies.StrategyHandler#iterateCallbacks} + * below for how to handle that case. + * + * @param {string} name The name of the callback to run within each plugin. + * @param {Object} param The object to pass as the first (and only) param + * when executing each callback. This object will be merged with the + * current plugin state prior to callback execution. + */ + async runCallbacks(name, param) { + for (const callback of this.iterateCallbacks(name)) { + // TODO(philipwalton): not sure why `any` is needed. It seems like + // this should work with `as WorkboxPluginCallbackParam[C]`. + await callback(param); + } + } + /** + * Accepts a callback and returns an iterable of matching plugin callbacks, + * where each callback is wrapped with the current handler state (i.e. when + * you call each callback, whatever object parameter you pass it will + * be merged with the plugin's current state). + * + * @param {string} name The name fo the callback to run + * @return {Array} + */ + *iterateCallbacks(name) { + for (const plugin of this._strategy.plugins) { + if (typeof plugin[name] === 'function') { + const state = this._pluginStateMap.get(plugin); + const statefulCallback = param => { + const statefulParam = Object.assign(Object.assign({}, param), { + state + }); + // TODO(philipwalton): not sure why `any` is needed. It seems like + // this should work with `as WorkboxPluginCallbackParam[C]`. + return plugin[name](statefulParam); + }; + yield statefulCallback; + } + } + } + /** + * Adds a promise to the + * [extend lifetime promises]{@link https://w3c.github.io/ServiceWorker/#extendableevent-extend-lifetime-promises} + * of the event associated with the request being handled (usually a + * `FetchEvent`). + * + * Note: you can await + * {@link workbox-strategies.StrategyHandler~doneWaiting} + * to know when all added promises have settled. + * + * @param {Promise} promise A promise to add to the extend lifetime promises + * of the event that triggered the request. + */ + waitUntil(promise) { + this._extendLifetimePromises.push(promise); + return promise; + } + /** + * Returns a promise that resolves once all promises passed to + * {@link workbox-strategies.StrategyHandler~waitUntil} + * have settled. + * + * Note: any work done after `doneWaiting()` settles should be manually + * passed to an event's `waitUntil()` method (not this handler's + * `waitUntil()` method), otherwise the service worker thread may be killed + * prior to your work completing. + */ + async doneWaiting() { + while (this._extendLifetimePromises.length) { + const promises = this._extendLifetimePromises.splice(0); + const result = await Promise.allSettled(promises); + const firstRejection = result.find(i => i.status === 'rejected'); + if (firstRejection) { + throw firstRejection.reason; + } + } + } + /** + * Stops running the strategy and immediately resolves any pending + * `waitUntil()` promises. + */ + destroy() { + this._handlerDeferred.resolve(null); + } + /** + * This method will call cacheWillUpdate on the available plugins (or use + * status === 200) to determine if the Response is safe and valid to cache. + * + * @param {Request} options.request + * @param {Response} options.response + * @return {Promise} + * + * @private + */ + async _ensureResponseSafeToCache(response) { + let responseToCache = response; + let pluginsUsed = false; + for (const callback of this.iterateCallbacks('cacheWillUpdate')) { + responseToCache = (await callback({ + request: this.request, + response: responseToCache, + event: this.event + })) || undefined; + pluginsUsed = true; + if (!responseToCache) { + break; + } + } + if (!pluginsUsed) { + if (responseToCache && responseToCache.status !== 200) { + responseToCache = undefined; + } + { + if (responseToCache) { + if (responseToCache.status !== 200) { + if (responseToCache.status === 0) { + logger.warn(`The response for '${this.request.url}' ` + `is an opaque response. The caching strategy that you're ` + `using will not cache opaque responses by default.`); + } else { + logger.debug(`The response for '${this.request.url}' ` + `returned a status code of '${response.status}' and won't ` + `be cached as a result.`); + } + } + } + } + } + return responseToCache; + } +} + +/* + Copyright 2020 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +/** + * An abstract base class that all other strategy classes must extend from: + * + * @memberof workbox-strategies + */ +class Strategy { + /** + * Creates a new instance of the strategy and sets all documented option + * properties as public instance properties. + * + * Note: if a custom strategy class extends the base Strategy class and does + * not need more than these properties, it does not need to define its own + * constructor. + * + * @param {Object} [options] + * @param {string} [options.cacheName] Cache name to store and retrieve + * requests. Defaults to the cache names provided by + * {@link workbox-core.cacheNames}. + * @param {Array} [options.plugins] [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins} + * to use in conjunction with this caching strategy. + * @param {Object} [options.fetchOptions] Values passed along to the + * [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters) + * of [non-navigation](https://github.com/GoogleChrome/workbox/issues/1796) + * `fetch()` requests made by this strategy. + * @param {Object} [options.matchOptions] The + * [`CacheQueryOptions`]{@link https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions} + * for any `cache.match()` or `cache.put()` calls made by this strategy. + */ + constructor(options = {}) { + /** + * Cache name to store and retrieve + * requests. Defaults to the cache names provided by + * {@link workbox-core.cacheNames}. + * + * @type {string} + */ + this.cacheName = cacheNames.getRuntimeName(options.cacheName); + /** + * The list + * [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins} + * used by this strategy. + * + * @type {Array} + */ + this.plugins = options.plugins || []; + /** + * Values passed along to the + * [`init`]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters} + * of all fetch() requests made by this strategy. + * + * @type {Object} + */ + this.fetchOptions = options.fetchOptions; + /** + * The + * [`CacheQueryOptions`]{@link https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions} + * for any `cache.match()` or `cache.put()` calls made by this strategy. + * + * @type {Object} + */ + this.matchOptions = options.matchOptions; + } + /** + * Perform a request strategy and returns a `Promise` that will resolve with + * a `Response`, invoking all relevant plugin callbacks. + * + * When a strategy instance is registered with a Workbox + * {@link workbox-routing.Route}, this method is automatically + * called when the route matches. + * + * Alternatively, this method can be used in a standalone `FetchEvent` + * listener by passing it to `event.respondWith()`. + * + * @param {FetchEvent|Object} options A `FetchEvent` or an object with the + * properties listed below. + * @param {Request|string} options.request A request to run this strategy for. + * @param {ExtendableEvent} options.event The event associated with the + * request. + * @param {URL} [options.url] + * @param {*} [options.params] + */ + handle(options) { + const [responseDone] = this.handleAll(options); + return responseDone; + } + /** + * Similar to {@link workbox-strategies.Strategy~handle}, but + * instead of just returning a `Promise` that resolves to a `Response` it + * it will return an tuple of `[response, done]` promises, where the former + * (`response`) is equivalent to what `handle()` returns, and the latter is a + * Promise that will resolve once any promises that were added to + * `event.waitUntil()` as part of performing the strategy have completed. + * + * You can await the `done` promise to ensure any extra work performed by + * the strategy (usually caching responses) completes successfully. + * + * @param {FetchEvent|Object} options A `FetchEvent` or an object with the + * properties listed below. + * @param {Request|string} options.request A request to run this strategy for. + * @param {ExtendableEvent} options.event The event associated with the + * request. + * @param {URL} [options.url] + * @param {*} [options.params] + * @return {Array} A tuple of [response, done] + * promises that can be used to determine when the response resolves as + * well as when the handler has completed all its work. + */ + handleAll(options) { + // Allow for flexible options to be passed. + if (options instanceof FetchEvent) { + options = { + event: options, + request: options.request + }; + } + const event = options.event; + const request = typeof options.request === 'string' ? new Request(options.request) : options.request; + const params = 'params' in options ? options.params : undefined; + const handler = new StrategyHandler(this, { + event, + request, + params + }); + const responseDone = this._getResponse(handler, request, event); + const handlerDone = this._awaitComplete(responseDone, handler, request, event); + // Return an array of promises, suitable for use with Promise.all(). + return [responseDone, handlerDone]; + } + async _getResponse(handler, request, event) { + await handler.runCallbacks('handlerWillStart', { + event, + request + }); + let response = undefined; + try { + response = await this._handle(request, handler); + // The "official" Strategy subclasses all throw this error automatically, + // but in case a third-party Strategy doesn't, ensure that we have a + // consistent failure when there's no response or an error response. + if (!response || response.type === 'error') { + throw new WorkboxError('no-response', { + url: request.url + }); + } + } catch (error) { + if (error instanceof Error) { + for (const callback of handler.iterateCallbacks('handlerDidError')) { + response = await callback({ + error, + event, + request + }); + if (response) { + break; + } + } + } + if (!response) { + throw error; + } else { + logger.log(`While responding to '${getFriendlyURL(request.url)}', ` + `an ${error instanceof Error ? error.toString() : ''} error occurred. Using a fallback response provided by ` + `a handlerDidError plugin.`); + } + } + for (const callback of handler.iterateCallbacks('handlerWillRespond')) { + response = await callback({ + event, + request, + response + }); + } + return response; + } + async _awaitComplete(responseDone, handler, request, event) { + let response; + let error; + try { + response = await responseDone; + } catch (error) { + // Ignore errors, as response errors should be caught via the `response` + // promise above. The `done` promise will only throw for errors in + // promises passed to `handler.waitUntil()`. + } + try { + await handler.runCallbacks('handlerDidRespond', { + event, + request, + response + }); + await handler.doneWaiting(); + } catch (waitUntilError) { + if (waitUntilError instanceof Error) { + error = waitUntilError; + } + } + await handler.runCallbacks('handlerDidComplete', { + event, + request, + response, + error: error + }); + handler.destroy(); + if (error) { + throw error; + } + } +} +/** + * Classes extending the `Strategy` based class should implement this method, + * and leverage the {@link workbox-strategies.StrategyHandler} + * arg to perform all fetching and cache logic, which will ensure all relevant + * cache, cache options, fetch options and plugins are used (per the current + * strategy instance). + * + * @name _handle + * @instance + * @abstract + * @function + * @param {Request} request + * @param {workbox-strategies.StrategyHandler} handler + * @return {Promise} + * + * @memberof workbox-strategies.Strategy + */ + +/* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +const messages = { + strategyStart: (strategyName, request) => `Using ${strategyName} to respond to '${getFriendlyURL(request.url)}'`, + printFinalResponse: response => { + if (response) { + logger.groupCollapsed(`View the final response here.`); + logger.log(response || '[No response returned]'); + logger.groupEnd(); + } + } +}; + +/* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +/** + * An implementation of a [cache-first](https://developer.chrome.com/docs/workbox/caching-strategies-overview/#cache-first-falling-back-to-network) + * request strategy. + * + * A cache first strategy is useful for assets that have been revisioned, + * such as URLs like `/styles/example.a8f5f1.css`, since they + * can be cached for long periods of time. + * + * If the network request fails, and there is no cache match, this will throw + * a `WorkboxError` exception. + * + * @extends workbox-strategies.Strategy + * @memberof workbox-strategies + */ +class CacheFirst extends Strategy { + /** + * @private + * @param {Request|string} request A request to run this strategy for. + * @param {workbox-strategies.StrategyHandler} handler The event that + * triggered the request. + * @return {Promise} + */ + async _handle(request, handler) { + const logs = []; + { + finalAssertExports.isInstance(request, Request, { + moduleName: 'workbox-strategies', + className: this.constructor.name, + funcName: 'makeRequest', + paramName: 'request' + }); + } + let response = await handler.cacheMatch(request); + let error = undefined; + if (!response) { + { + logs.push(`No response found in the '${this.cacheName}' cache. ` + `Will respond with a network request.`); + } + try { + response = await handler.fetchAndCachePut(request); + } catch (err) { + if (err instanceof Error) { + error = err; + } + } + { + if (response) { + logs.push(`Got response from network.`); + } else { + logs.push(`Unable to get a response from the network.`); + } + } + } else { + { + logs.push(`Found a cached response in the '${this.cacheName}' cache.`); + } + } + { + logger.groupCollapsed(messages.strategyStart(this.constructor.name, request)); + for (const log of logs) { + logger.log(log); + } + messages.printFinalResponse(response); + logger.groupEnd(); + } + if (!response) { + throw new WorkboxError('no-response', { + url: request.url, + error + }); + } + return response; + } +} + +/* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. +*/ +/** + * Claim any currently available clients once the service worker + * becomes active. This is normally used in conjunction with `skipWaiting()`. + * + * @memberof workbox-core + */ +function clientsClaim() { + self.addEventListener('activate', () => self.clients.claim()); +} + +self.skipWaiting(); +clientsClaim(); +registerRoute(/^.*\/apps\/photos\/api\/v1\/preview\/.*/, new CacheFirst({ + "cacheName": "images", + plugins: [new ExpirationPlugin({ + maxAgeSeconds: 604800, + maxEntries: 10000 + })] +}), 'GET'); diff --git a/js/photos-sidebar.mjs b/js/photos-sidebar.mjs index 62a746036a..b9c91bc87f 100644 --- a/js/photos-sidebar.mjs +++ b/js/photos-sidebar.mjs @@ -1,3 +1,58 @@ -const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=[window.OC.filePath('photos', '', 'js/PhotosTab-CjppOqbr.chunk.mjs'),window.OC.filePath('photos', '', 'js/index-H-n78F4h.chunk.mjs'),window.OC.filePath('photos', '', 'js/vue.runtime.esm-DCKfRL7V.chunk.mjs'),window.OC.filePath('photos', '', 'js/icons-BRqI-hCR.chunk.mjs'),window.OC.filePath('photos', '', 'css/PhotosTab-DGphhlff.chunk.css')])))=>i.map(i=>d[i]); -import{_ as s}from"./preload-helper-DxYC2qmj.chunk.mjs";import{t as d,V as n,c as u,e as o}from"./vue.runtime.esm-DCKfRL7V.chunk.mjs";const m='';n.prototype.t=d,n.prototype.n=u,o("nc:metadata-photos-exif"),o("nc:metadata-photos-ifd0"),o("nc:metadata-photos-gps"),o("nc:metadata-photos-place");let a=null,t=null;const c=new OCA.Files.Sidebar.Tab({id:"photos",name:d("photos","Details"),iconSvg:m,async mount(e,i,r){if(a===null){const{default:l}=await s(async()=>{const{default:p}=await import("./PhotosTab-CjppOqbr.chunk.mjs");return{default:p}},__vite__mapDeps([0,1,2,3,4]),import.meta.url);a=a??n.extend(l)}t&&t.$destroy(),t=new a({parent:r}),t.update(i),t.$mount(e)},update(e){t.update(e)},destroy(){t.$destroy(),t=null}});window.addEventListener("DOMContentLoaded",async function(){if(window.OCA.Files&&window.OCA.Files.Sidebar){window.OCA.Files.Sidebar.registerTab(c);const{default:e}=await s(async()=>{const{default:i}=await import("./PhotosTab-CjppOqbr.chunk.mjs");return{default:i}},__vite__mapDeps([0,1,2,3,4]),import.meta.url);a=a??n.extend(e)}}); +const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=[window.OC.filePath('photos', '', 'js/PhotosTab-BnDoRk-N.chunk.mjs'),window.OC.filePath('photos', '', 'js/index-CEGJzzBP.chunk.mjs'),window.OC.filePath('photos', '', 'js/vue.runtime.esm-D0MRZEe4.chunk.mjs'),window.OC.filePath('photos', '', 'js/icons-DpGfY1yM.chunk.mjs'),window.OC.filePath('photos', '', 'css/PhotosTab-D8FpRNKm.chunk.css')])))=>i.map(i=>d[i]); +const appName = "photos"; +const appVersion = "5.0.2"; +import { _ as __vitePreload } from "./preload-helper-BH8-nKqv.chunk.mjs"; +import { t as translate, V as Vue, c as translatePlural, e as registerDavProperty } from "./vue.runtime.esm-D0MRZEe4.chunk.mjs"; +const InformationOutline = ''; +Vue.prototype.t = translate; +Vue.prototype.n = translatePlural; +registerDavProperty("nc:metadata-photos-exif"); +registerDavProperty("nc:metadata-photos-ifd0"); +registerDavProperty("nc:metadata-photos-gps"); +registerDavProperty("nc:metadata-photos-place"); +let PhotosTabView = null; +let PhotosTabInstance = null; +const photosTab = new OCA.Files.Sidebar.Tab({ + id: "photos", + name: translate("photos", "Details"), + iconSvg: InformationOutline, + async mount(el, fileInfo, context) { + if (PhotosTabView === null) { + const { default: PhotosTab } = await __vitePreload(async () => { + const { default: PhotosTab2 } = await import("./PhotosTab-BnDoRk-N.chunk.mjs"); + return { default: PhotosTab2 }; + }, true ? __vite__mapDeps([0,1,2,3,4]) : void 0, import.meta.url); + PhotosTabView = PhotosTabView ?? Vue.extend(PhotosTab); + } + if (PhotosTabInstance) { + PhotosTabInstance.$destroy(); + } + PhotosTabInstance = new PhotosTabView({ + // Better integration with vue parent component + parent: context + }); + PhotosTabInstance.update(fileInfo); + PhotosTabInstance.$mount(el); + }, + update(fileInfo) { + PhotosTabInstance.update(fileInfo); + }, + destroy() { + PhotosTabInstance.$destroy(); + PhotosTabInstance = null; + } +}); +window.addEventListener("DOMContentLoaded", async function() { + if (window.OCA.Files && window.OCA.Files.Sidebar) { + window.OCA.Files.Sidebar.registerTab(photosTab); + const { default: PhotosTab } = await __vitePreload(async () => { + const { default: PhotosTab2 } = await import( + /* webpackPreload: true */ + "./PhotosTab-BnDoRk-N.chunk.mjs" + ); + return { default: PhotosTab2 }; + }, true ? __vite__mapDeps([0,1,2,3,4]) : void 0, import.meta.url); + PhotosTabView = PhotosTabView ?? Vue.extend(PhotosTab); + } +}); //# sourceMappingURL=photos-sidebar.mjs.map diff --git a/js/photos-sidebar.mjs.license b/js/photos-sidebar.mjs.license deleted file mode 100644 index 4867d08d4b..0000000000 --- a/js/photos-sidebar.mjs.license +++ /dev/null @@ -1,12 +0,0 @@ -SPDX-License-Identifier: AGPL-3.0-or-later -SPDX-License-Identifier: Apache-2.0 -SPDX-FileCopyrightText: Austin Andrews -SPDX-FileCopyrightText: John Molakvoæ - -This file is generated from multiple sources. Included packages: -- @mdi/svg - - version: 7.4.47 - - license: Apache-2.0 -- photos - - version: 5.0.0-dev.1 - - license: AGPL-3.0-or-later diff --git a/js/photos-sidebar.mjs.map b/js/photos-sidebar.mjs.map index d6a6f29373..ef1dc453a4 100644 --- a/js/photos-sidebar.mjs.map +++ b/js/photos-sidebar.mjs.map @@ -1 +1 @@ -{"version":3,"mappings":";sIAAA,MAAAA,EAAe,sTCSfC,EAAI,UAAU,EAAIC,EAClBD,EAAI,UAAU,EAAIE,EAElBC,EAAoB,yBAAyB,EAC7CA,EAAoB,yBAAyB,EAC7CA,EAAoB,wBAAwB,EAC5CA,EAAoB,0BAA0B,EAG9C,IAAIC,EAAgB,KAChBC,EAAoB,KACxB,MAAMC,EAAY,IAAI,IAAI,MAAM,QAAQ,IAAI,CAC3C,GAAI,SACJ,KAAML,EAAE,SAAU,SAAS,EAC3B,QAASF,EAET,MAAM,MAAMQ,EAAIC,EAAUC,EAAS,CAElC,GAAIL,IAAkB,KAAM,CAC3B,KAAM,CAAE,QAASM,CAAA,EAAc,MAAAC,EAAA,wBAAAD,CAAA,OAAM,QAAO,gCAAuB,iBAAAA,CAAA,iDACnEN,EAAgBA,GAAiBJ,EAAI,OAAOU,CAAS,CACtD,CAEIL,GACHA,EAAkB,WAEnBA,EAAoB,IAAID,EAAc,CAErC,OAAQK,CAAA,CACR,EAEDJ,EAAkB,OAAOG,CAAQ,EACjCH,EAAkB,OAAOE,CAAE,CAC5B,EACA,OAAOC,EAAU,CAChBH,EAAkB,OAAOG,CAAQ,CAClC,EACA,SAAU,CACTH,EAAkB,WAClBA,EAAoB,IACrB,CACD,CAAC,EAED,OAAO,iBAAiB,mBAAoB,gBAAiB,CAC5D,GAAI,OAAO,IAAI,OAAS,OAAO,IAAI,MAAM,QAAS,CACjD,OAAO,IAAI,MAAM,QAAQ,YAAYC,CAAS,EAC9C,KAAM,CAAE,QAASI,CAAA,EAAc,gDAAwC,kCAAuB,eAAAA,CAAA,iDAC9FN,EAAgBA,GAAiBJ,EAAI,OAAOU,CAAS,CACtD,CACD,CAAC","names":["InformationOutline","Vue","t","n","registerDavProperty","PhotosTabView","PhotosTabInstance","photosTab","el","fileInfo","context","PhotosTab","__vitePreload"],"ignoreList":[0],"sources":["../node_modules/@mdi/svg/svg/information-outline.svg?raw","../src/sidebar.ts"],"sourcesContent":["export default \"\"","import InformationOutline from '@mdi/svg/svg/information-outline.svg?raw'\nimport { registerDavProperty } from '@nextcloud/files/dav'\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\n/**\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport Vue from 'vue'\n\nVue.prototype.t = t\nVue.prototype.n = n\n\nregisterDavProperty('nc:metadata-photos-exif')\nregisterDavProperty('nc:metadata-photos-ifd0')\nregisterDavProperty('nc:metadata-photos-gps')\nregisterDavProperty('nc:metadata-photos-place')\n\n// Init Photos tab component\nlet PhotosTabView = null\nlet PhotosTabInstance = null\nconst photosTab = new OCA.Files.Sidebar.Tab({\n\tid: 'photos',\n\tname: t('photos', 'Details'),\n\ticonSvg: InformationOutline,\n\n\tasync mount(el, fileInfo, context) {\n\t\t// only load if needed\n\t\tif (PhotosTabView === null) {\n\t\t\tconst { default: PhotosTab } = await import('./views/PhotosTab.vue')\n\t\t\tPhotosTabView = PhotosTabView ?? Vue.extend(PhotosTab)\n\t\t}\n\t\t// destroy previous instance if available\n\t\tif (PhotosTabInstance) {\n\t\t\tPhotosTabInstance.$destroy()\n\t\t}\n\t\tPhotosTabInstance = new PhotosTabView({\n\t\t\t// Better integration with vue parent component\n\t\t\tparent: context,\n\t\t})\n\t\t// No need to await this, we will show a loading indicator instead\n\t\tPhotosTabInstance.update(fileInfo)\n\t\tPhotosTabInstance.$mount(el)\n\t},\n\tupdate(fileInfo) {\n\t\tPhotosTabInstance.update(fileInfo)\n\t},\n\tdestroy() {\n\t\tPhotosTabInstance.$destroy()\n\t\tPhotosTabInstance = null\n\t},\n})\n\nwindow.addEventListener('DOMContentLoaded', async function() {\n\tif (window.OCA.Files && window.OCA.Files.Sidebar) {\n\t\twindow.OCA.Files.Sidebar.registerTab(photosTab)\n\t\tconst { default: PhotosTab } = await import(/* webpackPreload: true */ './views/PhotosTab.vue')\n\t\tPhotosTabView = PhotosTabView ?? Vue.extend(PhotosTab)\n\t}\n})\n"],"file":"photos-sidebar.mjs"} \ No newline at end of file +{"version":3,"mappings":";;;;;AAAA,2BAAe;ACSf,IAAI,UAAU,IAAIA;AAClB,IAAI,UAAU,IAAIC;AAElB,oBAAoB,yBAAyB;AAC7C,oBAAoB,yBAAyB;AAC7C,oBAAoB,wBAAwB;AAC5C,oBAAoB,0BAA0B;AAG9C,IAAI,gBAAgB;AACpB,IAAI,oBAAoB;AACxB,MAAM,YAAY,IAAI,IAAI,MAAM,QAAQ,IAAI;AAAA,EAC3C,IAAI;AAAA,EACJ,MAAMD,UAAE,UAAU,SAAS;AAAA,EAC3B,SAAS;AAAA,EAET,MAAM,MAAM,IAAI,UAAU,SAAS;AAElC,QAAI,kBAAkB,MAAM;AAC3B,YAAM,EAAE,SAAS,cAAc;AAAA,yBAAAE,WAAA,UAAM,OAAO,gCAAuB;AAAA,0BAAAA,WAAA;AAAA;AACnE,sBAAgB,iBAAiB,IAAI,OAAO,SAAS;AAAA,IACtD;AAEA,QAAI,mBAAmB;AACtB,wBAAkB;AAAA,IACnB;AACA,wBAAoB,IAAI,cAAc;AAAA;AAAA,MAErC,QAAQ;AAAA,KACR;AAED,sBAAkB,OAAO,QAAQ;AACjC,sBAAkB,OAAO,EAAE;AAAA,EAC5B;AAAA,EACA,OAAO,UAAU;AAChB,sBAAkB,OAAO,QAAQ;AAAA,EAClC;AAAA,EACA,UAAU;AACT,sBAAkB;AAClB,wBAAoB;AAAA,EACrB;AACD,CAAC;AAED,OAAO,iBAAiB,oBAAoB,iBAAiB;AAC5D,MAAI,OAAO,IAAI,SAAS,OAAO,IAAI,MAAM,SAAS;AACjD,WAAO,IAAI,MAAM,QAAQ,YAAY,SAAS;AAC9C,UAAM,EAAE,SAAS,cAAc;4CAAM;AAAA;AAAA,QAAkC;AAAA;AAAuB,wBAAAA,WAAA;AAAA;AAC9F,oBAAgB,iBAAiB,IAAI,OAAO,SAAS;AAAA,EACtD;AACD,CAAC","names":["t","n","PhotosTab"],"ignoreList":[0],"sources":["../node_modules/@mdi/svg/svg/information-outline.svg?raw","../src/sidebar.ts"],"sourcesContent":["export default \"\"","import InformationOutline from '@mdi/svg/svg/information-outline.svg?raw'\nimport { registerDavProperty } from '@nextcloud/files/dav'\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\n/**\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport Vue from 'vue'\n\nVue.prototype.t = t\nVue.prototype.n = n\n\nregisterDavProperty('nc:metadata-photos-exif')\nregisterDavProperty('nc:metadata-photos-ifd0')\nregisterDavProperty('nc:metadata-photos-gps')\nregisterDavProperty('nc:metadata-photos-place')\n\n// Init Photos tab component\nlet PhotosTabView = null\nlet PhotosTabInstance = null\nconst photosTab = new OCA.Files.Sidebar.Tab({\n\tid: 'photos',\n\tname: t('photos', 'Details'),\n\ticonSvg: InformationOutline,\n\n\tasync mount(el, fileInfo, context) {\n\t\t// only load if needed\n\t\tif (PhotosTabView === null) {\n\t\t\tconst { default: PhotosTab } = await import('./views/PhotosTab.vue')\n\t\t\tPhotosTabView = PhotosTabView ?? Vue.extend(PhotosTab)\n\t\t}\n\t\t// destroy previous instance if available\n\t\tif (PhotosTabInstance) {\n\t\t\tPhotosTabInstance.$destroy()\n\t\t}\n\t\tPhotosTabInstance = new PhotosTabView({\n\t\t\t// Better integration with vue parent component\n\t\t\tparent: context,\n\t\t})\n\t\t// No need to await this, we will show a loading indicator instead\n\t\tPhotosTabInstance.update(fileInfo)\n\t\tPhotosTabInstance.$mount(el)\n\t},\n\tupdate(fileInfo) {\n\t\tPhotosTabInstance.update(fileInfo)\n\t},\n\tdestroy() {\n\t\tPhotosTabInstance.$destroy()\n\t\tPhotosTabInstance = null\n\t},\n})\n\nwindow.addEventListener('DOMContentLoaded', async function() {\n\tif (window.OCA.Files && window.OCA.Files.Sidebar) {\n\t\twindow.OCA.Files.Sidebar.registerTab(photosTab)\n\t\tconst { default: PhotosTab } = await import(/* webpackPreload: true */ './views/PhotosTab.vue')\n\t\tPhotosTabView = PhotosTabView ?? Vue.extend(PhotosTab)\n\t}\n})\n"],"file":"photos-sidebar.mjs"} \ No newline at end of file diff --git a/js/preload-helper-DxYC2qmj.chunk.mjs b/js/preload-helper-DxYC2qmj.chunk.mjs deleted file mode 100644 index 1d8fd1bfca..0000000000 --- a/js/preload-helper-DxYC2qmj.chunk.mjs +++ /dev/null @@ -1,2 +0,0 @@ -const v="modulepreload",y=function(a,s){return new URL(a,s).href},p={},E=function(a,s,u){let d=Promise.resolve();if(s&&s.length>0){let o=function(e){return Promise.all(e.map(r=>Promise.resolve(r).then(l=>({status:"fulfilled",value:l}),l=>({status:"rejected",reason:l}))))};const t=document.getElementsByTagName("link"),h=document.querySelector("meta[property=csp-nonce]"),m=h?.nonce||h?.getAttribute("nonce");d=o(s.map(e=>{if(e=y(e,u),e in p)return;p[e]=!0;const r=e.endsWith(".css"),l=r?'[rel="stylesheet"]':"";if(u)for(let c=t.length-1;c>=0;c--){const i=t[c];if(i.href===e&&(!r||i.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${e}"]${l}`))return;const n=document.createElement("link");if(n.rel=r?"stylesheet":v,r||(n.as="script"),n.crossOrigin="",n.href=e,m&&n.setAttribute("nonce",m),document.head.appendChild(n),r)return new Promise((c,i)=>{n.addEventListener("load",c),n.addEventListener("error",()=>i(new Error(`Unable to preload CSS for ${e}`)))})}))}function f(o){const t=new Event("vite:preloadError",{cancelable:!0});if(t.payload=o,window.dispatchEvent(t),!t.defaultPrevented)throw o}return d.then(o=>{for(const t of o||[])t.status==="rejected"&&f(t.reason);return a().catch(f)})};export{E as _}; -//# sourceMappingURL=preload-helper-DxYC2qmj.chunk.mjs.map diff --git a/js/preload-helper-DxYC2qmj.chunk.mjs.license b/js/preload-helper-DxYC2qmj.chunk.mjs.license deleted file mode 100644 index 49319894ba..0000000000 --- a/js/preload-helper-DxYC2qmj.chunk.mjs.license +++ /dev/null @@ -1,7 +0,0 @@ -SPDX-License-Identifier: MIT -SPDX-FileCopyrightText: Evan You - -This file is generated from multiple sources. Included packages: -- vite - - version: 7.3.0 - - license: MIT diff --git a/js/preload-helper-DxYC2qmj.chunk.mjs.map b/js/preload-helper-DxYC2qmj.chunk.mjs.map deleted file mode 100644 index 80096ad448..0000000000 --- a/js/preload-helper-DxYC2qmj.chunk.mjs.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"preload-helper-DxYC2qmj.chunk.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":""} \ No newline at end of file diff --git a/src/views/AlbumContent.vue b/src/views/AlbumContent.vue index f078a53743..67d8fe8ab8 100644 --- a/src/views/AlbumContent.vue +++ b/src/views/AlbumContent.vue @@ -33,7 +33,7 @@ {{ selectedFileIds.length }} {{ t('photos', 'selected') }} - + @@ -311,6 +312,7 @@ export default { loadingAddCollaborators: false, allowedMimes, uploader: getUploader(), + windowWidth: typeof window !== 'undefined' ? window.innerWidth : 0, } }, @@ -338,6 +340,19 @@ export default { .map((file) => file.fileid.toString()) }, + inlineActions() { + if (this.windowWidth < 512) { + return 0 + } + if (this.windowWidth < 768) { + return 1 + } + if (this.windowWidth < 1024) { + return 2 + } + return 3 + }, + croppedLayout() { return this.$store.state.userConfig.croppedLayout }, @@ -371,6 +386,11 @@ export default { async mounted() { this.fetchAlbum() this.fetchAlbumContent() + window.addEventListener('resize', this.handleResize) + }, + + destroyed() { + window.removeEventListener('resize', this.handleResize) }, methods: { @@ -380,6 +400,10 @@ export default { albumsExtraProps, ) }, + + handleResize() { + this.windowWidth = window.innerWidth + }, async fetchAlbumContent() { await this.fetchCollectionFiles(this.albumFileName, albumFilesExtraProps)