"@codemirror/state": "^6.2.0",
"@codemirror/theme-one-dark": "^6.1.1",
"@codemirror/view": "^6.9.4",
+ "@lezer/highlight": "^1.1.4",
"@ssddanbrown/codemirror-lang-smarty": "^1.0.0",
"@ssddanbrown/codemirror-lang-twig": "^1.0.0",
"codemirror": "^6.0.1",
"@codemirror/state": "^6.2.0",
"@codemirror/theme-one-dark": "^6.1.1",
"@codemirror/view": "^6.9.4",
+ "@lezer/highlight": "^1.1.4",
"@ssddanbrown/codemirror-lang-smarty": "^1.0.0",
"@ssddanbrown/codemirror-lang-twig": "^1.0.0",
"codemirror": "^6.0.1",
"es2021": true
},
"extends": "airbnb-base",
- "ignorePatterns": ["resources/**/*-stub.js"],
- "overrides": [
+ "ignorePatterns": [
+ "resources/**/*-stub.js"
],
+ "overrides": [],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"rules": {
- "indent": ["error", 4],
- "arrow-parens": ["error", "as-needed"],
- "padded-blocks": ["error", {
+ "indent": [
+ "error",
+ 4
+ ],
+ "arrow-parens": [
+ "error",
+ "as-needed"
+ ],
+ "padded-blocks": [
+ "error",
+ {
"blocks": "never",
"classes": "always"
- }],
- "object-curly-spacing": ["error", "never"],
- "space-before-function-paren": ["error", {
- "anonymous": "never",
- "named": "never",
- "asyncArrow": "always"
- }],
+ }
+ ],
+ "object-curly-spacing": [
+ "error",
+ "never"
+ ],
+ "space-before-function-paren": [
+ "error",
+ {
+ "anonymous": "never",
+ "named": "never",
+ "asyncArrow": "always"
+ }
+ ],
"import/prefer-default-export": "off",
- "no-plusplus": ["error", {
- "allowForLoopAfterthoughts": true
- }],
+ "no-plusplus": [
+ "error",
+ {
+ "allowForLoopAfterthoughts": true
+ }
+ ],
"arrow-body-style": "off",
"no-restricted-syntax": "off",
"no-continue": "off",
- "no-console": ["warn", {
- "allow": ["error"]
- }],
- "max-len": ["error", {
- "code": 110,
- "tabWidth": 4,
- "ignoreUrls": true,
- "ignoreComments": false,
- "ignoreRegExpLiterals": true,
- "ignoreStrings": true,
- "ignoreTemplateLiterals": true
- }],
- "no-param-reassign": ["error", {
- "props": false
- }]
+ "prefer-destructuring": "off",
+ "class-methods-use-this": "off",
+ "no-param-reassign": "off",
+ "no-console": [
+ "warn",
+ {
+ "allow": [
+ "error",
+ "warn"
+ ]
+ }
+ ],
+ "no-new": "off",
+ "max-len": [
+ "error",
+ {
+ "code": 110,
+ "tabWidth": 4,
+ "ignoreUrls": true,
+ "ignoreComments": false,
+ "ignoreRegExpLiterals": true,
+ "ignoreStrings": true,
+ "ignoreTemplateLiterals": true
+ }
+ ]
}
}
}
-import events from './services/events';
+import * as events from './services/events';
import * as httpInstance from './services/http';
import Translations from './services/translations';
import {SimpleEditorInterface} from './simple-editor-interface';
/**
- * Highlight pre elements on a page
+ * Add a button to a CodeMirror instance which copies the contents to the clipboard upon click.
+ * @param {EditorView} editorView
*/
-export function highlight() {
- const codeBlocks = document.querySelectorAll('.page-content pre, .comment-box .content pre');
- for (const codeBlock of codeBlocks) {
- highlightElem(codeBlock);
- }
-}
+function addCopyIcon(editorView) {
+ const copyIcon = '<svg viewBox="0 0 24 24" width="16" height="16" xmlns="http://www.w3.org/2000/svg"><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></svg>';
+ const checkIcon = '<svg viewBox="0 0 24 24" width="16" height="16" xmlns="http://www.w3.org/2000/svg"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>';
+ const copyButton = document.createElement('button');
+ copyButton.setAttribute('type', 'button');
+ copyButton.classList.add('cm-copy-button');
+ copyButton.innerHTML = copyIcon;
+ editorView.dom.appendChild(copyButton);
-/**
- * Highlight all code blocks within the given parent element
- * @param {HTMLElement} parent
- */
-export function highlightWithin(parent) {
- const codeBlocks = parent.querySelectorAll('pre');
- for (const codeBlock of codeBlocks) {
- highlightElem(codeBlock);
- }
+ const notifyTime = 620;
+ const transitionTime = 60;
+ copyButton.addEventListener('click', () => {
+ copyTextToClipboard(editorView.state.doc.toString());
+ copyButton.classList.add('success');
+
+ setTimeout(() => {
+ copyButton.innerHTML = checkIcon;
+ }, transitionTime / 2);
+
+ setTimeout(() => {
+ copyButton.classList.remove('success');
+ }, notifyTime);
+
+ setTimeout(() => {
+ copyButton.innerHTML = copyIcon;
+ }, notifyTime + (transitionTime / 2));
+ });
}
/**
*/
function highlightElem(elem) {
const innerCodeElem = elem.querySelector('code[class^=language-]');
- elem.innerHTML = elem.innerHTML.replace(/<br\s*[\/]?>/gi, '\n');
+ elem.innerHTML = elem.innerHTML.replace(/<br\s*\/?>/gi, '\n');
const content = elem.textContent.trimEnd();
let langName = '';
}
/**
- * Add a button to a CodeMirror instance which copies the contents to the clipboard upon click.
- * @param {EditorView} editorView
+ * Highlight all code blocks within the given parent element
+ * @param {HTMLElement} parent
*/
-function addCopyIcon(editorView) {
- const copyIcon = '<svg viewBox="0 0 24 24" width="16" height="16" xmlns="http://www.w3.org/2000/svg"><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></svg>';
- const checkIcon = '<svg viewBox="0 0 24 24" width="16" height="16" xmlns="http://www.w3.org/2000/svg"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>';
- const copyButton = document.createElement('button');
- copyButton.setAttribute('type', 'button');
- copyButton.classList.add('cm-copy-button');
- copyButton.innerHTML = copyIcon;
- editorView.dom.appendChild(copyButton);
-
- const notifyTime = 620;
- const transitionTime = 60;
- copyButton.addEventListener('click', event => {
- copyTextToClipboard(editorView.state.doc.toString());
- copyButton.classList.add('success');
-
- setTimeout(() => {
- copyButton.innerHTML = checkIcon;
- }, transitionTime / 2);
-
- setTimeout(() => {
- copyButton.classList.remove('success');
- }, notifyTime);
+export function highlightWithin(parent) {
+ const codeBlocks = parent.querySelectorAll('pre');
+ for (const codeBlock of codeBlocks) {
+ highlightElem(codeBlock);
+ }
+}
- setTimeout(() => {
- copyButton.innerHTML = copyIcon;
- }, notifyTime + (transitionTime / 2));
- });
+/**
+ * Highlight pre elements on a page
+ */
+export function highlight() {
+ const codeBlocks = document.querySelectorAll('.page-content pre, .comment-box .content pre');
+ for (const codeBlock of codeBlocks) {
+ highlightElem(codeBlock);
+ }
}
/**
window.$events.emit('success', resp.data.message);
}
this.row.remove();
- }).catch(err => {
+ }).catch(() => {
this.row.style.opacity = null;
this.row.style.pointerEvents = null;
});
this.startEdit(event.detail.id);
});
- this.container.addEventListener('event-emit-select-edit-back', event => {
+ this.container.addEventListener('event-emit-select-edit-back', () => {
this.stopEdit();
});
setupListeners() {
const navHandler = new KeyboardNavigationHandler(
this.list,
- event => {
+ () => {
this.input.focus();
setTimeout(() => this.hideSuggestions(), 1);
},
*/
displaySuggestions(suggestions) {
if (suggestions.length === 0) {
- return this.hideSuggestions();
+ this.hideSuggestions();
+ return;
}
// This used to use <button>s but was changed to div elements since Safari would not focus on buttons
*/
const moveActions = {
up: {
- active(elem, parent, book) {
+ active(elem, parent) {
return !(elem.previousElementSibling === null && !parent);
},
- run(elem, parent, book) {
+ run(elem, parent) {
const newSibling = elem.previousElementSibling || parent;
newSibling.insertAdjacentElement('beforebegin', elem);
},
},
down: {
- active(elem, parent, book) {
+ active(elem, parent) {
return !(elem.nextElementSibling === null && !parent);
},
- run(elem, parent, book) {
+ run(elem, parent) {
const newSibling = elem.nextElementSibling || parent;
newSibling.insertAdjacentElement('afterend', elem);
},
},
},
next_chapter: {
- active(elem, parent, book) {
+ active(elem, parent) {
return elem.dataset.type === 'page' && this.getNextChapter(elem, parent);
},
- run(elem, parent, book) {
+ run(elem, parent) {
const nextChapter = this.getNextChapter(elem, parent);
nextChapter.querySelector('ul').prepend(elem);
},
const topLevel = (parent || elem);
const topItems = Array.from(topLevel.parentElement.children);
const index = topItems.indexOf(topLevel);
- return topItems.slice(index + 1).find(elem => elem.dataset.type === 'chapter');
+ return topItems.slice(index + 1).find(item => item.dataset.type === 'chapter');
},
},
prev_chapter: {
- active(elem, parent, book) {
+ active(elem, parent) {
return elem.dataset.type === 'page' && this.getPrevChapter(elem, parent);
},
- run(elem, parent, book) {
+ run(elem, parent) {
const prevChapter = this.getPrevChapter(elem, parent);
prevChapter.querySelector('ul').append(elem);
},
const topLevel = (parent || elem);
const topItems = Array.from(topLevel.parentElement.children);
const index = topItems.indexOf(topLevel);
- return topItems.slice(0, index).reverse().find(elem => elem.dataset.type === 'chapter');
+ return topItems.slice(0, index).reverse().find(item => item.dataset.type === 'chapter');
},
},
book_end: {
- active(elem, parent, book) {
+ active(elem, parent) {
return parent || (parent === null && elem.nextElementSibling);
},
run(elem, parent, book) {
},
},
book_start: {
- active(elem, parent, book) {
+ active(elem, parent) {
return parent || (parent === null && elem.previousElementSibling);
},
run(elem, parent, book) {
},
},
before_chapter: {
- active(elem, parent, book) {
+ active(elem, parent) {
return parent;
},
- run(elem, parent, book) {
+ run(elem, parent) {
parent.insertAdjacentElement('beforebegin', elem);
},
},
after_chapter: {
- active(elem, parent, book) {
+ active(elem, parent) {
return parent;
},
- run(elem, parent, book) {
+ run(elem, parent) {
parent.insertAdjacentElement('afterend', elem);
},
},
reverse = (lastSort === sort) ? !reverse : false;
let sortFunction = sortOperations[sort];
if (reverse && reversibleTypes.includes(sort)) {
- sortFunction = function(a, b) {
+ sortFunction = function reverseSortOperation(a, b) {
return 0 - sortOperations[sort](a, b);
};
}
animation: 150,
fallbackOnBody: true,
swapThreshold: 0.65,
- onSort: event => {
+ onSort: () => {
this.ensureNoNestedChapters();
this.updateMapInput();
this.updateMoveActionStateForAll();
click(event) {
event.preventDefault();
- this.isOpen ? this.close() : this.open();
+ if (this.isOpen) {
+ this.close();
+ } else {
+ this.open();
+ }
}
}
this.languageInputChange(language);
});
- onEnterPress(this.languageInput, e => this.save());
- this.languageInput.addEventListener('input', e => this.languageInputChange(this.languageInput.value));
- onSelect(this.saveButton, e => this.save());
+ onEnterPress(this.languageInput, () => this.save());
+ this.languageInput.addEventListener('input', () => this.languageInputChange(this.languageInput.value));
+ onSelect(this.saveButton, () => this.save());
onChildEvent(this.historyList, 'button', 'click', (event, elem) => {
event.preventDefault();
onChildEvent(button.parentElement, '.lang-option-favorite-toggle', 'click', () => {
isFavorite = !isFavorite;
- isFavorite ? this.favourites.add(language) : this.favourites.delete(language);
+ const action = isFavorite ? this.favourites.add : this.favourites.delete;
+ action(language);
button.setAttribute('data-favourite', isFavorite ? 'true' : 'false');
window.$http.patch('/preferences/update-code-language-favourite', {
const historyKeys = Object.keys(this.history).reverse();
this.historyDropDown.classList.toggle('hidden', historyKeys.length === 0);
this.historyList.innerHTML = historyKeys.map(key => {
- const localTime = (new Date(parseInt(key))).toLocaleTimeString();
+ const localTime = (new Date(parseInt(key, 10))).toLocaleTimeString();
return `<li><button type="button" data-time="${key}" class="text-item">${localTime}</button></li>`;
}).join('');
}
this.sendResult(false);
});
- return new Promise((res, rej) => {
+ return new Promise(res => {
this.res = res;
});
}
this.menu.style.position = 'fixed';
this.menu.style.width = `${menuOriginalRect.width}px`;
this.menu.style.left = `${menuOriginalRect.left}px`;
- heightOffset = dropUpwards ? (window.innerHeight - menuOriginalRect.top - toggleHeight / 2) : menuOriginalRect.top;
+ if (dropUpwards) {
+ heightOffset = (window.innerHeight - menuOriginalRect.top - toggleHeight / 2);
+ } else {
+ heightOffset = menuOriginalRect.top;
+ }
}
// Adjust menu to display upwards if near the bottom of the screen
// Set listener to hide on mouse leave or window click
this.menu.addEventListener('mouseleave', this.hide);
- window.addEventListener('click', event => {
- if (!this.menu.contains(event.target)) {
+ window.addEventListener('click', clickEvent => {
+ if (!this.menu.contains(clickEvent.target)) {
this.hide();
}
});
this.uploadLimitMessage = this.$opts.uploadLimitMessage;
this.timeoutMessage = this.$opts.timeoutMessage;
- const _this = this;
+ const component = this;
this.dz = new DropZoneLib(this.container, {
addRemoveLinks: true,
dictRemoveFile: this.removeMessage,
withCredentials: true,
init() {
this.dz = this;
- this.dz.on('sending', _this.onSending.bind(_this));
- this.dz.on('success', _this.onSuccess.bind(_this));
- this.dz.on('error', _this.onError.bind(_this));
+ this.dz.on('sending', component.onSending.bind(component));
+ this.dz.on('success', component.onSuccess.bind(component));
+ this.dz.on('error', component.onError.bind(component));
},
});
}
const token = window.document.querySelector('meta[name=token]').getAttribute('content');
data.append('_token', token);
- xhr.ontimeout = e => {
+ xhr.ontimeout = () => {
this.dz.emit('complete', file);
this.dz.emit('error', file, this.timeoutMessage);
};
});
// Role select change
- this.roleSelect.addEventListener('change', event => {
+ this.roleSelect.addEventListener('change', () => {
const roleId = this.roleSelect.value;
if (roleId) {
this.addRoleRow(roleId);
runSearch() {
const term = this.searchInput.value.trim();
if (term.length === 0) {
- return this.clearSearch();
+ this.clearSearch();
+ return;
}
this.searchView.classList.remove('hidden');
this.elem.addEventListener('click', this.onClick.bind(this));
let lastSearch = 0;
- this.searchInput.addEventListener('input', event => {
+ this.searchInput.addEventListener('input', () => {
lastSearch = Date.now();
this.showLoading();
setTimeout(() => {
});
// Keyboard navigation
- onChildEvent(this.$el, '[data-entity-type]', 'keydown', (e, el) => {
- if (e.ctrlKey && e.code === 'Enter') {
+ onChildEvent(this.$el, '[data-entity-type]', 'keydown', event => {
+ if (event.ctrlKey && event.code === 'Enter') {
const form = this.$el.closest('form');
if (form) {
form.submit();
- e.preventDefault();
+ event.preventDefault();
return;
}
}
- if (e.code === 'ArrowDown') {
+ if (event.code === 'ArrowDown') {
this.focusAdjacent(true);
}
- if (e.code === 'ArrowUp') {
+ if (event.code === 'ArrowUp') {
this.focusAdjacent(false);
}
});
- this.searchInput.addEventListener('keydown', e => {
- if (e.code === 'ArrowDown') {
+ this.searchInput.addEventListener('keydown', event => {
+ if (event.code === 'ArrowDown') {
this.focusAdjacent(true);
}
});
export class ExpandToggle extends Component {
- setup(elem) {
+ setup() {
this.targetSelector = this.$opts.targetSelector;
this.isOpen = this.$opts.isOpen === 'true';
this.updateEndpoint = this.$opts.updateEndpoint;
const matchingElems = document.querySelectorAll(this.targetSelector);
for (const match of matchingElems) {
- this.isOpen ? this.close(match) : this.open(match);
+ const action = this.isOpen ? this.close : this.open;
+ action(match);
}
this.isOpen = !this.isOpen;
event.preventDefault();
});
- onSelect(this.cancelSearch, event => {
+ onSelect(this.cancelSearch, () => {
this.resetListView();
this.resetSearchView();
this.loadGallery();
this.cancelSearch.classList.remove('active');
});
- this.searchInput.addEventListener('input', event => {
+ this.searchInput.addEventListener('input', () => {
this.cancelSearch.classList.toggle('active', this.searchInput.value.trim());
});
onChildEvent(this.listContainer, '.load-more', 'click', async event => {
showLoading(event.target);
- this.page++;
+ this.page += 1;
await this.loadGallery();
event.target.remove();
});
this.listContainer.addEventListener('event-emit-select-image', this.onImageSelectEvent.bind(this));
this.listContainer.addEventListener('error', event => {
- event.target.src = baseUrl('loading_error.png');
+ event.target.src = window.baseUrl('loading_error.png');
}, true);
onSelect(this.selectButton, () => {
this.hide();
});
- onChildEvent(this.formContainer, '#image-manager-delete', 'click', event => {
+ onChildEvent(this.formContainer, '#image-manager-delete', 'click', () => {
if (this.lastSelected) {
this.loadImageEditForm(this.lastSelected.id, true);
}
-export {AddRemoveRows} from './add-remove-rows.js';
-export {AjaxDeleteRow} from './ajax-delete-row.js';
-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 {BackToTop} from './back-to-top.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 {CodeTextarea} from './code-textarea.js';
-export {Collapsible} from './collapsible.js';
+export {AddRemoveRows} from './add-remove-rows';
+export {AjaxDeleteRow} from './ajax-delete-row';
+export {AjaxForm} from './ajax-form';
+export {Attachments} from './attachments';
+export {AttachmentsList} from './attachments-list';
+export {AutoSuggest} from './auto-suggest';
+export {AutoSubmit} from './auto-submit';
+export {BackToTop} from './back-to-top';
+export {BookSort} from './book-sort';
+export {ChapterContents} from './chapter-contents';
+export {CodeEditor} from './code-editor';
+export {CodeHighlighter} from './code-highlighter';
+export {CodeTextarea} from './code-textarea';
+export {Collapsible} from './collapsible';
export {ConfirmDialog} from './confirm-dialog';
-export {CustomCheckbox} from './custom-checkbox.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 {CustomCheckbox} from './custom-checkbox';
+export {DetailsHighlighter} from './details-highlighter';
+export {Dropdown} from './dropdown';
+export {DropdownSearch} from './dropdown-search';
+export {Dropzone} from './dropzone';
+export {EditorToolbox} from './editor-toolbox';
export {EntityPermissions} from './entity-permissions';
-export {EntitySearch} from './entity-search.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 {GlobalSearch} from './global-search.js';
-export {HeaderMobileToggle} from './header-mobile-toggle.js';
-export {ImageManager} from './image-manager.js';
-export {ImagePicker} from './image-picker.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 {OptionalInput} from './optional-input.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 {Popup} from './popup.js';
-export {SettingAppColorScheme} from './setting-app-color-scheme.js';
-export {SettingColorPicker} from './setting-color-picker.js';
-export {SettingHomepageControl} from './setting-homepage-control.js';
-export {ShelfSort} from './shelf-sort.js';
+export {EntitySearch} from './entity-search';
+export {EntitySelector} from './entity-selector';
+export {EntitySelectorPopup} from './entity-selector-popup';
+export {EventEmitSelect} from './event-emit-select';
+export {ExpandToggle} from './expand-toggle';
+export {GlobalSearch} from './global-search';
+export {HeaderMobileToggle} from './header-mobile-toggle';
+export {ImageManager} from './image-manager';
+export {ImagePicker} from './image-picker';
+export {ListSortControl} from './list-sort-control';
+export {MarkdownEditor} from './markdown-editor';
+export {NewUserPassword} from './new-user-password';
+export {Notification} from './notification';
+export {OptionalInput} from './optional-input';
+export {PageComments} from './page-comments';
+export {PageDisplay} from './page-display';
+export {PageEditor} from './page-editor';
+export {PagePicker} from './page-picker';
+export {PermissionsTable} from './permissions-table';
+export {Pointer} from './pointer';
+export {Popup} from './popup';
+export {SettingAppColorScheme} from './setting-app-color-scheme';
+export {SettingColorPicker} from './setting-color-picker';
+export {SettingHomepageControl} from './setting-homepage-control';
+export {ShelfSort} from './shelf-sort';
export {Shortcuts} from './shortcuts';
export {ShortcutInput} from './shortcut-input';
-export {SortableList} from './sortable-list.js';
-export {SubmitOnChange} from './submit-on-change.js';
-export {Tabs} from './tabs.js';
-export {TagManager} from './tag-manager.js';
-export {TemplateManager} from './template-manager.js';
-export {ToggleSwitch} from './toggle-switch.js';
-export {TriLayout} from './tri-layout.js';
-export {UserSelect} from './user-select.js';
+export {SortableList} from './sortable-list';
+export {SubmitOnChange} from './submit-on-change';
+export {Tabs} from './tabs';
+export {TagManager} from './tag-manager';
+export {TemplateManager} from './template-manager';
+export {ToggleSwitch} from './toggle-switch';
+export {TriLayout} from './tri-layout';
+export {UserSelect} from './user-select';
export {WebhookEvents} from './webhook-events';
-export {WysiwygEditor} from './wysiwyg-editor.js';
+export {WysiwygEditor} from './wysiwyg-editor';
}
handleDividerDrag() {
- this.divider.addEventListener('pointerdown', event => {
+ this.divider.addEventListener('pointerdown', () => {
const wrapRect = this.elem.getBoundingClientRect();
const moveListener = event => {
const xRel = event.pageX - wrapRect.left;
this.displayWrap.style.flexBasis = `${100 - xPct}%`;
this.editor.settings.set('editorWidth', xPct);
};
- const upListener = event => {
+ const upListener = () => {
window.removeEventListener('pointermove', moveListener);
window.removeEventListener('pointerup', upListener);
this.display.style.pointerEvents = null;
deleteComment(commentElem) {
const id = commentElem.getAttribute('comment');
this.showLoading(commentElem.querySelector('[comment-content]'));
- window.$http.delete(`/comment/${id}`).then(resp => {
+ window.$http.delete(`/comment/${id}`).then(() => {
commentElem.parentNode.removeChild(commentElem);
window.$events.success(this.deletedText);
this.updateCount();
import {scrollAndHighlightElement} from '../services/util';
import {Component} from './component';
+function toggleAnchorHighlighting(elementId, shouldHighlight) {
+ DOM.forEach(`a[href="#${elementId}"]`, anchor => {
+ anchor.closest('li').classList.toggle('current-heading', shouldHighlight);
+ });
+}
+
+function headingVisibilityChange(entries) {
+ for (const entry of entries) {
+ const isVisible = (entry.intersectionRatio === 1);
+ toggleAnchorHighlighting(entry.target.id, isVisible);
+ }
+}
+
+function addNavObserver(headings) {
+ // Setup the intersection observer.
+ const intersectOpts = {
+ rootMargin: '0px 0px 0px 0px',
+ threshold: 1.0,
+ };
+ const pageNavObserver = new IntersectionObserver(headingVisibilityChange, intersectOpts);
+
+ // observe each heading
+ for (const heading of headings) {
+ pageNavObserver.observe(heading);
+ }
+}
+
export class PageDisplay extends Component {
setup() {
if (headings.length > 0 && pageNav !== null) {
addNavObserver(headings);
}
-
- function addNavObserver(headings) {
- // Setup the intersection observer.
- const intersectOpts = {
- rootMargin: '0px 0px 0px 0px',
- threshold: 1.0,
- };
- const pageNavObserver = new IntersectionObserver(headingVisibilityChange, intersectOpts);
-
- // observe each heading
- for (const heading of headings) {
- pageNavObserver.observe(heading);
- }
- }
-
- function headingVisibilityChange(entries, observer) {
- for (const entry of entries) {
- const isVisible = (entry.intersectionRatio === 1);
- toggleAnchorHighlighting(entry.target.id, isVisible);
- }
- }
-
- function toggleAnchorHighlighting(elementId, shouldHighlight) {
- DOM.forEach(`a[href="#${elementId}"]`, anchor => {
- anchor.closest('li').classList.toggle('current-heading', shouldHighlight);
- });
- }
}
setupDetailsCodeBlockRefresh() {
window.$events.listen('editor-save-page', this.savePage.bind(this));
// Listen to content changes from the editor
- const onContentChange = () => this.autoSave.pendingChange = true;
+ const onContentChange = () => {
+ this.autoSave.pendingChange = true;
+ };
window.$events.listen('editor-html-change', onContentChange);
window.$events.listen('editor-markdown-change', onContentChange);
setInitialFocus() {
if (this.hasDefaultTitle) {
- return this.titleElem.select();
+ this.titleElem.select();
+ return;
}
window.setTimeout(() => {
try {
const saveKey = `draft-save-fail-${(new Date()).toISOString()}`;
window.localStorage.setItem(saveKey, JSON.stringify(data));
- } catch (err) {}
+ } catch (lsErr) {
+ console.error(lsErr);
+ }
window.$events.emit('error', this.autosaveFailText);
}
try {
response = await window.$http.get(`/ajax/page/${this.pageId}`);
} catch (e) {
- return console.error(e);
+ console.error(e);
+ return;
}
if (this.autoSave.interval) {
import {Component} from './component';
+function toggleElem(elem, show) {
+ elem.style.display = show ? null : 'none';
+}
+
export class PagePicker extends Component {
setup() {
this.selectButton.addEventListener('click', this.showPopup.bind(this));
this.display.parentElement.addEventListener('click', this.showPopup.bind(this));
- this.resetButton.addEventListener('click', event => {
+ this.resetButton.addEventListener('click', () => {
this.setValue('', '');
});
}
}
}
-
-function toggleElem(elem, show) {
- elem.style.display = show ? null : 'none';
-}
setupListeners() {
// Copy on copy button click
- this.button.addEventListener('click', event => {
+ this.button.addEventListener('click', () => {
copyTextToClipboard(this.input.value);
});
});
// Hide pointer when clicking away
- DOM.onEvents(document.body, ['click', 'focus'], event => {
+ DOM.onEvents(document.body, ['click', 'focus'], () => {
if (!this.showing || this.isSelection) return;
this.hidePointer();
});
this.container.addEventListener('click', event => {
if (event.target === this.container && lastMouseDownTarget === this.container) {
- return this.hide();
+ this.hide();
}
});
- onSelect(this.hideButtons, e => this.hide());
+ onSelect(this.hideButtons, () => this.hide());
}
hide(onComplete = null) {
const rgb = this.hexToRgb(hexVal);
const rgbLightVal = `rgba(${[rgb.r, rgb.g, rgb.b, '0.15'].join(',')})`;
- console.log(input.name, lightName, hexVal, rgbLightVal);
const lightColorInput = this.container.querySelector(`input[name="${lightName}"][type="hidden"]`);
lightColorInput.value = rgbLightVal;
}
* @type {Object<string, function(HTMLElement, HTMLElement, HTMLElement)>}
*/
const itemActions = {
- move_up(item, shelfBooksList, allBooksList) {
+ move_up(item) {
const list = item.parentNode;
const index = Array.from(list.children).indexOf(item);
const newIndex = Math.max(index - 1, 0);
list.insertBefore(item, list.children[newIndex] || null);
},
- move_down(item, shelfBooksList, allBooksList) {
+ move_down(item) {
const list = item.parentNode;
const index = Array.from(list.children).indexOf(item);
const newIndex = Math.min(index + 2, list.children.length);
remove(item, shelfBooksList, allBooksList) {
allBooksList.appendChild(item);
},
- add(item, shelfBooksList, allBooksList) {
+ add(item, shelfBooksList) {
shelfBooksList.appendChild(item);
},
};
}
});
- this.bookSearchInput.addEventListener('input', event => {
+ this.bookSearchInput.addEventListener('input', () => {
this.filterBooksByName(this.bookSearchInput.value);
});
const bProp = bookB.dataset[sortProperty].toLowerCase();
if (reverse) {
- return aProp < bProp ? (aProp === bProp ? 0 : 1) : -1;
+ return bProp.localeCompare(aProp);
}
- return aProp < bProp ? (aProp === bProp ? 0 : -1) : 1;
+ return aProp.localeCompare(bProp);
});
for (const book of books) {
window.addEventListener('keydown', event => {
if (event.key === '?') {
- this.hintsShowing ? this.hideHints() : this.showHints();
+ const action = this.hintsShowing ? this.hideHints : this.showHints;
+ action();
}
});
}
});
// Search submit button press
- this.searchButton.addEventListener('click', event => this.performSearch());
+ this.searchButton.addEventListener('click', () => this.performSearch());
// Search cancel button press
- this.searchCancel.addEventListener('click', event => {
+ this.searchCancel.addEventListener('click', () => {
this.searchInput.value = '';
this.performSearch();
});
// Watch layout changes
this.updateLayout();
- window.addEventListener('resize', event => {
+ window.addEventListener('resize', () => {
this.updateLayout();
}, {passive: true});
}
-import DrawIO from '../services/drawio';
+import * as DrawIO from '../services/drawio';
export class Actions {
} else {
window.$events.emit('error', this.editor.config.text.imageUploadError);
}
- console.log(error);
+ console.error(error);
}
// Make the editor full screen
scrollToLine = lineCount;
break;
}
- lineCount++;
+ lineCount += 1;
}
if (scrollToLine === -1) {
* @param {String} end
*/
wrapSelection(start, end) {
- const selectionRange = this.#getSelectionRange();
- const selectionText = this.#getSelectionText(selectionRange);
- if (!selectionText) return this.#wrapLine(start, end);
+ const selectRange = this.#getSelectionRange();
+ const selectionText = this.#getSelectionText(selectRange);
+ if (!selectionText) {
+ this.#wrapLine(start, end);
+ return;
+ }
let newSelectionText = selectionText;
let newRange;
if (selectionText.startsWith(start) && selectionText.endsWith(end)) {
newSelectionText = selectionText.slice(start.length, selectionText.length - end.length);
- newRange = selectionRange.extend(selectionRange.from, selectionRange.to - (start.length + end.length));
+ newRange = selectRange.extend(selectRange.from, selectRange.to - (start.length + end.length));
} else {
newSelectionText = `${start}${selectionText}${end}`;
- newRange = selectionRange.extend(selectionRange.from, selectionRange.to + (start.length + end.length));
+ newRange = selectRange.extend(selectRange.from, selectRange.to + (start.length + end.length));
}
- this.#dispatchChange(selectionRange.from, selectionRange.to, newSelectionText, newRange.anchor, newRange.head);
+ this.#dispatchChange(
+ selectRange.from,
+ selectRange.to,
+ newSelectionText,
+ newRange.anchor,
+ newRange.head,
+ );
}
replaceLineStartForOrderedList() {
const newFormat = formats[newFormatIndex];
const newContent = line.text.replace(matches[0], matches[0].replace(format, newFormat));
const lineDiff = newContent.length - line.text.length;
- this.#dispatchChange(line.from, line.to, newContent, selectionRange.anchor + lineDiff, selectionRange.head + lineDiff);
+ this.#dispatchChange(
+ line.from,
+ line.to,
+ newContent,
+ selectionRange.anchor + lineDiff,
+ selectionRange.head + lineDiff,
+ );
}
}
} catch (err) {
window.$events.emit('error', this.editor.config.text.imageUploadError);
this.#findAndReplaceContent(placeHolderText, '');
- console.log(err);
+ console.error(err);
}
}
*/
#replaceSelection(newContent, cursorOffset = 0, selectionRange = null) {
selectionRange = selectionRange || this.editor.cm.state.selection.main;
- this.#dispatchChange(selectionRange.from, selectionRange.to, newContent, selectionRange.from + cursorOffset);
+ const selectFrom = selectionRange.from + cursorOffset;
+ this.#dispatchChange(selectionRange.from, selectionRange.to, newContent, selectFrom);
this.focus();
}
if (selectFrom) {
tr.selection = {anchor: selectFrom};
+ if (selectTo) {
+ tr.selection.head = selectTo;
+ }
}
this.editor.cm.dispatch(tr);
const onScrollDebounced = debounce(editor.actions.syncDisplayPosition.bind(editor.actions), 100, false);
let syncActive = editor.settings.get('scrollSync');
- editor.settings.onChange('scrollSync', val => syncActive = val);
+ editor.settings.onChange('scrollSync', val => {
+ syncActive = val;
+ });
const domEventHandlers = {
// Handle scroll to sync display view
listenToInputChanges(inputs) {
for (const input of inputs) {
- input.addEventListener('change', event => {
+ input.addEventListener('change', () => {
const name = input.getAttribute('name').replace('md-', '');
this.set(name, input.checked);
});
const shortcuts = {};
// Insert Image shortcut
- shortcuts['Shift-Mod-i'] = cm => editor.actions.insertImage();
+ shortcuts['Shift-Mod-i'] = () => editor.actions.insertImage();
// Save draft
- shortcuts['Mod-s'] = cm => window.$events.emit('editor-save-draft');
+ shortcuts['Mod-s'] = () => window.$events.emit('editor-save-draft');
// Save page
- shortcuts['Mod-Enter'] = cm => window.$events.emit('editor-save-page');
+ shortcuts['Mod-Enter'] = () => window.$events.emit('editor-save-page');
// Show link selector
- shortcuts['Shift-Mod-k'] = cm => editor.actions.showLinkSelector();
+ shortcuts['Shift-Mod-k'] = () => editor.actions.showLinkSelector();
// Insert Link
- shortcuts['Mod-k'] = cm => editor.actions.insertLink();
+ shortcuts['Mod-k'] = () => editor.actions.insertLink();
// FormatShortcuts
- shortcuts['Mod-1'] = cm => editor.actions.replaceLineStart('##');
- shortcuts['Mod-2'] = cm => editor.actions.replaceLineStart('###');
- shortcuts['Mod-3'] = cm => editor.actions.replaceLineStart('####');
- shortcuts['Mod-4'] = cm => editor.actions.replaceLineStart('#####');
- shortcuts['Mod-5'] = cm => editor.actions.replaceLineStart('');
- shortcuts['Mod-d'] = cm => editor.actions.replaceLineStart('');
- shortcuts['Mod-6'] = cm => editor.actions.replaceLineStart('>');
- shortcuts['Mod-q'] = cm => editor.actions.replaceLineStart('>');
- shortcuts['Mod-7'] = cm => editor.actions.wrapSelection('\n```\n', '\n```');
- shortcuts['Mod-8'] = cm => editor.actions.wrapSelection('`', '`');
- shortcuts['Shift-Mod-e'] = cm => editor.actions.wrapSelection('`', '`');
- shortcuts['Mod-9'] = cm => editor.actions.cycleCalloutTypeAtSelection();
- shortcuts['Mod-p'] = cm => editor.actions.replaceLineStart('-');
- shortcuts['Mod-o'] = cm => editor.actions.replaceLineStartForOrderedList();
+ shortcuts['Mod-1'] = () => editor.actions.replaceLineStart('##');
+ shortcuts['Mod-2'] = () => editor.actions.replaceLineStart('###');
+ shortcuts['Mod-3'] = () => editor.actions.replaceLineStart('####');
+ shortcuts['Mod-4'] = () => editor.actions.replaceLineStart('#####');
+ shortcuts['Mod-5'] = () => editor.actions.replaceLineStart('');
+ shortcuts['Mod-d'] = () => editor.actions.replaceLineStart('');
+ shortcuts['Mod-6'] = () => editor.actions.replaceLineStart('>');
+ shortcuts['Mod-q'] = () => editor.actions.replaceLineStart('>');
+ shortcuts['Mod-7'] = () => editor.actions.wrapSelection('\n```\n', '\n```');
+ shortcuts['Mod-8'] = () => editor.actions.wrapSelection('`', '`');
+ shortcuts['Shift-Mod-e'] = () => editor.actions.wrapSelection('`', '`');
+ shortcuts['Mod-9'] = () => editor.actions.cycleCalloutTypeAtSelection();
+ shortcuts['Mod-p'] = () => editor.actions.replaceLineStart('-');
+ shortcuts['Mod-o'] = () => editor.actions.replaceLineStartForOrderedList();
return shortcuts;
}
*/
const animateStylesCleanupMap = new WeakMap();
+/**
+ * Animate the css styles of an element using FLIP animation techniques.
+ * Styles must be an object where the keys are style properties, camelcase, and the values
+ * are an array of two items in the format [initialValue, finalValue]
+ * @param {Element} element
+ * @param {Object} styles
+ * @param {Number} animTime
+ * @param {Function} onComplete
+ */
+function animateStyles(element, styles, animTime = 400, onComplete = null) {
+ const styleNames = Object.keys(styles);
+ for (const style of styleNames) {
+ element.style[style] = styles[style][0];
+ }
+
+ const cleanup = () => {
+ for (const style of styleNames) {
+ element.style[style] = null;
+ }
+ element.style.transition = null;
+ element.removeEventListener('transitionend', cleanup);
+ animateStylesCleanupMap.delete(element);
+ if (onComplete) onComplete();
+ };
+
+ setTimeout(() => {
+ element.style.transition = `all ease-in-out ${animTime}ms`;
+ for (const style of styleNames) {
+ element.style[style] = styles[style][1];
+ }
+
+ element.addEventListener('transitionend', cleanup);
+ animateStylesCleanupMap.set(element, cleanup);
+ }, 15);
+}
+
+/**
+ * Run the active cleanup action for the given element.
+ * @param {Element} element
+ */
+function cleanupExistingElementAnimation(element) {
+ if (animateStylesCleanupMap.has(element)) {
+ const oldCleanup = animateStylesCleanupMap.get(element);
+ oldCleanup();
+ }
+}
+
/**
* Fade in the given element.
* @param {Element} element
animateStyles(element, animStyles, animTime);
};
}
-
-/**
- * Animate the css styles of an element using FLIP animation techniques.
- * Styles must be an object where the keys are style properties, camelcase, and the values
- * are an array of two items in the format [initialValue, finalValue]
- * @param {Element} element
- * @param {Object} styles
- * @param {Number} animTime
- * @param {Function} onComplete
- */
-function animateStyles(element, styles, animTime = 400, onComplete = null) {
- const styleNames = Object.keys(styles);
- for (const style of styleNames) {
- element.style[style] = styles[style][0];
- }
-
- const cleanup = () => {
- for (const style of styleNames) {
- element.style[style] = null;
- }
- element.style.transition = null;
- element.removeEventListener('transitionend', cleanup);
- animateStylesCleanupMap.delete(element);
- if (onComplete) onComplete();
- };
-
- setTimeout(() => {
- element.style.transition = `all ease-in-out ${animTime}ms`;
- for (const style of styleNames) {
- element.style[style] = styles[style][1];
- }
-
- element.addEventListener('transitionend', cleanup);
- animateStylesCleanupMap.set(element, cleanup);
- }, 15);
-}
-
-/**
- * Run the active cleanup action for the given element.
- * @param {Element} element
- */
-function cleanupExistingElementAnimation(element) {
- if (animateStylesCleanupMap.has(element)) {
- const oldCleanup = animateStylesCleanupMap.get(element);
- oldCleanup();
- }
-}
*/
const elementComponentMap = new WeakMap();
-/**
- * Initialize a component instance on the given dom element.
- * @param {String} name
- * @param {Element} element
- */
-function initComponent(name, element) {
- /** @type {Function<Component>|undefined} * */
- const componentModel = componentModelMap[name];
- if (componentModel === undefined) return;
-
- // Create our component instance
- /** @type {Component} * */
- let instance;
- try {
- instance = new componentModel();
- instance.$name = name;
- instance.$el = element;
- const allRefs = parseRefs(name, element);
- instance.$refs = allRefs.refs;
- instance.$manyRefs = allRefs.manyRefs;
- instance.$opts = parseOpts(name, element);
- instance.setup();
- } catch (e) {
- console.error('Failed to create component', e, name, element);
- }
-
- // Add to global listing
- if (typeof components[name] === 'undefined') {
- components[name] = [];
- }
- components[name].push(instance);
-
- // Add to element mapping
- const elComponents = elementComponentMap.get(element) || {};
- elComponents[name] = instance;
- elementComponentMap.set(element, elComponents);
-}
-
/**
* Parse out the element references within the given element
* for the given component name.
/**
* Parse out the element component options.
- * @param {String} name
+ * @param {String} componentName
* @param {Element} element
* @return {Object<String, String>}
*/
-function parseOpts(name, element) {
+function parseOpts(componentName, element) {
const opts = {};
- const prefix = `option:${name}:`;
+ const prefix = `option:${componentName}:`;
for (const {name, value} of element.attributes) {
if (name.startsWith(prefix)) {
const optName = name.replace(prefix, '');
return opts;
}
+/**
+ * Initialize a component instance on the given dom element.
+ * @param {String} name
+ * @param {Element} element
+ */
+function initComponent(name, element) {
+ /** @type {Function<Component>|undefined} * */
+ const ComponentModel = componentModelMap[name];
+ if (ComponentModel === undefined) return;
+
+ // Create our component instance
+ /** @type {Component} * */
+ let instance;
+ try {
+ instance = new ComponentModel();
+ instance.$name = name;
+ instance.$el = element;
+ const allRefs = parseRefs(name, element);
+ instance.$refs = allRefs.refs;
+ instance.$manyRefs = allRefs.manyRefs;
+ instance.$opts = parseOpts(name, element);
+ instance.setup();
+ } catch (e) {
+ console.error('Failed to create component', e, name, element);
+ }
+
+ // Add to global listing
+ if (typeof components[name] === 'undefined') {
+ components[name] = [];
+ }
+ components[name].push(instance);
+
+ // Add to element mapping
+ const elComponents = elementComponentMap.get(element) || {};
+ elComponents[name] = instance;
+ elementComponentMap.set(element, elComponents);
+}
+
/**
* Initialize all components found within the given element.
* @param {Element|Document} parentElement
let onInit; let
onSave;
-/**
- * Show the draw.io editor.
- * @param {String} drawioUrl
- * @param {Function} onInitCallback - Must return a promise with the xml to load for the editor.
- * @param {Function} onSaveCallback - Is called with the drawing data on save.
- */
-function show(drawioUrl, onInitCallback, onSaveCallback) {
- onInit = onInitCallback;
- onSave = onSaveCallback;
-
- iFrame = document.createElement('iframe');
- iFrame.setAttribute('frameborder', '0');
- window.addEventListener('message', drawReceive);
- iFrame.setAttribute('src', drawioUrl);
- iFrame.setAttribute('class', 'fullscreen');
- iFrame.style.backgroundColor = '#FFFFFF';
- document.body.appendChild(iFrame);
- lastApprovedOrigin = (new URL(drawioUrl)).origin;
-}
-
-function close() {
- drawEventClose();
-}
-
-/**
- * Receive and handle a message event from the draw.io window.
- * @param {MessageEvent} event
- */
-function drawReceive(event) {
- if (!event.data || event.data.length < 1) return;
- if (event.origin !== lastApprovedOrigin) return;
-
- const message = JSON.parse(event.data);
- if (message.event === 'init') {
- drawEventInit();
- } else if (message.event === 'exit') {
- drawEventClose();
- } else if (message.event === 'save') {
- drawEventSave(message);
- } else if (message.event === 'export') {
- drawEventExport(message);
- } else if (message.event === 'configure') {
- drawEventConfigure();
- }
+function drawPostMessage(data) {
+ iFrame.contentWindow.postMessage(JSON.stringify(data), lastApprovedOrigin);
}
function drawEventExport(message) {
}
function drawEventClose() {
+ // eslint-disable-next-line no-use-before-define
window.removeEventListener('message', drawReceive);
if (iFrame) document.body.removeChild(iFrame);
}
-function drawPostMessage(data) {
- iFrame.contentWindow.postMessage(JSON.stringify(data), lastApprovedOrigin);
+/**
+ * Receive and handle a message event from the draw.io window.
+ * @param {MessageEvent} event
+ */
+function drawReceive(event) {
+ if (!event.data || event.data.length < 1) return;
+ if (event.origin !== lastApprovedOrigin) return;
+
+ const message = JSON.parse(event.data);
+ if (message.event === 'init') {
+ drawEventInit();
+ } else if (message.event === 'exit') {
+ drawEventClose();
+ } else if (message.event === 'save') {
+ drawEventSave(message);
+ } else if (message.event === 'export') {
+ drawEventExport(message);
+ } else if (message.event === 'configure') {
+ drawEventConfigure();
+ }
+}
+
+/**
+ * Show the draw.io editor.
+ * @param {String} drawioUrl
+ * @param {Function} onInitCallback - Must return a promise with the xml to load for the editor.
+ * @param {Function} onSaveCallback - Is called with the drawing data on save.
+ */
+export function show(drawioUrl, onInitCallback, onSaveCallback) {
+ onInit = onInitCallback;
+ onSave = onSaveCallback;
+
+ iFrame = document.createElement('iframe');
+ iFrame.setAttribute('frameborder', '0');
+ window.addEventListener('message', drawReceive);
+ iFrame.setAttribute('src', drawioUrl);
+ iFrame.setAttribute('class', 'fullscreen');
+ iFrame.style.backgroundColor = '#FFFFFF';
+ document.body.appendChild(iFrame);
+ lastApprovedOrigin = (new URL(drawioUrl)).origin;
}
-async function upload(imageData, pageUploadedToId) {
+export async function upload(imageData, pageUploadedToId) {
const data = {
image: imageData,
uploaded_to: pageUploadedToId,
return resp.data;
}
+export function close() {
+ drawEventClose();
+}
+
/**
* Load an existing image, by fetching it as Base64 from the system.
* @param drawingId
* @returns {Promise<string>}
*/
-async function load(drawingId) {
+export async function load(drawingId) {
try {
const resp = await window.$http.get(window.baseUrl(`/images/drawio/base64/${drawingId}`));
return `data:image/png;base64,${resp.data.content}`;
throw error;
}
}
-
-export default {
- show, close, upload, load,
-};
* @param {String} eventName
* @param {*} eventData
*/
-function emit(eventName, eventData) {
+export function emit(eventName, eventData) {
stack.push({name: eventName, data: eventData});
- if (typeof listeners[eventName] === 'undefined') return this;
- const eventsToStart = listeners[eventName];
- for (let i = 0; i < eventsToStart.length; i++) {
- const event = eventsToStart[i];
- event(eventData);
+
+ const listenersToRun = listeners[eventName] || [];
+ for (const listener of listenersToRun) {
+ listener(eventData);
}
}
* @param {Function} callback
* @returns {Events}
*/
-function listen(eventName, callback) {
+export function listen(eventName, callback) {
if (typeof listeners[eventName] === 'undefined') listeners[eventName] = [];
listeners[eventName].push(callback);
}
* @param {String} eventName
* @param {Object} eventData
*/
-function emitPublic(targetElement, eventName, eventData) {
+export function emitPublic(targetElement, eventName, eventData) {
const event = new CustomEvent(eventName, {
detail: eventData,
bubbles: true,
targetElement.dispatchEvent(event);
}
+/**
+ * Emit a success event with the provided message.
+ * @param {String} message
+ */
+export function success(message) {
+ emit('success', message);
+}
+
+/**
+ * Emit an error event with the provided message.
+ * @param {String} message
+ */
+export function error(message) {
+ emit('error', message);
+}
+
/**
* Notify of standard server-provided validation errors.
- * @param {Object} error
+ * @param {Object} responseErr
*/
-function showValidationErrors(error) {
- if (!error.status) return;
- if (error.status === 422 && error.data) {
- const message = Object.values(error.data).flat().join('\n');
- emit('error', message);
+export function showValidationErrors(responseErr) {
+ if (!responseErr.status) return;
+ if (responseErr.status === 422 && responseErr.data) {
+ const message = Object.values(responseErr.data).flat().join('\n');
+ error(message);
}
}
/**
* Notify standard server-provided error messages.
- * @param {Object} error
+ * @param {Object} responseErr
*/
-function showResponseError(error) {
- if (!error.status) return;
- if (error.status >= 400 && error.data && error.data.message) {
- emit('error', error.data.message);
+export function showResponseError(responseErr) {
+ if (!responseErr.status) return;
+ if (responseErr.status >= 400 && responseErr.data && responseErr.data.message) {
+ error(responseErr.data.message);
}
}
-
-export default {
- emit,
- emitPublic,
- listen,
- success: msg => emit('success', msg),
- error: msg => emit('error', msg),
- showValidationErrors,
- showResponseError,
-};
*/
class Translator {
- /**
- * Create an instance, Passing in the required translations
- * @param translations
- */
- constructor(translations) {
+ constructor() {
this.store = new Map();
this.parseTranslations();
}
}
/**
- * Get a translation, Same format as laravel's 'trans' helper
+ * Get a translation, Same format as Laravel's 'trans' helper
* @param key
* @param replacements
* @returns {*}
}
/**
- * Get pluralised text, Dependant on the given count.
- * Same format at laravel's 'trans_choice' helper.
+ * Get pluralised text, Dependent on the given count.
+ * Same format at Laravel's 'trans_choice' helper.
* @param key
* @param count
* @param replacements
/**
* Parse the given translation and find the correct plural option
- * to use. Similar format at laravel's 'trans_choice' helper.
+ * to use. Similar format at Laravel's 'trans_choice' helper.
* @param {String} translation
* @param {Number} count
* @param {Object} replacements
*/
performReplacements(string, replacements) {
if (!replacements) return string;
- const replaceMatches = string.match(/:([\S]+)/g);
+ const replaceMatches = string.match(/:(\S+)/g);
if (replaceMatches === null) return string;
+ let updatedString = string;
+
replaceMatches.forEach(match => {
const key = match.substring(1);
if (typeof replacements[key] === 'undefined') return;
- string = string.replace(match, replacements[key]);
+ updatedString = updatedString.replace(match, replacements[key]);
});
- return string;
+
+ return updatedString;
}
}
-import DrawIO from '../services/drawio';
+import * as DrawIO from '../services/drawio';
let pageEditor = null;
let currentNode = null;