From 3f21d10338afe8eab699aaaea060556579e4b3c3 Mon Sep 17 00:00:00 2001
From: Zero~Informatique
Date: Sat, 21 Dec 2019 10:33:21 +0100
Subject: viewer: Some renaming for better clarity Implemented a basic display
 of filenames with basic navigation

---
 viewer/src/views/Gallery.vue | 60 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)
 create mode 100644 viewer/src/views/Gallery.vue

(limited to 'viewer/src/views/Gallery.vue')

diff --git a/viewer/src/views/Gallery.vue b/viewer/src/views/Gallery.vue
new file mode 100644
index 0000000..3625838
--- /dev/null
+++ b/viewer/src/views/Gallery.vue
@@ -0,0 +1,60 @@
+<template>
+  <div id="test-flex-col">
+    <div v-if="isDirectory">
+      <strong>Directory: {{currentItem.path}}</strong>
+      <div v-for="(item, index) in currentItem.properties.items" :key="item.path">
+        <router-link :to="item.path">Thumbnail: {{index}}-{{item.path}}</router-link>
+      </div>
+    </div>
+    <div v-if="isImage">Image: {{currentItem.path}}</div>
+  </div>
+</template>
+
+<script lang="ts">
+import { Component, Vue, Prop } from "vue-property-decorator";
+
+@Component
+export default class Root extends Vue {
+  @Prop(String) readonly pathMatch!: string;
+
+  get isDirectory(): boolean {
+    return this.checkType("directory");
+  }
+
+  get isImage(): boolean {
+    return this.checkType("image");
+  }
+
+  get currentItem(): Gallery.Item | null {
+    const galleryItems = this.$galleryStore.galleryItems;
+    if (galleryItems) return this.searchCurrentItem(galleryItems, this.pathMatch);
+    return null;
+  }
+
+  // ---
+
+  private searchCurrentItem(item: Gallery.Item, currentPath: string): Gallery.Item | null {
+    if (currentPath === item.path) return item;
+    if (item.properties.type === "directory" && currentPath.startsWith(item.path)) {
+      const itemFound = item.properties.items
+        .map(item => this.searchCurrentItem(item, currentPath))
+        .find(item => Boolean(item));
+      return itemFound || null;
+    }
+    return null;
+  }
+
+  private checkType(type: string) {
+    return (this.currentItem && this.currentItem.properties.type === type) || false;
+  }
+}
+</script>
+
+<style lang="scss">
+#test-flex-col {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+}
+</style>
-- 
cgit v1.2.3


From 91d3148f97ca59769648f9307f3d7e65b1bd7e95 Mon Sep 17 00:00:00 2001
From: Zero~Informatique
Date: Sat, 21 Dec 2019 11:04:14 +0100
Subject: viewer: ESLint rules

---
 viewer/src/views/Gallery.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'viewer/src/views/Gallery.vue')

diff --git a/viewer/src/views/Gallery.vue b/viewer/src/views/Gallery.vue
index 3625838..55b93db 100644
--- a/viewer/src/views/Gallery.vue
+++ b/viewer/src/views/Gallery.vue
@@ -44,7 +44,7 @@ export default class Root extends Vue {
     return null;
   }
 
-  private checkType(type: string) {
+  private checkType(type: string): boolean {
     return (this.currentItem && this.currentItem.properties.type === type) || false;
   }
 }
-- 
cgit v1.2.3


From 57d1b89d314970bf56d3d398c393f6a67a4ed0b5 Mon Sep 17 00:00:00 2001
From: Zero~Informatique
Date: Sat, 21 Dec 2019 20:14:33 +0100
Subject: viewer: Isolated the Directory and Image views in their own
 components

---
 viewer/src/views/Gallery.vue | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

(limited to 'viewer/src/views/Gallery.vue')

diff --git a/viewer/src/views/Gallery.vue b/viewer/src/views/Gallery.vue
index 55b93db..10ff323 100644
--- a/viewer/src/views/Gallery.vue
+++ b/viewer/src/views/Gallery.vue
@@ -1,19 +1,18 @@
 <template>
   <div id="test-flex-col">
-    <div v-if="isDirectory">
-      <strong>Directory: {{currentItem.path}}</strong>
-      <div v-for="(item, index) in currentItem.properties.items" :key="item.path">
-        <router-link :to="item.path">Thumbnail: {{index}}-{{item.path}}</router-link>
-      </div>
-    </div>
-    <div v-if="isImage">Image: {{currentItem.path}}</div>
+    <gallery-directory v-if="isDirectory" :directory="currentItem" />
+    <gallery-image v-if="isImage" :image="currentItem" />
   </div>
 </template>
 
 <script lang="ts">
 import { Component, Vue, Prop } from "vue-property-decorator";
