Skip to content

Commit 6c978f3

Browse files
committed
Toggling external content by tabs switching
1 parent 9ad4514 commit 6c978f3

File tree

2 files changed

+156
-1
lines changed

2 files changed

+156
-1
lines changed

preview-src/index.adoc

+8
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,14 @@ Tab C::
144144

145145
There you have it.
146146

147+
The module file is generated in ... for [.lang-java]#Java# [.lang-scala]#Scala#
148+
149+
[tabs%sync,sync-group-id=lang]
150+
====
151+
Java:: Java
152+
Scala:: Scala
153+
====
154+
147155
=== Some Code
148156

149157
How about some code?

src/js/vendor/tabs.bundle.js

+148-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,148 @@
1-
require('@asciidoctor/tabs')
1+
// TODO: uncomment after release a new version asciidoctor/tabs
2+
// See https://github.com/asciidoctor/asciidoctor-tabs/pull/68
3+
// require('@asciidoctor/tabs')
4+
5+
/* eslint-disable */
6+
;(function () { /*! Asciidoctor Tabs | Copyright (c) 2018-present Dan Allen | MIT License */
7+
'use strict'
8+
9+
var config = (document.currentScript || {}).dataset || {}
10+
var forEach = Array.prototype.forEach
11+
12+
document.addEventListener('asciidoctor-tabs:toggle', function (event) {
13+
const groupId = event.detail.syncGroupId.replace(/\W/g, '-').toLowerCase()
14+
const id = event.detail.syncId.replace(/\W/g, '-').toLowerCase()
15+
document.querySelectorAll('[class^="' + groupId + '"]').forEach(function (el) {
16+
const hide = !el.classList.contains(groupId + '-' + id)
17+
el.classList[(el.hidden = hide) ? 'add' : 'remove']('is-hidden')
18+
})
19+
})
20+
21+
init(document.querySelectorAll('.tabs'))
22+
23+
function init (tabsBlocks) {
24+
if (!tabsBlocks.length) return
25+
forEach.call(tabsBlocks, function (tabs) {
26+
var syncIds = tabs.classList.contains('is-sync') ? {} : undefined
27+
var tablist = tabs.querySelector('.tablist ul')
28+
if (!tablist) return
29+
tablist.setAttribute('role', 'tablist')
30+
var start
31+
forEach.call(tablist.querySelectorAll('li'), function (tab, idx) {
32+
tab.tabIndex = -1
33+
tab.setAttribute('role', tab.classList.add('tab') || 'tab')
34+
var id, anchor, syncId
35+
if (!(id = tab.id) && (anchor = tab.querySelector('a[id]'))) {
36+
id = tab.id = anchor.parentNode.removeChild(anchor).id
37+
}
38+
var panel = id && tabs.querySelector('.tabpanel[aria-labelledby~="' + id + '"]')
39+
if (!panel) return idx ? undefined : toggleSelected(tab, true) // invalid state
40+
syncIds && (((syncId = tab.textContent.trim()) in syncIds) ? (syncId = undefined) : true) &&
41+
(syncIds[(tab.dataset.syncId = syncId)] = tab)
42+
idx || (syncIds && (start = { tab: tab, panel: panel })) ? toggleHidden(panel, true) : toggleSelected(tab, true)
43+
tab.setAttribute('aria-controls', panel.id)
44+
panel.setAttribute('role', 'tabpanel')
45+
var onClick = syncId === undefined ? activateTab : activateTabSync
46+
tab.addEventListener('click', onClick.bind({ tabs: tabs, tab: tab, panel: panel }))
47+
})
48+
if (!tabs.closest('.tabpanel')) {
49+
forEach.call(tabs.querySelectorAll('.tabpanel table.tableblock'), function (table) {
50+
var container = Object.assign(document.createElement('div'), { className: 'tablecontainer' })
51+
table.parentNode.insertBefore(container, table).appendChild(table)
52+
})
53+
}
54+
if (start) {
55+
var syncGroupId
56+
for (var i = 0, lst = tabs.classList, len = lst.length, className; i !== len; i++) {
57+
if (!(className = lst.item(i)).startsWith('data-sync-group-id=')) continue
58+
tabs.dataset.syncGroupId = syncGroupId = lst.remove(className) || className.slice(19).replace(/\u00a0/g, ' ')
59+
break
60+
}
61+
if (syncGroupId === undefined) tabs.dataset.syncGroupId = syncGroupId = Object.keys(syncIds).sort().join('|')
62+
var preferredSyncId = 'syncStorageKey' in config &&
63+
window[(config.syncStorageScope || 'local') + 'Storage'].getItem(config.syncStorageKey + '-' + syncGroupId)
64+
var tab = preferredSyncId && syncIds[preferredSyncId]
65+
tab && Object.assign(start, { tab: tab, panel: document.getElementById(tab.getAttribute('aria-controls')) })
66+
toggleSelected(start.tab, true) || toggleHidden(start.panel, false)
67+
document.dispatchEvent(new CustomEvent('asciidoctor-tabs:toggle', {
68+
detail: { syncGroupId: tabs.dataset.syncGroupId, syncId: start.tab.dataset.syncId }
69+
}))
70+
}
71+
})
72+
onHashChange()
73+
toggleClassOnEach(tabsBlocks, 'is-loading', 'remove')
74+
window.setTimeout(toggleClassOnEach.bind(null, tabsBlocks, 'is-loaded', 'add'), 0)
75+
window.addEventListener('hashchange', onHashChange)
76+
}
77+
78+
function activateTab (e) {
79+
var tab = this.tab
80+
var tabs = this.tabs || (this.tabs = tab.closest('.tabs'))
81+
var panel = this.panel || (this.panel = document.getElementById(tab.getAttribute('aria-controls')))
82+
querySelectorWithSiblings(tabs, '.tablist .tab', 'tab').forEach(function (el) {
83+
toggleSelected(el, el === tab)
84+
})
85+
querySelectorWithSiblings(tabs, '.tabpanel', 'tabpanel').forEach(function (el) {
86+
toggleHidden(el, el !== panel)
87+
})
88+
if (!this.isSync && 'syncStorageKey' in config && 'syncGroupId' in tabs.dataset) {
89+
var storageKey = config.syncStorageKey + '-' + tabs.dataset.syncGroupId
90+
window[(config.syncStorageScope || 'local') + 'Storage'].setItem(storageKey, tab.dataset.syncId)
91+
}
92+
if (!e) return
93+
var loc = window.location
94+
var hashIdx = loc.hash ? loc.href.indexOf('#') : -1
95+
if (~hashIdx) window.history.replaceState(null, '', loc.href.slice(0, hashIdx))
96+
e.preventDefault()
97+
}
98+
99+
function activateTabSync (e) {
100+
activateTab.call(this, e)
101+
var thisTabs = this.tabs
102+
var thisTab = this.tab
103+
var initialY = thisTabs.getBoundingClientRect().y
104+
forEach.call(document.querySelectorAll('.tabs'), function (tabs) {
105+
if (tabs === thisTabs || tabs.dataset.syncGroupId !== thisTabs.dataset.syncGroupId) return
106+
querySelectorWithSiblings(tabs, '.tablist .tab', 'tab').forEach(function (tab) {
107+
if (tab.dataset.syncId === thisTab.dataset.syncId) activateTab.call({ tabs: tabs, tab: tab, isSync: true })
108+
})
109+
})
110+
var shiftedBy = thisTabs.getBoundingClientRect().y - initialY
111+
if (shiftedBy && (shiftedBy = Math.round(shiftedBy))) window.scrollBy({ top: shiftedBy, behavior: 'instant' })
112+
document.dispatchEvent(new CustomEvent('asciidoctor-tabs:toggle', {
113+
detail: { syncGroupId: thisTabs.dataset.syncGroupId, syncId: thisTab.dataset.syncId }
114+
}))
115+
}
116+
117+
function querySelectorWithSiblings (scope, selector, siblingClass) {
118+
var el = scope.querySelector(selector)
119+
if (!el) return []
120+
var result = [el]
121+
while ((el = el.nextElementSibling) && el.classList.contains(siblingClass)) result.push(el)
122+
return result
123+
}
124+
125+
function toggleClassOnEach (elements, className, method) {
126+
forEach.call(elements, function (el) {
127+
el.classList[method](className)
128+
})
129+
}
130+
131+
function toggleHidden (el, state) {
132+
el.classList[(el.hidden = state) ? 'add' : 'remove']('is-hidden')
133+
}
134+
135+
function toggleSelected (el, state) {
136+
el.setAttribute('aria-selected', '' + state)
137+
el.classList[state ? 'add' : 'remove']('is-selected')
138+
el.tabIndex = state ? 0 : -1
139+
}
140+
141+
function onHashChange () {
142+
var id = window.location.hash.slice(1)
143+
if (!id) return
144+
var tab = document.getElementById(~id.indexOf('%') ? decodeURIComponent(id) : id)
145+
if (!(tab && tab.classList.contains('tab'))) return
146+
'syncId' in tab.dataset ? activateTabSync.call({ tab: tab }) : activateTab.call({ tab: tab })
147+
}
148+
})()

0 commit comments

Comments
 (0)