]> BookStack Code Mirror - bookstack/commitdiff
Added content-view body classes generated from tags
authorDan Brown <redacted>
Sat, 23 Jul 2022 17:29:04 +0000 (18:29 +0100)
committerDan Brown <redacted>
Sat, 23 Jul 2022 17:29:04 +0000 (18:29 +0100)
Included tests to cover.

Closes #3583

app/Actions/TagClassGenerator.php [new file with mode: 0644]
resources/views/books/show.blade.php
resources/views/chapters/show.blade.php
resources/views/entities/body-tag-classes.blade.php [new file with mode: 0644]
resources/views/layouts/base.blade.php
resources/views/layouts/tri.blade.php
resources/views/pages/edit.blade.php
resources/views/pages/show.blade.php
resources/views/shelves/show.blade.php
tests/Entity/TagTest.php
tests/TestCase.php

diff --git a/app/Actions/TagClassGenerator.php b/app/Actions/TagClassGenerator.php
new file mode 100644 (file)
index 0000000..997ace8
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+
+namespace BookStack\Actions;
+
+class TagClassGenerator
+{
+
+    protected array $tags;
+
+    /**
+     * @param Tag[] $tags
+     */
+    public function __construct(array $tags)
+    {
+        $this->tags = $tags;
+    }
+
+    /**
+     * @return string[]
+     */
+    public function generate(): array
+    {
+        $classes = [];
+
+        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;
+            }
+        }
+
+        return array_unique($classes);
+    }
+
+    public function generateAsString(): string
+    {
+        return implode(' ', $this->generate());
+    }
+
+    protected function normalizeTagClassString(string $value): string
+    {
+        $value = str_replace(' ', '', strtolower($value));
+        $value = str_replace('-', '', strtolower($value));
+        return $value;
+    }
+
+}
\ No newline at end of file
index e0cb4b862dd8327179c4b1655f6d574d1886c36f..03801f9a5f827ea9d6ac36a8c4a8312414d01048 100644 (file)
@@ -13,6 +13,8 @@
     @endif
 @endpush
 
+@include('entities.body-tag-classes', ['entity' => $book])
+
 @section('body')
 
     <div class="mb-s">
index 8a86900fb1b744e81f1ed0b87a4aabf1e24f7a68..a7b90ceef5e33567cda5b068c7c8030ea180ba9d 100644 (file)
@@ -10,6 +10,8 @@
     <meta property="og:description" content="{{ Str::limit($chapter->description, 100, '...') }}">
 @endpush
 
+@include('entities.body-tag-classes', ['entity' => $chapter])
+
 @section('body')
 
     <div class="mb-m print-hidden">
diff --git a/resources/views/entities/body-tag-classes.blade.php b/resources/views/entities/body-tag-classes.blade.php
new file mode 100644 (file)
index 0000000..2edb3e0
--- /dev/null
@@ -0,0 +1 @@
+@push('body-class', e((new \BookStack\Actions\TagClassGenerator($entity->tags->all()))->generateAsString() . ' '))
\ No newline at end of file
index c465c5f7ef59d2ade5dbcf852e7f8f14269dac86..9f6e9f89af0f99fd54c19d26a92c4e1ccefb2ae4 100644 (file)
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html lang="{{ config('app.lang') }}"
       dir="{{ config('app.rtl') ? 'rtl' : 'ltr' }}"
-      class="{{ setting()->getForCurrentUser('dark-mode-enabled') ? 'dark-mode ' : '' }}@yield('body-class')">
+      class="{{ setting()->getForCurrentUser('dark-mode-enabled') ? 'dark-mode ' : '' }}">
 <head>
     <title>{{ isset($pageTitle) ? $pageTitle . ' | ' : '' }}{{ setting('app-name') }}</title>
 
@@ -31,7 +31,7 @@
     <!-- Translations for JS -->
     @stack('translations')
 </head>
-<body class="@yield('body-class')">
+<body class="@stack('body-class')">
 
     @include('layouts.parts.base-body-start')
     @include('common.skip-to-content')
index 4571f4471ca94cd59428e9a73d4e20122c120129..e0f16321f083208218c822fbeb21cf56d2fc2000 100644 (file)
@@ -1,6 +1,6 @@
 @extends('layouts.base')
 
-@section('body-class', 'tri-layout')
+@push('body-class', 'tri-layout ')
 @section('content-components', 'tri-layout')
 
 @section('content')
index cd9635758060fe77f58a99427138d81075ca9749..98adc849c26a12c73bb00aed4387f575ede80d1c 100644 (file)
@@ -1,6 +1,6 @@
 @extends('layouts.base')
 
-@section('body-class', 'flexbox')
+@push('body-class', 'flexbox ')
 
 @section('content')
 
index f1aed730b24b6bc9cb063fd272022db77a94108b..45d2e2d7f7c9139eaa454e4c2bdf9ecdcaa1503f 100644 (file)
@@ -4,6 +4,8 @@
     <meta property="og:description" content="{{ Str::limit($page->text, 100, '...') }}">
 @endpush
 
+@include('entities.body-tag-classes', ['entity' => $page])
+
 @section('body')
 
     <div class="mb-m print-hidden">
index 4d440b635f4f83e386f47fdb4cfb07d5ad0a9372..306d55e54ea5d318c045cdcab2faa69b8301eff5 100644 (file)
@@ -7,6 +7,8 @@
     @endif
 @endpush
 
+@include('entities.body-tag-classes', ['entity' => $shelf])
+
 @section('body')
 
     <div class="mb-s">
index 6d03ed95ab24962fccb53b3d457ae94cc7036efa..1d2c9124f9bc06dbe413c2a2fb8039fbc5dba196 100644 (file)
@@ -198,9 +198,28 @@ class TagTest extends TestCase
 
     public function test_tag_index_shows_message_on_no_results()
     {
-        /** @var Page $page */
         $resp = $this->asEditor()->get('/tags?search=testingval');
         $resp->assertSee('No items available');
         $resp->assertSee('Tags can be assigned via the page editor sidebar');
     }
+
+    public function test_tag_classes_visible_on_entities()
+    {
+        $this->asEditor();
+
+        foreach ($this->getEachEntityType() as $entity) {
+            $entity->tags()->create(['name' => 'My Super Tag Name', 'value' => 'An-awesome-value']);
+            $html = $this->withHtml($this->get($entity->getUrl()));
+            $html->assertElementExists('body.tag-name-mysupertagname.tag-value-anawesomevalue.tag-pair-mysupertagname-anawesomevalue');
+        }
+    }
+
+    public function test_tag_classes_are_escaped()
+    {
+        $page = Page::query()->first();
+        $page->tags()->create(['name' => '<>']);
+        $resp = $this->asEditor()->get($page->getUrl());
+        $resp->assertDontSee('tag-name-<>', false);
+        $resp->assertSee('tag-name-&lt;&gt;', false);
+    }
 }
index 95e58b267b812b6ecb8e06494316c371fe81d47d..9ffce917e36e280cd482508ac76894b6653bca28 100644 (file)
@@ -428,4 +428,17 @@ abstract class TestCase extends BaseTestCase
 
         $this->assertDatabaseHas('activities', $detailsToCheck);
     }
+
+    /**
+     * @return Entity[]
+     */
+    protected function getEachEntityType(): array
+    {
+        return [
+            'page' => Page::query()->first(),
+            'chapter' => Chapter::query()->first(),
+            'book' => Book::query()->first(),
+            'bookshelf' => Bookshelf::query()->first(),
+        ];
+    }
 }