X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/a6633642232efd164d4708967ab59e498fbff896..refs/pull/4191/head:/resources/js/components/tabs.js diff --git a/resources/js/components/tabs.js b/resources/js/components/tabs.js index 7121d7044..560dc6273 100644 --- a/resources/js/components/tabs.js +++ b/resources/js/components/tabs.js @@ -1,51 +1,49 @@ +import {Component} from './component'; + /** * Tabs - * Works by matching 'tabToggle' with 'tabContent' sections. - * @extends {Component} + * Uses accessible attributes to drive its functionality. + * On tab wrapping element: + * - role=tablist + * On tabs (Should be a button): + * - id + * - role=tab + * - aria-selected=true/false + * - aria-controls= + * On panels: + * - id + * - tabindex=0 + * - role=tabpanel + * - aria-labelledby= + * - hidden (If not shown by default). */ -import {onSelect} from "../services/dom"; - -class Tabs { +export class Tabs extends Component { setup() { - this.tabContentsByName = {}; - this.tabButtonsByName = {}; - this.allContents = []; - this.allButtons = []; + this.container = this.$el; + this.tabs = Array.from(this.container.querySelectorAll('[role="tab"]')); + this.panels = Array.from(this.container.querySelectorAll('[role="tabpanel"]')); - for (const [key, elems] of Object.entries(this.$manyRefs || {})) { - if (key.startsWith('toggle')) { - const cleanKey = key.replace('toggle', '').toLowerCase(); - onSelect(elems, e => this.show(cleanKey)); - this.allButtons.push(...elems); - this.tabButtonsByName[cleanKey] = elems; - } - if (key.startsWith('content')) { - const cleanKey = key.replace('content', '').toLowerCase(); - this.tabContentsByName[cleanKey] = elems; - this.allContents.push(...elems); + this.container.addEventListener('click', event => { + const button = event.target.closest('[role="tab"]'); + if (button) { + this.show(button.getAttribute('aria-controls')); } - } + }); } - show(key) { - this.allContents.forEach(c => { - c.classList.add('hidden'); - c.classList.remove('selected'); - }); - this.allButtons.forEach(b => b.classList.remove('selected')); + show(sectionId) { + for (const panel of this.panels) { + panel.toggleAttribute('hidden', panel.id !== sectionId); + } - const contents = this.tabContentsByName[key] || []; - const buttons = this.tabButtonsByName[key] || []; - if (contents.length > 0) { - contents.forEach(c => { - c.classList.remove('hidden') - c.classList.add('selected') - }); - buttons.forEach(b => b.classList.add('selected')); + for (const tab of this.tabs) { + const tabSection = tab.getAttribute('aria-controls'); + const selected = tabSection === sectionId; + tab.setAttribute('aria-selected', selected ? 'true' : 'false'); } + + this.$emit('change', {showing: sectionId}); } } - -export default Tabs; \ No newline at end of file