mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Added content-view body classes generated from tags
Included tests to cover. Closes #3583
This commit is contained in:
parent
840a1ea011
commit
975ba4f8d8
50
app/Actions/TagClassGenerator.php
Normal file
50
app/Actions/TagClassGenerator.php
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -13,6 +13,8 @@
|
||||
@endif
|
||||
@endpush
|
||||
|
||||
@include('entities.body-tag-classes', ['entity' => $book])
|
||||
|
||||
@section('body')
|
||||
|
||||
<div class="mb-s">
|
||||
|
@ -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">
|
||||
|
1
resources/views/entities/body-tag-classes.blade.php
Normal file
1
resources/views/entities/body-tag-classes.blade.php
Normal file
@ -0,0 +1 @@
|
||||
@push('body-class', e((new \BookStack\Actions\TagClassGenerator($entity->tags->all()))->generateAsString() . ' '))
|
@ -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')
|
||||
|
@ -1,6 +1,6 @@
|
||||
@extends('layouts.base')
|
||||
|
||||
@section('body-class', 'tri-layout')
|
||||
@push('body-class', 'tri-layout ')
|
||||
@section('content-components', 'tri-layout')
|
||||
|
||||
@section('content')
|
||||
|
@ -1,6 +1,6 @@
|
||||
@extends('layouts.base')
|
||||
|
||||
@section('body-class', 'flexbox')
|
||||
@push('body-class', 'flexbox ')
|
||||
|
||||
@section('content')
|
||||
|
||||
|
@ -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">
|
||||
|
@ -7,6 +7,8 @@
|
||||
@endif
|
||||
@endpush
|
||||
|
||||
@include('entities.body-tag-classes', ['entity' => $shelf])
|
||||
|
||||
@section('body')
|
||||
|
||||
<div class="mb-s">
|
||||
|
@ -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-<>', false);
|
||||
}
|
||||
}
|
||||
|
@ -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(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user