Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 24 additions & 6 deletions dev/docs/javascript-code.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class Dropdown {

All usage of $refs, $manyRefs and $opts should be done at the top of the `setup` function so any requirements can be easily seen.

Once defined, the component has to be registered for use. This is done in the `resources/js/components/index.js` file. You'll need to import the component class then add it to `componentMapping` object, following the pattern of other components.
Once defined, the component has to be registered for use. This is done in the `resources/js/components/index.js` file by defining an additional export, following the pattern of other components.

### Using a Component in HTML

Expand Down Expand Up @@ -80,9 +80,9 @@ Will result with `this.$opts` being:
}
```

#### Component Properties
#### Component Properties & Methods

A component has the below shown properties available for use. As mentioned above, most of these should be used within the `setup()` function to make the requirements/dependencies of the component clear.
A component has the below shown properties & methods available for use. As mentioned above, most of these should be used within the `setup()` function to make the requirements/dependencies of the component clear.

```javascript
// The root element that the compontent has been applied to.
Expand All @@ -98,6 +98,15 @@ this.$manyRefs

// Options defined for the compontent.
this.$opts

// The registered name of the component, usually kebab-case.
this.$name

// Emit a custom event from this component.
// Will be bubbled up from the dom element this is registered on,
// as a custom event with the name `<elementName>-<eventName>`,
// with the provided data in the event detail.
this.$emit(eventName, data = {})
```

## Global JavaScript Helpers
Expand Down Expand Up @@ -132,7 +141,16 @@ window.trans_plural(translationString, count, replacements);

// Component System
// Parse and initialise any components from the given root el down.
window.components.init(rootEl);
// Get the first active component of the given name
window.components.first(name);
window.$components.init(rootEl);
// Register component models to be used by the component system.
// Takes a mapping of classes/constructors keyed by component names.
// Names will be converted to kebab-case.
window.$components.register(mapping);
// Get the first active component of the given name.
window.$components.first(name);
// Get all the active components of the given name.
window.$components.get(name);
// Get the first active component of the given name that's been
// created on the given element.
window.$components.firstOnElement(element, name);
```
7 changes: 5 additions & 2 deletions resources/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,8 @@ window.trans_choice = translator.getPlural.bind(translator);
window.trans_plural = translator.parsePlural.bind(translator);

// Load Components
import components from "./components"
components();
import * as components from "./services/components"
import * as componentMap from "./components";
components.register(componentMap);
window.$components = components;
components.init();
10 changes: 4 additions & 6 deletions resources/js/components/add-remove-rows.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import {onChildEvent} from "../services/dom";
import {uniqueId} from "../services/util";
import {Component} from "./component";

