mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-02-17 06:52:53 +08:00
Converted entity-dash from vue to a component
This commit is contained in:
parent
a5fa745749
commit
10305a4446
|
@ -1,16 +1,22 @@
|
|||
# JavaScript Components
|
||||
|
||||
This document details the format for JavaScript components in BookStack.
|
||||
This document details the format for JavaScript components in BookStack. This is a really simple class-based setup with a few helpers provided.
|
||||
|
||||
#### Defining a Component in JS
|
||||
|
||||
```js
|
||||
class Dropdown {
|
||||
setup() {
|
||||
this.toggle = this.$refs.toggle;
|
||||
this.menu = this.$refs.menu;
|
||||
|
||||
this.speed = parseInt(this.$opts.speed);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
All usage of $refs, $manyRefs and $opts should be done at the top of the `setup` function so any requirements can be easily seen.
|
||||
|
||||
#### Using a Component in HTML
|
||||
|
||||
A component is used like so:
|
||||
|
|
59
resources/js/components/entity-search.js
Normal file
59
resources/js/components/entity-search.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
import {onSelect} from "../services/dom";
|
||||
|
||||
/**
|
||||
* Class EntitySearch
|
||||
* @extends {Component}
|
||||
*/
|
||||
class EntitySearch {
|
||||
setup() {
|
||||
this.entityId = this.$opts.entityId;
|
||||
this.entityType = this.$opts.entityType;
|
||||
|
||||
this.contentView = this.$refs.contentView;
|
||||
this.searchView = this.$refs.searchView;
|
||||
this.searchResults = this.$refs.searchResults;
|
||||
this.searchInput = this.$refs.searchInput;
|
||||
this.searchForm = this.$refs.searchForm;
|
||||
this.clearButton = this.$refs.clearButton;
|
||||
this.loadingBlock = this.$refs.loadingBlock;
|
||||
|
||||
this.setupListeners();
|
||||
}
|
||||
|
||||
setupListeners() {
|
||||
this.searchInput.addEventListener('change', this.runSearch.bind(this));
|
||||
this.searchForm.addEventListener('submit', e => {
|
||||
e.preventDefault();
|
||||
this.runSearch();
|
||||
});
|
||||
|
||||
onSelect(this.clearButton, this.clearSearch.bind(this));
|
||||
}
|
||||
|
||||
runSearch() {
|
||||
const term = this.searchInput.value.trim();
|
||||
if (term.length === 0) {
|
||||
return this.clearSearch();
|
||||
}
|
||||
|
||||
this.searchView.classList.remove('hidden');
|
||||
this.contentView.classList.add('hidden');
|
||||
this.loadingBlock.classList.remove('hidden');
|
||||
|
||||
const url = window.baseUrl(`/search/${this.entityType}/${this.entityId}`);
|
||||
window.$http.get(url, {term}).then(resp => {
|
||||
this.searchResults.innerHTML = resp.data;
|
||||
}).catch(console.error).then(() => {
|
||||
this.loadingBlock.classList.add('hidden');
|
||||
});
|
||||
}
|
||||
|
||||
clearSearch() {
|
||||
this.searchView.classList.add('hidden');
|
||||
this.contentView.classList.remove('hidden');
|
||||
this.loadingBlock.classList.add('hidden');
|
||||
this.searchInput.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
export default EntitySearch;
|
|
@ -1,44 +0,0 @@
|
|||
let data = {
|
||||
id: null,
|
||||
type: '',
|
||||
searching: false,
|
||||
searchTerm: '',
|
||||
searchResults: '',
|
||||
};
|
||||
|
||||
let computed = {
|
||||
|
||||
};
|
||||
|
||||
let methods = {
|
||||
|
||||
searchBook() {
|
||||
if (this.searchTerm.trim().length === 0) return;
|
||||
this.searching = true;
|
||||
this.searchResults = '';
|
||||
let url = window.baseUrl(`/search/${this.type}/${this.id}`);
|
||||
url += `?term=${encodeURIComponent(this.searchTerm)}`;
|
||||
this.$http.get(url).then(resp => {
|
||||
this.searchResults = resp.data;
|
||||
});
|
||||
},
|
||||
|
||||
checkSearchForm() {
|
||||
this.searching = this.searchTerm > 0;
|
||||
},
|
||||
|
||||
clearSearch() {
|
||||
this.searching = false;
|
||||
this.searchTerm = '';
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
function mounted() {
|
||||
this.id = Number(this.$el.getAttribute('entity-id'));
|
||||
this.type = this.$el.getAttribute('entity-type');
|
||||
}
|
||||
|
||||
export default {
|
||||
data, computed, methods, mounted
|
||||
};
|
|
@ -4,14 +4,12 @@ function exists(id) {
|
|||
return document.getElementById(id) !== null;
|
||||
}
|
||||
|
||||
import entityDashboard from "./entity-dashboard";
|
||||
import imageManager from "./image-manager";
|
||||
import tagManager from "./tag-manager";
|
||||
import attachmentManager from "./attachment-manager";
|
||||
import pageEditor from "./page-editor";
|
||||
|
||||
let vueMapping = {
|
||||
'entity-dashboard': entityDashboard,
|
||||
'image-manager': imageManager,
|
||||
'tag-manager': tagManager,
|
||||
'attachment-manager': attachmentManager,
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
@extends('tri-layout')
|
||||
|
||||
@section('container-attrs')
|
||||
id="entity-dashboard"
|
||||
entity-id="{{ $book->id }}"
|
||||
entity-type="book"
|
||||
component="entity-search"
|
||||
option:entity-search:entity-id="{{ $book->id }}"
|
||||
option:entity-search:entity-type="book"
|
||||
@stop
|
||||
|
||||
@section('body')
|
||||
|
@ -15,11 +15,11 @@
|
|||
</div>
|
||||
|
||||
<main class="content-wrap card">
|
||||
<h1 class="break-text" v-pre>{{$book->name}}</h1>
|
||||
<div class="book-content" v-show="!searching">
|
||||
<p class="text-muted" v-pre>{!! nl2br(e($book->description)) !!}</p>
|
||||
<h1 class="break-text">{{$book->name}}</h1>
|
||||
<div refs="entity-search@contentView" class="book-content">
|
||||
<p class="text-muted">{!! nl2br(e($book->description)) !!}</p>
|
||||
@if(count($bookChildren) > 0)
|
||||
<div class="entity-list book-contents" v-pre>
|
||||
<div class="entity-list book-contents">
|
||||
@foreach($bookChildren as $childElement)
|
||||
@if($childElement->isA('chapter'))
|
||||
@include('chapters.list-item', ['chapter' => $childElement])
|
||||
|
@ -29,7 +29,7 @@
|
|||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
<div class="mt-xl" v-pre>
|
||||
<div class="mt-xl">
|
||||
<hr>
|
||||
<p class="text-muted italic mb-m mt-xl">{{ trans('entities.books_empty_contents') }}</p>
|
||||
|
||||
|
@ -52,7 +52,7 @@
|
|||
@endif
|
||||
</div>
|
||||
|
||||
@include('partials.entity-dashboard-search-results')
|
||||
@include('partials.entity-search-results')
|
||||
</main>
|
||||
|
||||
@stop
|
||||
|
@ -126,7 +126,7 @@
|
|||
|
||||
@section('left')
|
||||
|
||||
@include('partials.entity-dashboard-search-box')
|
||||
@include('partials.entity-search-form', ['label' => trans('entities.books_search_this')])
|
||||
|
||||
@if($book->tags->count() > 0)
|
||||
<div class="mb-xl">
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
@extends('tri-layout')
|
||||
|
||||
@section('container-attrs')
|
||||
id="entity-dashboard"
|
||||
entity-id="{{ $chapter->id }}"
|
||||
entity-type="chapter"
|
||||
component="entity-search"
|
||||
option:entity-search:entity-id="{{ $chapter->id }}"
|
||||
option:entity-search:entity-type="chapter"
|
||||
@stop
|
||||
|
||||
@section('body')
|
||||
|
@ -16,17 +16,17 @@
|
|||
</div>
|
||||
|
||||
<main class="content-wrap card">
|
||||
<h1 class="break-text" v-pre>{{ $chapter->name }}</h1>
|
||||
<div class="chapter-content" v-show="!searching">
|
||||
<p v-pre class="text-muted break-text">{!! nl2br(e($chapter->description)) !!}</p>
|
||||
<h1 class="break-text">{{ $chapter->name }}</h1>
|
||||
<div refs="entity-search@contentView" class="chapter-content">
|
||||
<p class="text-muted break-text">{!! nl2br(e($chapter->description)) !!}</p>
|
||||
@if(count($pages) > 0)
|
||||
<div v-pre class="entity-list book-contents">
|
||||
<div class="entity-list book-contents">
|
||||
@foreach($pages as $page)
|
||||
@include('pages.list-item', ['page' => $page])
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
<div class="mt-xl" v-pre>
|
||||
<div class="mt-xl">
|
||||
<hr>
|
||||
<p class="text-muted italic mb-m mt-xl">{{ trans('entities.chapters_empty') }}</p>
|
||||
|
||||
|
@ -49,7 +49,7 @@
|
|||
@endif
|
||||
</div>
|
||||
|
||||
@include('partials.entity-dashboard-search-results')
|
||||
@include('partials.entity-search-results')
|
||||
</main>
|
||||
|
||||
@stop
|
||||
|
@ -130,7 +130,7 @@
|
|||
|
||||
@section('left')
|
||||
|
||||
@include('partials.entity-dashboard-search-box')
|
||||
@include('partials.entity-search-form', ['label' => trans('entities.chapters_search_this')])
|
||||
|
||||
@if($chapter->tags->count() > 0)
|
||||
<div class="mb-xl">
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
<div class="mb-xl">
|
||||
<form v-on:submit.prevent="searchBook" class="search-box flexible" role="search">
|
||||
<input v-model="searchTerm" v-on:change="checkSearchForm" type="text" aria-label="{{ trans('entities.books_search_this') }}" name="term" placeholder="{{ trans('entities.books_search_this') }}">
|
||||
<button type="submit" aria-label="{{ trans('common.search') }}">@icon('search')</button>
|
||||
<button v-if="searching" v-cloak class="search-box-cancel text-neg" v-on:click="clearSearch"
|
||||
type="button" aria-label="{{ trans('common.search_clear') }}">@icon('close')</button>
|
||||
</form>
|
||||
</div>
|
|
@ -1,15 +0,0 @@
|
|||
<div class="search-results" v-cloak v-show="searching">
|
||||
<div class="grid half v-center">
|
||||
<h3 class="text-muted px-none">
|
||||
{{ trans('entities.search_results') }}
|
||||
</h3>
|
||||
<div class="text-right">
|
||||
<a v-if="searching" v-on:click="clearSearch" class="button outline">{{ trans('entities.search_clear') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="!searchResults">
|
||||
@include('partials.loading-icon')
|
||||
</div>
|
||||
<div class="book-contents" v-html="searchResults"></div>
|
||||
</div>
|
10
resources/views/partials/entity-search-form.blade.php
Normal file
10
resources/views/partials/entity-search-form.blade.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
{{--
|
||||
@label - Placeholder/aria-label text
|
||||
--}}
|
||||
<div class="mb-xl">
|
||||
<form refs="entity-search@searchForm" class="search-box flexible" role="search">
|
||||
<input refs="entity-search@searchInput" type="text"
|
||||
aria-label="{{ $label }}" name="term" placeholder="{{ $label }}">
|
||||
<button type="submit" aria-label="{{ trans('common.search') }}">@icon('search')</button>
|
||||
</form>
|
||||
</div>
|
15
resources/views/partials/entity-search-results.blade.php
Normal file
15
resources/views/partials/entity-search-results.blade.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<div refs="entity-search@searchView" class="search-results hidden">
|
||||
<div class="grid half v-center">
|
||||
<h3 class="text-muted px-none">
|
||||
{{ trans('entities.search_results') }}
|
||||
</h3>
|
||||
<div class="text-right">
|
||||
<a refs="entity-search@clearButton" class="button outline">{{ trans('entities.search_clear') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div refs="entity-search@loadingBlock">
|
||||
@include('partials.loading-icon')
|
||||
</div>
|
||||
<div class="book-contents" refs="entity-search@searchResults"></div>
|
||||
</div>
|
Loading…
Reference in New Issue
Block a user