+import GalleryDirectory from "./GalleryDirectory.vue";
+import GalleryImage from "./GalleryImage.vue";
 
-@Component
+@Component({
+  components: { GalleryDirectory, GalleryImage },
+})
 export default class Root extends Vue {
   @Prop(String) readonly pathMatch!: string;
 
-- 
cgit v1.2.3


From c2b4c5d144db17ebf2dc9de32ba25cc836831ae2 Mon Sep 17 00:00:00 2001
From: Zero~Informatique
Date: Sat, 21 Dec 2019 21:15:59 +0100
Subject: viewer: Improved the Gallery type definitions. Basic display of the
 images and thumbnails example: "thumbnails" instead of "thumbs"

---
 viewer/src/views/Gallery.vue | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

(limited to 'viewer/src/views/Gallery.vue')

diff --git a/viewer/src/views/Gallery.vue b/viewer/src/views/Gallery.vue
index 10ff323..954903a 100644
--- a/viewer/src/views/Gallery.vue
+++ b/viewer/src/views/Gallery.vue
@@ -1,5 +1,5 @@
 <template>
-  <div id="test-flex-col">
+  <div>
     <gallery-directory v-if="isDirectory" :directory="currentItem" />
     <gallery-image v-if="isImage" :image="currentItem" />
   </div>
@@ -50,10 +50,4 @@ export default class Root extends Vue {
 </script>
 
 <style lang="scss">
-#test-flex-col {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  justify-content: center;
-}
 </style>
-- 
cgit v1.2.3


From e34be1261d9219e5b2b92ebe271f609f11d55f63 Mon Sep 17 00:00:00 2001
From: Zero~Informatique
Date: Sun, 22 Dec 2019 03:50:40 +0100
Subject: vewer: Tags indexing and search input

---
 viewer/src/views/Gallery.vue | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'viewer/src/views/Gallery.vue')

diff --git a/viewer/src/views/Gallery.vue b/viewer/src/views/Gallery.vue
index 954903a..2020280 100644
--- a/viewer/src/views/Gallery.vue
+++ b/viewer/src/views/Gallery.vue
@@ -13,7 +13,7 @@ import GalleryImage from "./GalleryImage.vue";
 @Component({
   components: { GalleryDirectory, GalleryImage },
 })