/**
* AddRemoveRows
* Allows easy row add/remove controls onto a table.
* Needs a model row to use when adding a new row.
* @extends {Component}
*/
class AddRemoveRows {
export class AddRemoveRows extends Component {
setup() {
this.modelRow = this.$refs.model;
this.addButton = this.$refs.add;
Expand All @@ -31,7 +31,7 @@ class AddRemoveRows {
clone.classList.remove('hidden');
this.setClonedInputNames(clone);
this.modelRow.parentNode.insertBefore(clone, this.modelRow);
window.components.init(clone);
window.$components.init(clone);
}

/**
Expand All @@ -49,6 +49,4 @@ class AddRemoveRows {
elem.name = elem.name.split('randrowid').join(rowId);
}
}
}

export default AddRemoveRows;
}
11 changes: 3 additions & 8 deletions resources/js/components/ajax-delete-row.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
/**
* AjaxDelete
* @extends {Component}
*/
import {onSelect} from "../services/dom";
import {Component} from "./component";

class AjaxDeleteRow {
export class AjaxDeleteRow extends Component {
setup() {
this.row = this.$el;
this.url = this.$opts.url;
Expand All @@ -27,6 +24,4 @@ class AjaxDeleteRow {
this.row.style.pointerEvents = null;
});
}
}

export default AjaxDeleteRow;
}
11 changes: 4 additions & 7 deletions resources/js/components/ajax-form.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {onEnterPress, onSelect} from "../services/dom";
import {Component} from "./component";

/**
* Ajax Form
Expand All @@ -8,10 +9,8 @@ import {onEnterPress, onSelect} from "../services/dom";
*
* Will handle a real form if that's what the component is added to
* otherwise will act as a fake form element.
*
* @extends {Component}
*/
class AjaxForm {
export class AjaxForm extends Component {
setup() {
this.container = this.$el;
this.responseContainer = this.container;
Expand Down Expand Up @@ -72,11 +71,9 @@ class AjaxForm {
this.responseContainer.innerHTML = err.data;
}

window.components.init(this.responseContainer);
window.$components.init(this.responseContainer);
this.responseContainer.style.opacity = null;
this.responseContainer.style.pointerEvents = null;
}

}

export default AjaxForm;
}
9 changes: 4 additions & 5 deletions resources/js/components/attachments-list.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import {Component} from "./component";

/**
* Attachments List
* Adds '?open=true' query to file attachment links
* when ctrl/cmd is pressed down.
* @extends {Component}
*/
class AttachmentsList {
export class AttachmentsList extends Component {

setup() {
this.container = this.$el;
Expand Down Expand Up @@ -42,6 +43,4 @@ class AttachmentsList {
link.removeAttribute('target');
}
}
}

export default AttachmentsList;
}
19 changes: 8 additions & 11 deletions resources/js/components/attachments.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
/**
* Attachments
* @extends {Component}
*/
import {showLoading} from "../services/dom";
import {Component} from "./component";

class Attachments {
export class Attachments extends Component {

setup() {
this.container = this.$el;
Expand Down Expand Up @@ -46,10 +43,12 @@ class Attachments {

reloadList() {
this.stopEdit();
this.mainTabs.components.tabs.show('items');
/** @var {Tabs} */
const tabs = window.$components.firstOnElement(this.mainTabs, 'tabs');
tabs.show('items');
window.$http.get(`/attachments/get/page/${this.pageId}`).then(resp => {
this.list.innerHTML = resp.data;
window.components.init(this.list);
window.$components.init(this.list);
});
}

Expand All @@ -66,14 +65,12 @@ class Attachments {
showLoading(this.editContainer);
const resp = await window.$http.get(`/attachments/edit/${id}`);
this.editContainer.innerHTML = resp.data;
window.components.init(this.editContainer);
window.$components.init(this.editContainer);
}

stopEdit() {
this.editContainer.classList.add('hidden');
this.listContainer.classList.remove('hidden');
}

}

export default Attachments;
}
7 changes: 3 additions & 4 deletions resources/js/components/auto-submit.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import {Component} from "./component";

class AutoSubmit {
export class AutoSubmit extends Component {

setup() {
this.form = this.$el;

this.form.submit();
}

}

export default AutoSubmit;
}
8 changes: 3 additions & 5 deletions resources/js/components/auto-suggest.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import {escapeHtml} from "../services/util";
import {onChildEvent} from "../services/dom";
import {Component} from "./component";

const ajaxCache = {};

/**
* AutoSuggest
* @extends {Component}
*/
class AutoSuggest {
export class AutoSuggest extends Component {
setup() {
this.parent = this.$el.parentElement;
this.container = this.$el;
Expand Down Expand Up @@ -148,6 +148,4 @@ class AutoSuggest {
this.hideSuggestions();
}
}
}

export default AutoSuggest;
}
23 changes: 11 additions & 12 deletions resources/js/components/back-to-top.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,35 @@
import {Component} from "./component";

class BackToTop {
export class BackToTop extends Component {

constructor(elem) {
this.elem = elem;
setup() {
this.button = this.$el;
this.targetElem = document.getElementById('header');
this.showing = false;
this.breakPoint = 1200;

if (document.body.classList.contains('flexbox')) {
this.elem.style.display = 'none';
this.button.style.display = 'none';
return;
}

this.elem.addEventListener('click', this.scrollToTop.bind(this));
this.button.addEventListener('click', this.scrollToTop.bind(this));
window.addEventListener('scroll', this.onPageScroll.bind(this));
}

onPageScroll() {
let scrollTopPos = document.documentElement.scrollTop || document.body.scrollTop || 0;
if (!this.showing && scrollTopPos > this.breakPoint) {
this.elem.style.display = 'block';
this.button.style.display = 'block';
this.showing = true;
setTimeout(() => {
this.elem.style.opacity = 0.4;
this.button.style.opacity = 0.4;
}, 1);
} else if (this.showing && scrollTopPos < this.breakPoint) {
this.elem.style.opacity = 0;
this.button.style.opacity = 0;
this.showing = false;
setTimeout(() => {
this.elem.style.display = 'none';
this.button.style.display = 'none';
}, 500);
}
}
Expand All @@ -54,6 +55,4 @@ class BackToTop {
requestAnimationFrame(setPos.bind(this));
}

}

export default BackToTop;
}
26 changes: 12 additions & 14 deletions resources/js/components/book-sort.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import Sortable from "sortablejs";
import {Component} from "./component";
import {htmlToDom} from "../services/dom";

// Auto sort control
const sortOperations = {
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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);
});
Expand Down Expand Up @@ -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');
Expand Down Expand Up @@ -202,6 +202,4 @@ class BookSort {
}
}

}

export default BookSort;
}
Loading