X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/a6633642232efd164d4708967ab59e498fbff896..refs/pull/4673/head:/resources/js/components/index.js diff --git a/resources/js/components/index.js b/resources/js/components/index.js index 91ccdaf3a..a56f18a5a 100644 --- a/resources/js/components/index.js +++ b/resources/js/components/index.js @@ -1,268 +1,60 @@ -import addRemoveRows from "./add-remove-rows.js" -import ajaxDeleteRow from "./ajax-delete-row.js" -import ajaxForm from "./ajax-form.js" -import attachments from "./attachments.js" -import autoSuggest from "./auto-suggest.js" -import backToTop from "./back-to-top.js" -import bookSort from "./book-sort.js" -import chapterToggle from "./chapter-toggle.js" -import codeEditor from "./code-editor.js" -import codeHighlighter from "./code-highlighter.js" -import collapsible from "./collapsible.js" -import customCheckbox from "./custom-checkbox.js" -import detailsHighlighter from "./details-highlighter.js" -import dropdown from "./dropdown.js" -import dropdownSearch from "./dropdown-search.js" -import dropzone from "./dropzone.js" -import editorToolbox from "./editor-toolbox.js" -import entityPermissionsEditor from "./entity-permissions-editor.js" -import entitySearch from "./entity-search.js" -import entitySelector from "./entity-selector.js" -import entitySelectorPopup from "./entity-selector-popup.js" -import eventEmitSelect from "./event-emit-select.js" -import expandToggle from "./expand-toggle.js" -import headerMobileToggle from "./header-mobile-toggle.js" -import homepageControl from "./homepage-control.js" -import imageManager from "./image-manager.js" -import imagePicker from "./image-picker.js" -import index from "./index.js" -import listSortControl from "./list-sort-control.js" -import markdownEditor from "./markdown-editor.js" -import newUserPassword from "./new-user-password.js" -import notification from "./notification.js" -import optionalInput from "./optional-input.js" -import pageComments from "./page-comments.js" -import pageDisplay from "./page-display.js" -import pageEditor from "./page-editor.js" -import pagePicker from "./page-picker.js" -import permissionsTable from "./permissions-table.js" -import popup from "./popup.js" -import settingAppColorPicker from "./setting-app-color-picker.js" -import settingColorPicker from "./setting-color-picker.js" -import shelfSort from "./shelf-sort.js" -import sidebar from "./sidebar.js" -import sortableList from "./sortable-list.js" -import submitOnChange from "./submit-on-change.js" -import tabs from "./tabs.js" -import tagManager from "./tag-manager.js" -import templateManager from "./template-manager.js" -import toggleSwitch from "./toggle-switch.js" -import triLayout from "./tri-layout.js" -import userSelect from "./user-select.js" -import wysiwygEditor from "./wysiwyg-editor.js" - -const componentMapping = { - "add-remove-rows": addRemoveRows, - "ajax-delete-row": ajaxDeleteRow, - "ajax-form": ajaxForm, - "attachments": attachments, - "auto-suggest": autoSuggest, - "back-to-top": backToTop, - "book-sort": bookSort, - "chapter-toggle": chapterToggle, - "code-editor": codeEditor, - "code-highlighter": codeHighlighter, - "collapsible": collapsible, - "custom-checkbox": customCheckbox, - "details-highlighter": detailsHighlighter, - "dropdown": dropdown, - "dropdown-search": dropdownSearch, - "dropzone": dropzone, - "editor-toolbox": editorToolbox, - "entity-permissions-editor": entityPermissionsEditor, - "entity-search": entitySearch, - "entity-selector": entitySelector, - "entity-selector-popup": entitySelectorPopup, - "event-emit-select": eventEmitSelect, - "expand-toggle": expandToggle, - "header-mobile-toggle": headerMobileToggle, - "homepage-control": homepageControl, - "image-manager": imageManager, - "image-picker": imagePicker, - "index": index, - "list-sort-control": listSortControl, - "markdown-editor": markdownEditor, - "new-user-password": newUserPassword, - "notification": notification, - "optional-input": optionalInput, - "page-comments": pageComments, - "page-display": pageDisplay, - "page-editor": pageEditor, - "page-picker": pagePicker, - "permissions-table": permissionsTable, - "popup": popup, - "setting-app-color-picker": settingAppColorPicker, - "setting-color-picker": settingColorPicker, - "shelf-sort": shelfSort, - "sidebar": sidebar, - "sortable-list": sortableList, - "submit-on-change": submitOnChange, - "tabs": tabs, - "tag-manager": tagManager, - "template-manager": templateManager, - "toggle-switch": toggleSwitch, - "tri-layout": triLayout, - "user-select": userSelect, - "wysiwyg-editor": wysiwygEditor, -}; - -window.components = {}; - -/** - * Initialize components of the given name within the given element. - * @param {String} componentName - * @param {HTMLElement|Document} parentElement - */ -function searchForComponentInParent(componentName, parentElement) { - const elems = parentElement.querySelectorAll(`[${componentName}]`); - for (let j = 0, jLen = elems.length; j < jLen; j++) { - initComponent(componentName, elems[j]); - } -} - -/** - * Initialize a component instance on the given dom element. - * @param {String} name - * @param {Element} element - */ -function initComponent(name, element) { - const componentModel = componentMapping[name]; - if (componentModel === undefined) return; - - // Create our component instance - let instance; - try { - instance = new componentModel(element); - instance.$el = element; - const allRefs = parseRefs(name, element); - instance.$refs = allRefs.refs; - instance.$manyRefs = allRefs.manyRefs; - instance.$opts = parseOpts(name, element); - instance.$emit = (eventName, data = {}) => { - data.from = instance; - const event = new CustomEvent(`${name}-${eventName}`, { - bubbles: true, - detail: data - }); - instance.$el.dispatchEvent(event); - }; - if (typeof instance.setup === 'function') { - instance.setup(); - } - } catch (e) { - console.error('Failed to create component', e, name, element); - } - - - // Add to global listing - if (typeof window.components[name] === "undefined") { - window.components[name] = []; - } - window.components[name].push(instance); - - // Add to element listing - if (typeof element.components === 'undefined') { - element.components = {}; - } - element.components[name] = instance; -} - -/** - * Parse out the element references within the given element - * for the given component name. - * @param {String} name - * @param {Element} element - */ -function parseRefs(name, element) { - const refs = {}; - const manyRefs = {}; - - const prefix = `${name}@` - const selector = `[refs*="${prefix}"]`; - const refElems = [...element.querySelectorAll(selector)]; - if (element.matches(selector)) { - refElems.push(element); - } - - for (const el of refElems) { - const refNames = el.getAttribute('refs') - .split(' ') - .filter(str => str.startsWith(prefix)) - .map(str => str.replace(prefix, '')) - .map(kebabToCamel); - for (const ref of refNames) { - refs[ref] = el; - if (typeof manyRefs[ref] === 'undefined') { - manyRefs[ref] = []; - } - manyRefs[ref].push(el); - } - } - return {refs, manyRefs}; -} - -/** - * Parse out the element component options. - * @param {String} name - * @param {Element} element - * @return {Object} - */ -function parseOpts(name, element) { - const opts = {}; - const prefix = `option:${name}:`; - for (const {name, value} of element.attributes) { - if (name.startsWith(prefix)) { - const optName = name.replace(prefix, ''); - opts[kebabToCamel(optName)] = value || ''; - } - } - return opts; -} - -/** - * Convert a kebab-case string to camelCase - * @param {String} kebab - * @returns {string} - */ -function kebabToCamel(kebab) { - const ucFirst = (word) => word.slice(0,1).toUpperCase() + word.slice(1); - const words = kebab.split('-'); - return words[0] + words.slice(1).map(ucFirst).join(''); -} - -/** - * Initialize all components found within the given element. - * @param parentElement - */ -function initAll(parentElement) { - if (typeof parentElement === 'undefined') parentElement = document; - - // Old attribute system - for (const componentName of Object.keys(componentMapping)) { - searchForComponentInParent(componentName, parentElement); - } - - // New component system - const componentElems = parentElement.querySelectorAll(`[component],[components]`); - - for (const el of componentElems) { - const componentNames = `${el.getAttribute('component') || ''} ${(el.getAttribute('components'))}`.toLowerCase().split(' ').filter(Boolean); - for (const name of componentNames) { - initComponent(name, el); - } - } -} - -window.components.init = initAll; -window.components.first = (name) => (window.components[name] || [null])[0]; - -export default initAll; - -/** - * @typedef Component - * @property {HTMLElement} $el - * @property {Object} $refs - * @property {Object} $manyRefs - * @property {Object} $opts - * @property {function(string, Object)} $emit - */ \ No newline at end of file +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'; +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'; +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 {PageComment} from './page-comment'; +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'; +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';