-export default class Root extends Vue {
+export default class Gallery extends Vue {
   @Prop(String) readonly pathMatch!: string;
 
   get isDirectory(): boolean {
@@ -25,8 +25,8 @@ export default class Root extends Vue {
   }
 
   get currentItem(): Gallery.Item | null {
-    const galleryItems = this.$galleryStore.galleryItems;
-    if (galleryItems) return this.searchCurrentItem(galleryItems, this.pathMatch);
+    const galleryItemsRoot = this.$galleryStore.galleryItemsRoot;
+    if (galleryItemsRoot) return this.searchCurrentItem(galleryItemsRoot, this.pathMatch);
     return null;
   }
 
-- 
cgit v1.2.3


From dc251fffc2998f1cf4f8e9631928c4b92ac0d90e Mon Sep 17 00:00:00 2001
From: Zero~Informatique
Date: Sun, 22 Dec 2019 07:40:55 +0100
Subject: viewer: Implemented the search by tags. Pushed the special urls to
 ENV.

---
 viewer/src/views/Gallery.vue | 31 ++++++++++++++++---------------
 1 file changed, 16 insertions(+), 15 deletions(-)

(limited to 'viewer/src/views/Gallery.vue')

diff --git a/viewer/src/views/Gallery.vue b/viewer/src/views/Gallery.vue
index 2020280..38199b9 100644
--- a/viewer/src/views/Gallery.vue
+++ b/viewer/src/views/Gallery.vue
@@ -1,17 +1,20 @@
 <template>
   <div>
-    <gallery-directory v-if="isDirectory" :directory="currentItem" />
-    <gallery-image v-if="isImage" :image="currentItem" />
+    <gallery-search v-if="$uiStore.isModeSearch" :items="currentSearch" />
+    <gallery-directory v-else-if="isDirectory" :directory="currentItem" />
+    <gallery-image v-else-if="isImage" :image="currentItem" />
   </div>
 </template>
 
 <script lang="ts">
 import { Component, Vue, Prop } from "vue-property-decorator";
+import GallerySearch from "./GallerySearch.vue";
 import GalleryDirectory from "./GalleryDirectory.vue";
 import GalleryImage from "./GalleryImage.vue";
+import GalleryStore from "../store/galleryStore";
 
 @Component({
-  components: { GalleryDirectory, GalleryImage },
+  components: { GallerySearch, GalleryDirectory, GalleryImage },
 })
 export default class Gallery extends Vue {
   @Prop(String) readonly pathMatch!: string;
@@ -24,25 +27,23 @@ export default class Gallery extends Vue {
     return this.checkType("image");
   }
 
+  // Results of the search (by tags)
+  get currentSearch(): Gallery.Item[] {
+    const currentTags = this.$uiStore.currentTags;
+    let items = new Set<Gallery.Item>();
+    currentTags.flatMap(tag => tag.items).forEach(item => items.add(item));
+    return [...items];
+  }
+
+  // Item pointed by the URL (navigation)
   get currentItem(): Gallery.Item | null {
     const galleryItemsRoot = this.$galleryStore.galleryItemsRoot;
-    if (galleryItemsRoot) return this.searchCurrentItem(galleryItemsRoot, this.pathMatch);
+    if (galleryItemsRoot) return GalleryStore.searchCurrentItem(galleryItemsRoot, this.pathMatch);
     return null;
   }
 
   // ---
 
-  private searchCurrentItem(item: Gallery.Item, currentPath: string): Gallery.Item | null {
-    if (currentPath === item.path) return item;
-    if (item.properties.type === "directory" && currentPath.startsWith(item.path)) {
-      const itemFound = item.properties.items
-        .map(item => this.searchCurrentItem(item, currentPath))
-        .find(item => Boolean(item));
-      return itemFound || null;
-    }
-    return null;
-  }
-
   private checkType(type: string): boolean {
     return (this.currentItem && this.currentItem.properties.type === type) || false;
   }
-- 
cgit v1.2.3


From 7c2576b0cfb0a15b2a14f6f5ea96de16f0c23b44 Mon Sep 17 00:00:00 2001
From: Zero~Informatique
Date: Tue, 24 Dec 2019 02:22:56 +0100
Subject: viewer: Plugin for Optional chaining and Coalesce. Implemented tag
 operations (intersection, addition, substraction). Unified Tag.Search

---
 viewer/src/views/Gallery.vue | 46 +++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 41 insertions(+), 5 deletions(-)

(limited to 'viewer/src/views/Gallery.vue')

diff --git a/viewer/src/views/Gallery.vue b/viewer/src/views/Gallery.vue
index 38199b9..f04b276 100644
--- a/viewer/src/views/Gallery.vue
+++ b/viewer/src/views/Gallery.vue
@@ -8,6 +8,7 @@
 
 <script lang="ts">
 import { Component, Vue, Prop } from "vue-property-decorator";
+import { Operation } from '@/@types/tag/Operation';
 import GallerySearch from "./GallerySearch.vue";
 import GalleryDirectory from "./GalleryDirectory.vue";
 import GalleryImage from "./GalleryImage.vue";
@@ -29,10 +30,10 @@ export default class Gallery extends Vue {
 
   // Results of the search (by tags)
   get currentSearch(): Gallery.Item[] {
-    const currentTags = this.$uiStore.currentTags;
-    let items = new Set<Gallery.Item>();
-    currentTags.flatMap(tag => tag.items).forEach(item => items.add(item));
-    return [...items];
+    const byOperation = this.extractTagsByOperation(this.$uiStore.currentTags);
+    const intersection = this.extractIntersection(byOperation);
+    const substraction = this.extractSubstraction(byOperation);
+    return this.aggregateAll(byOperation, intersection, substraction);
   }
 
   // Item pointed by the URL (navigation)
@@ -45,7 +46,42 @@ export default class Gallery extends Vue {
   // ---
 
   private checkType(type: string): boolean {
-    return (this.currentItem && this.currentItem.properties.type === type) || false;
+    return this.currentItem?.properties.type === type ?? false;
+  }
+
+  private extractTagsByOperation(currentTags: Tag.Search[]): Tag.SearchByOperation {
+    let byOperation: Tag.SearchByOperation = {};
+    Object.values(Operation)
+      .forEach(operation => byOperation[operation] = currentTags.filter(tag => tag.operation === operation));
+    return byOperation;
+  }
+
+  private extractIntersection(byOperation: Tag.SearchByOperation): Set<Gallery.Item> {
+    let intersection = new Set<Gallery.Item>();
+    if (byOperation[Operation.INTERSECTION].length > 0) {
+      byOperation[Operation.INTERSECTION]
+        .map(tag => tag.items)
+        .reduce((a,b) => a.filter(c => b.includes(c)))
+        .flatMap(items=>items)
+        .forEach(item => intersection.add(item));
+    }
+    return intersection;
+  }
+
+  private extractSubstraction(byOperation: Tag.SearchByOperation): Set<Gallery.Item> {
+    let substraction = new Set<Gallery.Item>();
+    if (byOperation[Operation.SUBSTRACTION].length > 0) {
+      byOperation[Operation.SUBSTRACTION]
+        .flatMap(tag => tag.items)
+        .forEach(item => substraction.add(item));
+    }
+    return substraction;
+  }
+
+  private aggregateAll(byOperation: Tag.SearchByOperation, intersection: Set<Gallery.Item>, substraction: Set<Gallery.Item>): Gallery.Item[] {
+    byOperation[Operation.ADDITION].flatMap(tag => tag.items).forEach(item => intersection.add(item));
+    substraction.forEach(item => intersection.delete(item));
+    return [...intersection];
   }
 }
 </script>
-- 
cgit v1.2.3


From c7153c8d6d3879566b49af0f7b23593d46477eb9 Mon Sep 17 00:00:00 2001
From: Zero~Informatique
Date: Tue, 7 Jan 2020 19:46:41 +0100
Subject: viewer: relative gallery path (NOT STABLE with current compiler)
 compiler: commands for compilation on Windows

---
 viewer/src/views/Gallery.vue | 1 +
 1 file changed, 1 insertion(+)

(limited to 'viewer/src/views/Gallery.vue')

diff --git a/viewer/src/views/Gallery.vue b/viewer/src/views/Gallery.vue
index f04b276..4deb937 100644
--- a/viewer/src/views/Gallery.vue
+++ b/viewer/src/views/Gallery.vue
@@ -3,6 +3,7 @@
     <gallery-search v-if="$uiStore.isModeSearch" :items="currentSearch" />
     <gallery-directory v-else-if="isDirectory" :directory="currentItem" />
     <gallery-image v-else-if="isImage" :image="currentItem" />
+    <div v-else>Unknown type</div>
   </div>
 </template>
 
-- 
cgit v1.2.3


From 89bcb2dbe5b5e6eb8e8ba13ceecee2770dfe4cd4 Mon Sep 17 00:00:00 2001
From: Zero~Informatique
Date: Thu, 9 Jan 2020 02:10:35 +0100
Subject: viewer: Changed "image" type to "picture". Adapted the code to the
 current compiler output format. The currentItem and currentPath are
 calculated in the store for easier multi-component access. Breadcrumb for
 current's position and navigation.

---
 viewer/src/views/Gallery.vue | 36 +++++++++++++++++++-----------------
 1 file changed, 19 insertions(+), 17 deletions(-)

(limited to 'viewer/src/views/Gallery.vue')

diff --git a/viewer/src/views/Gallery.vue b/viewer/src/views/Gallery.vue
index 4deb937..a53df3d 100644
--- a/viewer/src/views/Gallery.vue
+++ b/viewer/src/views/Gallery.vue
@@ -1,32 +1,41 @@
 <template>
   <div>
     <gallery-search v-if="$uiStore.isModeSearch" :items="currentSearch" />
-    <gallery-directory v-else-if="isDirectory" :directory="currentItem" />
-    <gallery-image v-else-if="isImage" :image="currentItem" />
-    <div v-else>Unknown type</div>
+    <gallery-directory v-else-if="isDirectory" :directory="$galleryStore.currentItem" />
+    <gallery-picture v-else-if="isPicture" :picture="$galleryStore.currentItem" />
+    <div v-else>{{$t("gallery.unknowntype")}}</div>
   </div>
 </template>
 
 <script lang="ts">
-import { Component, Vue, Prop } from "vue-property-decorator";
+import { Component, Vue, Prop, Watch } from "vue-property-decorator";
 import { Operation } from '@/@types/tag/Operation';
 import GallerySearch from "./GallerySearch.vue";
 import GalleryDirectory from "./GalleryDirectory.vue";
-import GalleryImage from "./GalleryImage.vue";
-import GalleryStore from "../store/galleryStore";
+import GalleryPicture from "./GalleryPicture.vue";
 
 @Component({
-  components: { GallerySearch, GalleryDirectory, GalleryImage },
+  components: { GallerySearch, GalleryDirectory, GalleryPicture },
 })
 export default class Gallery extends Vue {
   @Prop(String) readonly pathMatch!: string;
 
+  mounted() {
+    this.pathChanged()
+  }
+
+  @Watch("pathMatch")
+  pathChanged() {
+    console.log("Path: ", this.pathMatch);
+    this.$galleryStore.setCurrentPath(this.pathMatch);
+  }
+
   get isDirectory(): boolean {
     return this.checkType("directory");
   }
 
-  get isImage(): boolean {
-    return this.checkType("image");
+  get isPicture(): boolean {
+    return this.checkType("picture");
   }
 
   // Results of the search (by tags)
@@ -37,17 +46,10 @@ export default class Gallery extends Vue {
     return this.aggregateAll(byOperation, intersection, substraction);
   }
 
-  // Item pointed by the URL (navigation)
-  get currentItem(): Gallery.Item | null {
-    const galleryItemsRoot = this.$galleryStore.galleryItemsRoot;
-    if (galleryItemsRoot) return GalleryStore.searchCurrentItem(galleryItemsRoot, this.pathMatch);
-    return null;
-  }
-
   // ---
 
   private checkType(type: string): boolean {
-    return this.currentItem?.properties.type === type ?? false;
+    return this.$galleryStore.currentItem?.properties.type === type ?? false;
   }
 
   private extractTagsByOperation(currentTags: Tag.Search[]): Tag.SearchByOperation {
-- 
cgit v1.2.3


From d25b5a87668bba43e81342f7385a1097653c5311 Mon Sep 17 00:00:00 2001
From: Zero~Informatique
Date: Fri, 10 Jan 2020 22:03:30 +0100
Subject: Code review code improvements

---
 viewer/src/views/Gallery.vue | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

(limited to 'viewer/src/views/Gallery.vue')

diff --git a/viewer/src/views/Gallery.vue b/viewer/src/views/Gallery.vue
index a53df3d..1c98877 100644
--- a/viewer/src/views/Gallery.vue
+++ b/viewer/src/views/Gallery.vue
@@ -1,8 +1,8 @@
 <template>
   <div>
     <gallery-search v-if="$uiStore.isModeSearch" :items="currentSearch" />
-    <gallery-directory v-else-if="isDirectory" :directory="$galleryStore.currentItem" />
-    <gallery-picture v-else-if="isPicture" :picture="$galleryStore.currentItem" />
+    <gallery-directory v-else-if="checkType('directory')" :directory="$galleryStore.currentItem" />
+    <gallery-picture v-else-if="checkType('picture')" :picture="$galleryStore.currentItem" />
     <div v-else>{{$t("gallery.unknowntype")}}</div>
   </div>
 </template>
@@ -30,14 +30,6 @@ export default class Gallery extends Vue {
     this.$galleryStore.setCurrentPath(this.pathMatch);
   }
 
-  get isDirectory(): boolean {
-    return this.checkType("directory");
-  }
-
-  get isPicture(): boolean {
-    return this.checkType("picture");
-  }
-
   // Results of the search (by tags)
   get currentSearch(): Gallery.Item[] {
     const byOperation = this.extractTagsByOperation(this.$uiStore.currentTags);
-- 
cgit v1.2.3


From 27b51018525dbb7a6edb3073819d82245387ddd3 Mon Sep 17 00:00:00 2001
From: Zero~Informatique
Date: Fri, 10 Jan 2020 22:22:22 +0100
Subject: viewer: license headers

---
 viewer/src/views/Gallery.vue | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

(limited to 'viewer/src/views/Gallery.vue')

diff --git a/viewer/src/views/Gallery.vue b/viewer/src/views/Gallery.vue
index 1c98877..fad7cc3 100644
--- a/viewer/src/views/Gallery.vue
+++ b/viewer/src/views/Gallery.vue
@@ -1,3 +1,22 @@
+<!-- ldgallery - A static generator which turns a collection of tagged
+--             pictures into a searchable web gallery.
+--
+-- Copyright (C) 2019-2020  Guillaume FOUET
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU Affero General Public License as
+-- published by the Free Software Foundation, either version 3 of the
+-- License, or (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU Affero General Public License for more details.
+--
+-- You should have received a copy of the GNU Affero General Public License
+-- along with this program.  If not, see <https://www.gnu.org/licenses/>.
+-->
+
 <template>
   <div>
     <gallery-search v-if="$uiStore.isModeSearch" :items="currentSearch" />
-- 
cgit v1.2.3

