import Sortable from "sortablejs";
+import {Component} from "./component";
+import {htmlToDom} from "../services/dom";
// Auto sort control
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();
* @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);
});
*/
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');
}
}
-}
-
-export default BookSort;
\ No newline at end of file
+}
\ No newline at end of file
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;
event.preventDefault();
this.isOpen ? this.close() : this.open();
}
-
}
-
-export default ChapterContents;
-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;
\ No newline at end of file
+}
\ No newline at end of file
-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;
\ No newline at end of file
+}
\ No newline at end of file
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;
});
}
-}
-
-export default DropDown;
\ No newline at end of file
+}
\ No newline at end of file
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;
this.selectedItemData = null;
}
-}
-
-export default EntitySelector;
\ No newline at end of file
+}
\ No newline at end of file
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"
// 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"
+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);
}
}
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);
}
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;
\ No newline at end of file
+}
\ No newline at end of file
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;
};
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);
formElem.querySelector('.form-group.loading').style.display = 'none';
}
-}
-
-export default PageComments;
\ No newline at end of file
+}
\ No newline at end of file
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;
editAnchor.href = `${editHref}?content-id=${elementId}&content-text=${encodeURIComponent(queryContent)}`;
}
}
-}
-
-export default Pointer;
\ No newline at end of file
+}
\ No newline at end of file
+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;
this.input.removeEventListener('keydown', this.listenerRecordKey);
}
-}
-
-export default ShortcutInput;
\ No newline at end of file
+}
\ No newline at end of file
+import {Component} from "./component";
+
function reverseMap(map) {
const reversed = {};
for (const [key, value] of Object.entries(map)) {
return reversed;
}
-/**
- * @extends {Component}
- */
-class Shortcuts {
+
+export class Shortcuts extends Component {
setup() {
this.container = this.$el;
this.hintsShowing = false;
}
-}
-
-export default Shortcuts;
\ No newline at end of file
+}
\ No newline at end of file
for (const key of keys) {
componentMap[camelToKebab(key)] = mapping[key];
}
- console.log(componentMap);
}
/**
// System wide notifications
-[notification] {
+.notification {
position: fixed;
top: 0;
right: 0;
<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>
@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>
<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">
<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>
-<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>
\ No newline at end of file