mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Updated a batch of JS components
This commit is contained in:
parent
09c6a3c240
commit
4310d34135
@ -1,4 +1,6 @@
|
||||
import Sortable from "sortablejs";
|
||||
import {Component} from "./component";
|
||||
import {htmlToDom} from "../services/dom";
|
||||
|
||||
// Auto sort control
|
||||
const sortOperations = {
|
||||
@ -35,14 +37,14 @@ const sortOperations = {
|
||||
},
|
||||
};
|
||||
|
||||
class BookSort {
|
||||
export class BookSort extends Component {
|
||||
|
||||
constructor(elem) {
|
||||
this.elem = elem;
|
||||
this.sortContainer = elem.querySelector('[book-sort-boxes]');
|
||||
this.input = elem.querySelector('[book-sort-input]');
|
||||
setup() {
|
||||
this.container = this.$el;
|
||||
this.sortContainer = this.$refs.sortContainer;
|
||||
this.input = this.$refs.input;
|
||||
|
||||
const initialSortBox = elem.querySelector('.sort-box');
|
||||
const initialSortBox = this.container.querySelector('.sort-box');
|
||||
this.setupBookSortable(initialSortBox);
|
||||
this.setupSortPresets();
|
||||
|
||||
@ -90,14 +92,12 @@ class BookSort {
|
||||
* @param {Object} entityInfo
|
||||
*/
|
||||
bookSelect(entityInfo) {
|
||||
const alreadyAdded = this.elem.querySelector(`[data-type="book"][data-id="${entityInfo.id}"]`) !== null;
|
||||
const alreadyAdded = this.container.querySelector(`[data-type="book"][data-id="${entityInfo.id}"]`) !== null;
|
||||
if (alreadyAdded) return;
|
||||
|
||||
const entitySortItemUrl = entityInfo.link + '/sort-item';
|
||||
window.$http.get(entitySortItemUrl).then(resp => {
|
||||
const wrap = document.createElement('div');
|
||||
wrap.innerHTML = resp.data;
|
||||
const newBookContainer = wrap.children[0];
|
||||
const newBookContainer = htmlToDom(resp.data);
|
||||
this.sortContainer.append(newBookContainer);
|
||||
this.setupBookSortable(newBookContainer);
|
||||
});
|
||||
@ -155,7 +155,7 @@ class BookSort {
|
||||
*/
|
||||
buildEntityMap() {
|
||||
const entityMap = [];
|
||||
const lists = this.elem.querySelectorAll('.sort-list');
|
||||
const lists = this.container.querySelectorAll('.sort-list');
|
||||
|
||||
for (let list of lists) {
|
||||
const bookId = list.closest('[data-type="book"]').getAttribute('data-id');
|
||||
@ -202,6 +202,4 @@ class BookSort {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default BookSort;
|
||||
}
|
@ -1,9 +1,7 @@
|
||||
import {slideUp, slideDown} from "../services/animations";
|
||||
import {Component} from "./component";
|
||||
|
||||
/**
|
||||
* @extends {Component}
|
||||
*/
|
||||
class ChapterContents {
|
||||
export class ChapterContents extends Component {
|
||||
|
||||
setup() {
|
||||
this.list = this.$refs.list;
|
||||
@ -31,7 +29,4 @@ class ChapterContents {
|
||||
event.preventDefault();
|
||||
this.isOpen ? this.close() : this.open();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ChapterContents;
|
||||
|
@ -1,14 +1,16 @@
|
||||
class CodeHighlighter {
|
||||
import {Component} from "./component";
|
||||
|
||||
constructor(elem) {
|
||||
const codeBlocks = elem.querySelectorAll('pre');
|
||||
export class CodeHighlighter extends Component{
|
||||
|
||||
setup() {
|
||||
const container = this.$el;
|
||||
|
||||
const codeBlocks = container.querySelectorAll('pre');
|
||||
if (codeBlocks.length > 0) {
|
||||
window.importVersioned('code').then(Code => {
|
||||
Code.highlightWithin(elem);
|
||||
Code.highlightWithin(container);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default CodeHighlighter;
|
||||
}
|
@ -1,21 +1,22 @@
|
||||
class DetailsHighlighter {
|
||||
import {Component} from "./component";
|
||||
|
||||
constructor(elem) {
|
||||
this.elem = elem;
|
||||
export class DetailsHighlighter extends Component {
|
||||
|
||||
setup() {
|
||||
this.container = this.$el;
|
||||
this.dealtWith = false;
|
||||
elem.addEventListener('toggle', this.onToggle.bind(this));
|
||||
|
||||
this.container.addEventListener('toggle', this.onToggle.bind(this));
|
||||
}
|
||||
|
||||
onToggle() {
|
||||
if (this.dealtWith) return;
|
||||
|
||||
if (this.elem.querySelector('pre')) {
|
||||
if (this.container.querySelector('pre')) {
|
||||
window.importVersioned('code').then(Code => {
|
||||
Code.highlightWithin(this.elem);
|
||||
Code.highlightWithin(this.container);
|
||||
});
|
||||
}
|
||||
this.dealtWith = true;
|
||||
}
|
||||
}
|
||||
|
||||
export default DetailsHighlighter;
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
import {onSelect} from "../services/dom";
|
||||
import {Component} from "./component";
|
||||
|
||||
/**
|
||||
* Dropdown
|
||||
* Provides some simple logic to create simple dropdown menus.
|
||||
* @extends {Component}
|
||||
*/
|
||||
class DropDown {
|
||||
export class Dropdown extends Component {
|
||||
|
||||
setup() {
|
||||
this.container = this.$el;
|
||||
@ -171,6 +171,4 @@ class DropDown {
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default DropDown;
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
import {onChildEvent} from "../services/dom";
|
||||
import {Component} from "./component";
|
||||
|
||||
/**
|
||||
* Entity Selector
|
||||
* @extends {Component}
|
||||
*/
|
||||
class EntitySelector {
|
||||
export class EntitySelector extends Component {
|
||||
|
||||
setup() {
|
||||
this.elem = this.$el;
|
||||
@ -185,6 +185,4 @@ class EntitySelector {
|
||||
this.selectedItemData = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default EntitySelector;
|
||||
}
|
@ -4,24 +4,24 @@ export {AjaxForm} from "./ajax-form.js"
|
||||
export {Attachments} from "./attachments.js"
|
||||
export {AttachmentsList} from "./attachments-list.js"
|
||||
export {AutoSuggest} from "./auto-suggest.js"
|
||||
export {AutoSubmit} from "./auto-submit.js";
|
||||
export {AutoSubmit} from "./auto-submit.js"
|
||||
export {BackToTop} from "./back-to-top.js"
|
||||
// export {BookSort} from "./book-sort.js"
|
||||
// export {ChapterContents} from "./chapter-contents.js"
|
||||
export {BookSort} from "./book-sort.js"
|
||||
export {ChapterContents} from "./chapter-contents.js"
|
||||
// export {CodeEditor} from "./code-editor.js"
|
||||
// export {CodeHighlighter} from "./code-highlighter.js"
|
||||
export {CodeHighlighter} from "./code-highlighter.js"
|
||||
// export {CodeTextarea} from "./code-textarea.js"
|
||||
// export {Collapsible} from "./collapsible.js"
|
||||
// export {ConfirmDialog} from "./confirm-dialog"
|
||||
// export {CustomCheckbox} from "./custom-checkbox.js"
|
||||
// export {DetailsHighlighter} from "./details-highlighter.js"
|
||||
// export {Dropdown} from "./dropdown.js"
|
||||
export {DetailsHighlighter} from "./details-highlighter.js"
|
||||
export {Dropdown} from "./dropdown.js"
|
||||
// export {DropdownSearch} from "./dropdown-search.js"
|
||||
// export {Dropzone} from "./dropzone.js"
|
||||
// export {EditorToolbox} from "./editor-toolbox.js"
|
||||
// export {EntityPermissions} from "./entity-permissions";
|
||||
// export {EntityPermissions} from "./entity-permissions"
|
||||
// export {EntitySearch} from "./entity-search.js"
|
||||
// export {EntitySelector} from "./entity-selector.js"
|
||||
export {EntitySelector} from "./entity-selector.js"
|
||||
// export {EntitySelectorPopup} from "./entity-selector-popup.js"
|
||||
// export {EventEmitSelect} from "./event-emit-select.js"
|
||||
// export {ExpandToggle} from "./expand-toggle.js"
|
||||
@ -32,20 +32,20 @@ export {BackToTop} from "./back-to-top.js"
|
||||
// export {ListSortControl} from "./list-sort-control.js"
|
||||
// export {MarkdownEditor} from "./markdown-editor.js"
|
||||
// export {NewUserPassword} from "./new-user-password.js"
|
||||
// export {Notification} from "./notification.js"
|
||||
export {Notification} from "./notification.js"
|
||||
// export {OptionalInput} from "./optional-input.js"
|
||||
// export {PageComments} from "./page-comments.js"
|
||||
export {PageComments} from "./page-comments.js"
|
||||
// export {PageDisplay} from "./page-display.js"
|
||||
// export {PageEditor} from "./page-editor.js"
|
||||
// export {PagePicker} from "./page-picker.js"
|
||||
// export {PermissionsTable} from "./permissions-table.js"
|
||||
// export {Pointer} from "./pointer.js";
|
||||
export {Pointer} from "./pointer.js";
|
||||
// export {Popup} from "./popup.js"
|
||||
// export {SettingAppColorPicker} from "./setting-app-color-picker.js"
|
||||
// export {SettingColorPicker} from "./setting-color-picker.js"
|
||||
// export {ShelfSort} from "./shelf-sort.js"
|
||||
// export {Shortcuts} from "./shortcuts";
|
||||
// export {ShortcutInput} from "./shortcut-input";
|
||||
export {Shortcuts} from "./shortcuts"
|
||||
export {ShortcutInput} from "./shortcut-input"
|
||||
// export {Sidebar} from "./sidebar.js"
|
||||
// export {SortableList} from "./sortable-list.js"
|
||||
// export {SubmitOnChange} from "./submit-on-change.js"
|
||||
|
@ -1,19 +1,21 @@
|
||||
import {Component} from "./component";
|
||||
|
||||
class Notification {
|
||||
export class Notification extends Component {
|
||||
|
||||
constructor(elem) {
|
||||
this.elem = elem;
|
||||
this.type = elem.getAttribute('notification');
|
||||
this.textElem = elem.querySelector('span');
|
||||
this.autohide = this.elem.hasAttribute('data-autohide');
|
||||
this.elem.style.display = 'grid';
|
||||
setup() {
|
||||
this.container = this.$el;
|
||||
this.type = this.$opts.type;
|
||||
this.textElem = this.container.querySelector('span');
|
||||
this.autoHide = this.$opts.autoHide === 'true';
|
||||
this.initialShow = this.$opts.show === 'true'
|
||||
this.container.style.display = 'grid';
|
||||
|
||||
window.$events.listen(this.type, text => {
|
||||
this.show(text);
|
||||
});
|
||||
elem.addEventListener('click', this.hide.bind(this));
|
||||
this.container.addEventListener('click', this.hide.bind(this));
|
||||
|
||||
if (elem.hasAttribute('data-show')) {
|
||||
if (this.initialShow) {
|
||||
setTimeout(() => this.show(this.textElem.textContent), 100);
|
||||
}
|
||||
|
||||
@ -21,14 +23,14 @@ class Notification {
|
||||
}
|
||||
|
||||
show(textToShow = '') {
|
||||
this.elem.removeEventListener('transitionend', this.hideCleanup);
|
||||
this.container.removeEventListener('transitionend', this.hideCleanup);
|
||||
this.textElem.textContent = textToShow;
|
||||
this.elem.style.display = 'grid';
|
||||
this.container.style.display = 'grid';
|
||||
setTimeout(() => {
|
||||
this.elem.classList.add('showing');
|
||||
this.container.classList.add('showing');
|
||||
}, 1);
|
||||
|
||||
if (this.autohide) {
|
||||
if (this.autoHide) {
|
||||
const words = textToShow.split(' ').length;
|
||||
const timeToShow = Math.max(2000, 1000 + (250 * words));
|
||||
setTimeout(this.hide.bind(this), timeToShow);
|
||||
@ -36,15 +38,13 @@ class Notification {
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.elem.classList.remove('showing');
|
||||
this.elem.addEventListener('transitionend', this.hideCleanup);
|
||||
this.container.classList.remove('showing');
|
||||
this.container.addEventListener('transitionend', this.hideCleanup);
|
||||
}
|
||||
|
||||
hideCleanup() {
|
||||
this.elem.style.display = 'none';
|
||||
this.elem.removeEventListener('transitionend', this.hideCleanup);
|
||||
this.container.style.display = 'none';
|
||||
this.container.removeEventListener('transitionend', this.hideCleanup);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Notification;
|
||||
}
|
@ -1,9 +1,8 @@
|
||||
import {scrollAndHighlightElement} from "../services/util";
|
||||
import {Component} from "./component";
|
||||
import {htmlToDom} from "../services/dom";
|
||||
|
||||
/**
|
||||
* @extends {Component}
|
||||
*/
|
||||
class PageComments {
|
||||
export class PageComments extends Component {
|
||||
|
||||
setup() {
|
||||
this.elem = this.$el;
|
||||
@ -119,9 +118,7 @@ class PageComments {
|
||||
};
|
||||
this.showLoading(this.form);
|
||||
window.$http.post(`/comment/${this.pageId}`, reqData).then(resp => {
|
||||
let newComment = document.createElement('div');
|
||||
newComment.innerHTML = resp.data;
|
||||
let newElem = newComment.children[0];
|
||||
const newElem = htmlToDom(resp.data);
|
||||
this.container.appendChild(newElem);
|
||||
window.$components.init(newElem);
|
||||
window.$events.success(this.createdText);
|
||||
@ -199,6 +196,4 @@ class PageComments {
|
||||
formElem.querySelector('.form-group.loading').style.display = 'none';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default PageComments;
|
||||
}
|
@ -1,10 +1,9 @@
|
||||
import * as DOM from "../services/dom";
|
||||
import Clipboard from "clipboard/dist/clipboard.min";
|
||||
import {Component} from "./component";
|
||||
|
||||
/**
|
||||
* @extends Component
|
||||
*/
|
||||
class Pointer {
|
||||
|
||||
export class Pointer extends Component {
|
||||
|
||||
setup() {
|
||||
this.container = this.$el;
|
||||
@ -126,6 +125,4 @@ class Pointer {
|
||||
editAnchor.href = `${editHref}?content-id=${elementId}&content-text=${encodeURIComponent(queryContent)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Pointer;
|
||||
}
|
@ -1,13 +1,12 @@
|
||||
import {Component} from "./component";
|
||||
|
||||
/**
|
||||
* Keys to ignore when recording shortcuts.
|
||||
* @type {string[]}
|
||||
*/
|
||||
const ignoreKeys = ['Control', 'Alt', 'Shift', 'Meta', 'Super', ' ', '+', 'Tab', 'Escape'];
|
||||
|
||||
/**
|
||||
* @extends {Component}
|
||||
*/
|
||||
class ShortcutInput {
|
||||
export class ShortcutInput extends Component {
|
||||
|
||||
setup() {
|
||||
this.input = this.$el;
|
||||
@ -52,6 +51,4 @@ class ShortcutInput {
|
||||
this.input.removeEventListener('keydown', this.listenerRecordKey);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ShortcutInput;
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
import {Component} from "./component";
|
||||
|
||||
function reverseMap(map) {
|
||||
const reversed = {};
|
||||
for (const [key, value] of Object.entries(map)) {
|
||||
@ -6,10 +8,8 @@ function reverseMap(map) {
|
||||
return reversed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @extends {Component}
|
||||
*/
|
||||
class Shortcuts {
|
||||
|
||||
export class Shortcuts extends Component {
|
||||
|
||||
setup() {
|
||||
this.container = this.$el;
|
||||
@ -159,6 +159,4 @@ class Shortcuts {
|
||||
|
||||
this.hintsShowing = false;
|
||||
}
|
||||
}
|
||||
|
||||
export default Shortcuts;
|
||||
}
|
@ -127,7 +127,6 @@ export function register(mapping) {
|
||||
for (const key of keys) {
|
||||
componentMap[camelToKebab(key)] = mapping[key];
|
||||
}
|
||||
console.log(componentMap);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,6 @@
|
||||
|
||||
// System wide notifications
|
||||
[notification] {
|
||||
.notification {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
|
@ -38,7 +38,7 @@
|
||||
|
||||
<div style="overflow: auto;">
|
||||
|
||||
<section code-highlighter class="card content-wrap auto-height">
|
||||
<section component="code-highlighter" class="card content-wrap auto-height">
|
||||
@include('api-docs.parts.getting-started')
|
||||
</section>
|
||||
|
||||
|
@ -34,14 +34,14 @@
|
||||
@endif
|
||||
|
||||
@if($endpoint['example_request'] ?? false)
|
||||
<details details-highlighter class="mb-m">
|
||||
<details component="details-highlighter" class="mb-m">
|
||||
<summary class="text-muted">Example Request</summary>
|
||||
<pre><code class="language-json">{{ $endpoint['example_request'] }}</code></pre>
|
||||
</details>
|
||||
@endif
|
||||
|
||||
@if($endpoint['example_response'] ?? false)
|
||||
<details details-highlighter class="mb-m">
|
||||
<details component="details-highlighter" class="mb-m">
|
||||
<summary class="text-muted">Example Response</summary>
|
||||
<pre><code class="language-json">{{ $endpoint['example_response'] }}</code></pre>
|
||||
</details>
|
||||
|
@ -4,11 +4,11 @@
|
||||
<span>{{ $book->name }}</span>
|
||||
</h5>
|
||||
<div class="sort-box-options pb-sm">
|
||||
<a href="#" data-sort="name" class="button outline small">{{ trans('entities.books_sort_name') }}</a>
|
||||
<a href="#" data-sort="created" class="button outline small">{{ trans('entities.books_sort_created') }}</a>
|
||||
<a href="#" data-sort="updated" class="button outline small">{{ trans('entities.books_sort_updated') }}</a>
|
||||
<a href="#" data-sort="chaptersFirst" class="button outline small">{{ trans('entities.books_sort_chapters_first') }}</a>
|
||||
<a href="#" data-sort="chaptersLast" class="button outline small">{{ trans('entities.books_sort_chapters_last') }}</a>
|
||||
<button type="button" data-sort="name" class="button outline small">{{ trans('entities.books_sort_name') }}</button>
|
||||
<button type="button" data-sort="created" class="button outline small">{{ trans('entities.books_sort_created') }}</button>
|
||||
<button type="button" data-sort="updated" class="button outline small">{{ trans('entities.books_sort_updated') }}</button>
|
||||
<button type="button" data-sort="chaptersFirst" class="button outline small">{{ trans('entities.books_sort_chapters_first') }}</button>
|
||||
<button type="button" data-sort="chaptersLast" class="button outline small">{{ trans('entities.books_sort_chapters_last') }}</button>
|
||||
</div>
|
||||
<ul class="sortable-page-list sort-list">
|
||||
|
||||
|
@ -16,16 +16,16 @@
|
||||
|
||||
<div class="grid left-focus gap-xl">
|
||||
<div>
|
||||
<div book-sort class="card content-wrap">
|
||||
<div component="book-sort" class="card content-wrap">
|
||||
<h1 class="list-heading mb-l">{{ trans('entities.books_sort') }}</h1>
|
||||
<div book-sort-boxes>
|
||||
<div refs="book-sort@sortContainer">
|
||||
@include('books.parts.sort-box', ['book' => $book, 'bookChildren' => $bookChildren])
|
||||
</div>
|
||||
|
||||
<form action="{{ $book->getUrl('/sort') }}" method="POST">
|
||||
{!! csrf_field() !!}
|
||||
<input type="hidden" name="_method" value="PUT">
|
||||
<input book-sort-input type="hidden" name="sort-tree">
|
||||
<input refs="book-sort@input" type="hidden" name="sort-tree">
|
||||
<div class="list text-right">
|
||||
<a href="{{ $book->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
|
||||
<button class="button" type="submit">{{ trans('entities.books_sort_save') }}</button>
|
||||
|
@ -1,11 +1,29 @@
|
||||
<div notification="success" style="display: none;" data-autohide class="pos" role="alert" @if(session()->has('success')) data-show @endif>
|
||||
<div component="notification"
|
||||
option:notification:type="success"
|
||||
option:notification:auto-hide="true"
|
||||
option:notification:show="{{ session()->has('success') ? 'true' : 'false' }}"
|
||||
style="display: none;"
|
||||
class="notification pos"
|
||||
role="alert">
|
||||
@icon('check-circle') <span>{!! nl2br(htmlentities(session()->get('success'))) !!}</span><div class="dismiss">@icon('close')</div>
|
||||
</div>
|
||||
|
||||
<div notification="warning" style="display: none;" class="warning" role="alert" @if(session()->has('warning')) data-show @endif>
|
||||
<div component="notification"
|
||||
option:notification:type="warning"
|
||||
option:notification:auto-hide="false"
|
||||
option:notification:show="{{ session()->has('warning') ? 'true' : 'false' }}"
|
||||
style="display: none;"
|
||||
class="notification warning"
|
||||
role="alert">
|
||||
@icon('info') <span>{!! nl2br(htmlentities(session()->get('warning'))) !!}</span><div class="dismiss">@icon('close')</div>
|
||||
</div>
|
||||
|
||||
<div notification="error" style="display: none;" class="neg" role="alert" @if(session()->has('error')) data-show @endif>
|
||||
<div component="notification"
|
||||
option:notification:type="error"
|
||||
option:notification:auto-hide="false"
|
||||
option:notification:show="{{ session()->has('error') ? 'true' : 'false' }}"
|
||||
style="display: none;"
|
||||
class="notification neg"
|
||||
role="alert">
|
||||
@icon('danger') <span>{!! nl2br(htmlentities(session()->get('error'))) !!}</span><div class="dismiss">@icon('close')</div>
|
||||
</div>
|
||||
</div>
|
Loading…
Reference in New Issue
Block a user