]> BookStack Code Mirror - bookstack/commitdiff
Customization: Added parent tag classes 5681/head
authorDan Brown <redacted>
Sat, 28 Jun 2025 21:27:28 +0000 (22:27 +0100)
committerDan Brown <redacted>
Sat, 28 Jun 2025 21:27:28 +0000 (22:27 +0100)
For #5217

app/Activity/Models/Tag.php
app/Activity/Tools/TagClassGenerator.php
resources/views/entities/body-tag-classes.blade.php
tests/Entity/TagTest.php

index 0af0a65ac76deda65a1d9d0570304b13333b5d09..0e7c68a270a26a122eab0739e0a8c36cc34b9b2a 100644 (file)
@@ -12,6 +12,8 @@ use Illuminate\Database\Eloquent\Relations\MorphTo;
  * @property int    $id
  * @property string $name
  * @property string $value
+ * @property int    $entity_id
+ * @property string $entity_type
  * @property int    $order
  */
 class Tag extends Model
index 1a1bd16c881060d2615ecc99b10c837392dd292f..5bcb44113d6ecaaa596a8ce6aed8da689e180910 100644 (file)
@@ -3,17 +3,15 @@
 namespace BookStack\Activity\Tools;
 
 use BookStack\Activity\Models\Tag;
+use BookStack\Entities\Models\BookChild;
+use BookStack\Entities\Models\Entity;
+use BookStack\Entities\Models\Page;
 
 class TagClassGenerator
 {
-    protected array $tags;
-
-    /**
-     * @param Tag[] $tags
-     */
-    public function __construct(array $tags)
-    {
-        $this->tags = $tags;
+    public function __construct(
+        protected Entity $entity
+    ) {
     }
 
     /**
@@ -22,14 +20,23 @@ class TagClassGenerator
     public function generate(): array
     {
         $classes = [];
+        $tags = $this->entity->tags->all();
+
+        foreach ($tags as $tag) {
+             array_push($classes, ...$this->generateClassesForTag($tag));
+        }
+
+        if ($this->entity instanceof BookChild && userCan('view', $this->entity->book)) {
+            $bookTags = $this->entity->book->tags;
+            foreach ($bookTags as $bookTag) {
+                 array_push($classes, ...$this->generateClassesForTag($bookTag, 'book-'));
+            }
+        }
 
-        foreach ($this->tags as $tag) {
-            $name = $this->normalizeTagClassString($tag->name);
-            $value = $this->normalizeTagClassString($tag->value);
-            $classes[] = 'tag-name-' . $name;
-            if ($value) {
-                $classes[] = 'tag-value-' . $value;
-                $classes[] = 'tag-pair-' . $name . '-' . $value;
+        if ($this->entity instanceof Page && $this->entity->chapter && userCan('view', $this->entity->chapter)) {
+            $chapterTags = $this->entity->chapter->tags;
+            foreach ($chapterTags as $chapterTag) {
+                 array_push($classes, ...$this->generateClassesForTag($chapterTag, 'chapter-'));
             }
         }
 
@@ -41,6 +48,22 @@ class TagClassGenerator
         return implode(' ', $this->generate());
     }
 
+    /**
+     * @return string[]
+     */
+    protected function generateClassesForTag(Tag $tag, string $prefix = ''): array
+    {
+        $classes = [];
+        $name = $this->normalizeTagClassString($tag->name);
+        $value = $this->normalizeTagClassString($tag->value);
+        $classes[] = "{$prefix}tag-name-{$name}";
+        if ($value) {
+            $classes[] = "{$prefix}tag-value-{$value}";
+            $classes[] = "{$prefix}tag-pair-{$name}-{$value}";
+        }
+        return $classes;
+    }
+
     protected function normalizeTagClassString(string $value): string
     {
         $value = str_replace(' ', '', strtolower($value));
index 08427f1a5ed293e7c9eae924ea3bdbcfdadf44d0..f9ba023c37ee464f71e9c7ec551c7548cf2b8118 100644 (file)
@@ -1 +1 @@
-@push('body-class', e((new \BookStack\Activity\Tools\TagClassGenerator($entity->tags->all()))->generateAsString() . ' '))
\ No newline at end of file
+@push('body-class', e((new \BookStack\Activity\Tools\TagClassGenerator($entity))->generateAsString() . ' '))
\ No newline at end of file
index 729f9390358d5ff1e044a00bed7e67ddb82cf23e..63f037d9cc011ef6783987617ab8de36e133a7f9 100644 (file)
@@ -230,4 +230,39 @@ class TagTest extends TestCase
         $resp->assertDontSee('tag-name-<>', false);
         $resp->assertSee('tag-name-&lt;&gt;', false);
     }
+
+    public function test_parent_tag_classes_visible()
+    {
+        $page = $this->entities->pageWithinChapter();
+        $page->chapter->tags()->create(['name' => 'My Chapter Tag', 'value' => 'abc123']);
+        $page->book->tags()->create(['name' => 'My Book Tag', 'value' => 'def456']);
+        $this->asEditor();
+
+        $html = $this->withHtml($this->get($page->getUrl()));
+        $html->assertElementExists('body.chapter-tag-pair-mychaptertag-abc123');
+        $html->assertElementExists('body.book-tag-pair-mybooktag-def456');
+
+        $html = $this->withHtml($this->get($page->chapter->getUrl()));
+        $html->assertElementExists('body.book-tag-pair-mybooktag-def456');
+    }
+
+    public function test_parent_tag_classes_not_visible_if_cannot_see_parent()
+    {
+        $page = $this->entities->pageWithinChapter();
+        $page->chapter->tags()->create(['name' => 'My Chapter Tag', 'value' => 'abc123']);
+        $page->book->tags()->create(['name' => 'My Book Tag', 'value' => 'def456']);
+        $editor = $this->users->editor();
+        $this->actingAs($editor);
+
+        $this->permissions->setEntityPermissions($page, ['view'], [$editor->roles()->first()]);
+        $this->permissions->disableEntityInheritedPermissions($page->chapter);
+
+        $html = $this->withHtml($this->get($page->getUrl()));
+        $html->assertElementNotExists('body.chapter-tag-pair-mychaptertag-abc123');
+        $html->assertElementExists('body.book-tag-pair-mybooktag-def456');
+
+        $this->permissions->disableEntityInheritedPermissions($page->book);
+        $html = $this->withHtml($this->get($page->getUrl()));
+        $html->assertElementNotExists('body.book-tag-pair-mybooktag-def456');
+    }
 }