Updated a batch of JS components

This commit is contained in:
Dan Brown 2022-11-15 11:24:31 +00:00
parent 09c6a3c240
commit 4310d34135
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
19 changed files with 124 additions and 128 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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"

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -127,7 +127,6 @@ export function register(mapping) {
for (const key of keys) {
componentMap[camelToKebab(key)] = mapping[key];
}
console.log(componentMap);
}
/**

View File

@ -1,6 +1,6 @@
// System wide notifications
[notification] {
.notification {
position: fixed;
top: 0;
right: 0;

View File

@ -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>

View File

@ -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>

View File

@ -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">

View File

@ -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>

View File

@ -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>