return [];
}
- $tree = collect([]);
- foreach ($headers as $header) {
- $text = $header->nodeValue;
- $tree->push([
+ $tree = collect($headers)->map(function($header) {
+ $text = trim(str_replace("\xc2\xa0", '', $header->nodeValue));
+ if (strlen($text) > 30) {
+ $text = substr($text, 0, 27) . '...';
+ }
+
+ return [
'nodeName' => strtolower($header->nodeName),
'level' => intval(str_replace('h', '', $header->nodeName)),
'link' => '#' . $header->getAttribute('id'),
- 'text' => strlen($text) > 30 ? substr($text, 0, 27) . '...' : $text
- ]);
- }
+ 'text' => $text,
+ ];
+ })->filter(function($header) {
+ return strlen($header['text']) > 0;
+ });
// Normalise headers if only smaller headers have been used
- if (count($tree) > 0) {
- $minLevel = $tree->pluck('level')->min();
- $tree = $tree->map(function ($header) use ($minLevel) {
- $header['level'] -= ($minLevel - 2);
- return $header;
- });
- }
+ $minLevel = $tree->pluck('level')->min();
+ $tree = $tree->map(function ($header) use ($minLevel) {
+ $header['level'] -= ($minLevel - 2);
+ return $header;
+ });
+
return $tree->toArray();
}
{
$image->thumbs = [
'gallery' => $this->getThumbnail($image, 150, 150, false),
- 'display' => $this->getThumbnail($image, 840, null, true)
+ 'display' => $this->getThumbnail($image, 1680, null, true)
];
}
// Handle image paste
cm.on('paste', (cm, event) => {
- if (!event.clipboardData || !event.clipboardData.items) return;
- for (let i = 0; i < event.clipboardData.items.length; i++) {
- uploadImage(event.clipboardData.items[i].getAsFile());
+ const clipboardItems = event.clipboardData.items;
+ if (!event.clipboardData || !clipboardItems) return;
+
+ // Don't handle if clipboard includes text content
+ for (let clipboardItem of clipboardItems) {
+ if (clipboardItem.type.includes('text/')) {
+ return;
+ }
+ }
+
+ for (let clipboardItem of clipboardItems) {
+ if (clipboardItem.type.includes("image")) {
+ uploadImage(clipboardItem.getAsFile());
+ }
}
});
* @param editor
*/
function editorPaste(event, editor, wysiwygComponent) {
- if (!event.clipboardData || !event.clipboardData.items) return;
+ const clipboardItems = event.clipboardData.items;
+ if (!event.clipboardData || !clipboardItems) return;
- for (let clipboardItem of event.clipboardData.items) {
- if (clipboardItem.type.indexOf("image") === -1) continue;
- event.preventDefault();
+ // Don't handle if clipboard includes text content
+ for (let clipboardItem of clipboardItems) {
+ if (clipboardItem.type.includes('text/')) {
+ return;
+ }
+ }
+
+ for (let clipboardItem of clipboardItems) {
+ if (!clipboardItem.type.includes("image")) {
+ continue;
+ }
const id = "image-" + Math.random().toString(16).slice(2);
const loadingImage = window.baseUrl('/loading.gif');
}
@include smaller-than($m) {
- .grid.third {
+ .grid.third:not(.no-break) {
grid-template-columns: 1fr 1fr;
}
.grid.half:not(.no-break), .grid.left-focus:not(.no-break), .grid.right-focus:not(.no-break) {
}
@include smaller-than($s) {
- .grid.third {
+ .grid.third:not(.no-break) {
grid-template-columns: 1fr;
}
}
}
}
-@include smaller-than($m) {
+@include smaller-than($s) {
.page-edit-toolbar {
overflow-x: scroll;
overflow-y: visible;
- z-index: 12;
}
.page-edit-toolbar .grid.third {
display: block;
}
}
-@include smaller-than($m) {
- .page-edit-toolbar #save-button {
- position: fixed;
- z-index: 30;
- border-radius: 50%;
- width: 56px;
- height: 56px;
- font-size: 24px;
- right: $-m;
- bottom: $-s;
- box-shadow: $bs-hover;
- background-color: currentColor;
- svg {
- fill: #FFF;
- }
- span {
- display: none;
- }
+.page-save-mobile-button {
+ position: fixed;
+ z-index: 30;
+ border-radius: 50%;
+ width: 56px;
+ height: 56px;
+ font-size: 24px;
+ right: $-m;
+ bottom: $-s;
+ box-shadow: $bs-hover;
+ background-color: currentColor;
+ text-align: center;
+ svg {
+ fill: #FFF;
+ margin-right: 0;
}
}
{{--Header Bar--}}
<div class="primary-background-light toolbar page-edit-toolbar">
- <div class="grid third v-center">
+ <div class="grid third no-break v-center">
<div class="action-buttons text-left px-m py-xs">
<a href="{{ back()->getTargetUrl() }}" class="text-button text-primary">@icon('back')<span class="hide-under-l">{{ trans('common.back') }}</span></a>
<span>{{-- Prevents button jumping on menu show --}}</span>
</div>
- <button type="submit" id="save-button" class="float-left text-primary text-button text-pos-hover">@icon('save')<span>{{ trans('entities.pages_save') }}</span></button>
+ <button type="submit" id="save-button" class="float-left text-primary text-button text-pos-hover hide-under-m">@icon('save')<span>{{ trans('entities.pages_save') }}</span></button>
</div>
</div>
</div>
@endif
</div>
+
+ <button type="submit" id="save-button-mobile" title="{{ trans('entities.pages_save') }}" class="text-primary text-button hide-over-m page-save-mobile-button">@icon('save')</button>
</div>
\ No newline at end of file
<div>
<div v-pre class="card content-wrap">
<h1 class="list-heading">{{ trans('entities.search_results') }}</h1>
+ <form action="{{ baseUrl('/search') }}" method="GET" class="search-box flexible hide-over-l">
+ <input value="{{$searchTerm}}" type="text" name="term" placeholder="{{ trans('common.search') }}">
+ <button type="submit">@icon('search')</button>
+ <button v-if="searching" v-cloak class="search-box-cancel text-neg" v-on:click="clearSearch" type="button">@icon('close')</button>
+ </form>
<h6 class="text-muted">{{ trans_choice('entities.search_total_results_found', $totalResults, ['count' => $totalResults]) }}</h6>
<div class="book-contents">
@include('partials.entity-list', ['entities' => $entities, 'showPath' => true])
--- /dev/null
+<?php
+namespace Tests;
+
+use BookStack\Entities\Repos\PageRepo;
+
+class PageRepoTest extends TestCase
+{
+ /**
+ * @var PageRepo $pageRepo
+ */
+ protected $pageRepo;
+
+ protected function setUp()
+ {
+ parent::setUp();
+ $this->pageRepo = app()->make(PageRepo::class);
+ }
+
+ public function test_get_page_nav_does_not_show_empty_titles()
+ {
+ $content = '<h1 id="testa">Hello</h1><h2 id="testb"> </h2><h3 id="testc"></h3>';
+ $navMap = $this->pageRepo->getPageNav($content);
+
+ $this->assertCount(1, $navMap);
+ $this->assertArraySubset([
+ 'nodeName' => 'h1',
+ 'link' => '#testa',
+ 'text' => 'Hello'
+ ], $navMap[0]);
+ }
+
+}
\ No newline at end of file