asciidoctor-tabs 1.0.0.alpha.4 → 1.0.0.alpha.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e968b72b74144aad60adceb6290712b43017a61b74cc80c73793f474473e59c3
4
- data.tar.gz: c7a33865929a61775548be25bda28627c6d9687e68e5d498134d3d87a4eef82b
3
+ metadata.gz: fd23b52dcb671b18e2fc149ff7c4c0f131acc7b36c5a83df0003c22cc341d8cd
4
+ data.tar.gz: 502e57c0df6a007731a21dce2f382f54ea3e940c6548e914e91aab25d233a995
5
5
  SHA512:
6
- metadata.gz: afdc6a70cec6b9a9519a9f8d72a29e234099ab3b58ed0cceabdcfff3a14574ad905214af88b6c32ffa527994607d30d3ed66403c22f4c60442cd318fd2f9dc7c
7
- data.tar.gz: d09843fadb14ddee7d2fa5baf42e0125faeebe6342f7428175100ad7d0401cb6d8693045d51dfe53225e637849cefd15085ca7c7d52ec94f847d3949fc31e2a4
6
+ metadata.gz: 41ddf35603690caa50d3685eb398ebbfd65ecc13630827731ec11493667a2bcd4db8616e530ae11cb8f05fa450d258b9e734ad4ee10fbe1bcaaf1c256ee681e7
7
+ data.tar.gz: ac3f2b5a3d44a8209436955dd5ebb74eff9e2bfbc0f107e572488859de78cb133817db3c5362c09198aee71b9381dfa56646e036ebd885b5cf05231b23231a7b
data/CHANGELOG.adoc CHANGED
@@ -4,6 +4,44 @@
4
4
  This document provides a curated view of the changes to Asciidoctor Tabs per release.
5
5
  For a detailed view of what has changed, refer to the {url-repo}/commits/main[commit history] on GitHub.
6
6
 
7
+ == 1.0.0-alpha.6 (2022-11-16) - @mojavelinux
8
+
9
+ === Added
10
+
11
+ * Honor title on tabs block; apply normal subs to it (#26)
12
+ * Clear location hash (URL fragment) when a tab is clicked (#24)
13
+ * Register ref for each tab so its ID can be used as target of xref (#24)
14
+ * Activate tab when selected from an internal xref (#24)
15
+
16
+ === Fixed
17
+
18
+ * Decode fragment from URL so it can be matched against tab ID (#27)
19
+
20
+ === Details
21
+
22
+ {url-repo}/releases/tag/v1.0.0-alpha.6[git tag] | {url-repo}/compare/v1.0.0-alpha.5\...v1.0.0-alpha.6[full diff]
23
+
24
+ == 1.0.0-alpha.5 (2022-10-23) - @mojavelinux
25
+
26
+ === Added
27
+
28
+ * Link to stylesheet (style) and script (behavior) if `linkcss` attribute is set on document (#7)
29
+ * Honor safe mode settings (don't read files if safe mode is secure) (#7)
30
+
31
+ === Changed
32
+
33
+ * Rename Docinfo::Styles class to Docinfo::Style (#22)
34
+ * Add smoke test for npm package (#19)
35
+
36
+ === Fixed
37
+
38
+ * Prevent dlist ref from being registered again to avoid warning when filetype is not html (#21)
39
+ * Restore missing default style and behavior in JavaScript version by mapping data dir to dist folder in npm package (#18)
40
+
41
+ === Details
42
+
43
+ {url-repo}/releases/tag/v1.0.0-alpha.5[git tag] | {url-repo}/compare/v1.0.0-alpha.4\...v1.0.0-alpha.5[full diff]
44
+
7
45
  == 1.0.0-alpha.4 (2022-10-08) - @mojavelinux
8
46
 
9
47
  === Added
data/README.adoc CHANGED
@@ -1,6 +1,6 @@
1
1
  = Asciidoctor Tabs
2
2
  Dan Allen <https://github.com/mojavelinux[@mojavelinux]>
3
- v1.0.0-alpha.4, 2022-10-08
3
+ v1.0.0-alpha.6, 2022-11-16
4
4
  :idprefix:
5
5
  :idseparator: -
6
6
  ifndef::env-github[:icons: font]
@@ -10,13 +10,20 @@ ifdef::env-github[]
10
10
  endif::[]
11
11
 
12
12
  An Asciidoctor extension that adds a tabs block to the AsciiDoc syntax.
13
- Each set of tabs (a "tabset") is constructed from a dlist enclosed in an example block marked with the tabs style.
14
13
 
15
- NOTE: This extension is intended to be used with HTML backends (e.g., `html`).
16
- For other backends (i.e., filetype is not html), the example block enclosure will be taken away and the dlist will be converted normally.
14
+ NOTE: This extension is intended to be used with HTML backends (e.g., `html5`).
15
+ For all other backends (i.e., the filetype is not html), the custom block enclosure is taken away and its contents (a dlist) is converted normally.
17
16
 
18
17
  TIP: This extension is also published as an npm package named `@asciidoctor/tabs` for use with Asciidoctor.js (and thus Antora).
19
18
 
19
+ == Overview
20
+
21
+ Each set of tabs (a "`tabset`") is constructed from a description list (dlist) enclosed in an example block marked with the tabs style (i.e., `[tab]`).
22
+ The tabbed interface that this block produces can help to organize information by code language, operating system, or product variant.
23
+
24
+ The benefit of organizing information in this way is that it condenses the use of vertical space by only showing what's relevant to the reader (and thus hiding information that's irrelevant or redundant).
25
+ The result is that readers enjoy a better user experience when reading your documentation.
26
+
20
27
  == Install
21
28
 
22
29
  === Using gem command
@@ -35,10 +42,10 @@ source 'https://rubygems.org'
35
42
  gem 'asciidoctor-tabs'
36
43
 
37
44
  # or use the code directlly from GitHub
38
- # gem 'asciidoctor-tabs', github: 'asciidoctor/asciidoctor-pdf'
45
+ # gem 'asciidoctor-tabs', github: 'asciidoctor/asciidoctor-tabs'
39
46
  ----
40
47
 
41
- Then configure Bundler to install gems locally (optional):
48
+ Then optionally configure Bundler to install gems locally:
42
49
 
43
50
  $ bundle config --local path .bundle/gems
44
51
 
@@ -48,12 +55,7 @@ Then use Bundler to install the gem:
48
55
 
49
56
  == Syntax
50
57
 
51
- A tabset is defined using a dlist enclosed in an example block marked with the tabs style.
52
- Each item in the dlist becomes a separate tab.
53
- The term in the dlist item is used as the tab's label.
54
- The description in the dlist item is used for the contents of the tab.
55
- The contents can be defined as primary text, attached blocks, or blocks enclosed in an attached open block.
56
- If the blocks are enclosed in an attached open block, the open block enclosure itself will be discarded.
58
+ A tabset is defined using a description list (dlist) enclosed in an example block marked with the tabs style.
57
59
 
58
60
  .document-with-tabs.adoc
59
61
  [,asciidoc]
@@ -76,6 +78,28 @@ Contains more than one block.
76
78
  ====
77
79
  ----
78
80
 
81
+ The tabbed content is modeled as a dlist.
82
+ Each item in the dlist becomes a separate tab.
83
+ The term is used as the tab's label and the description is used as the tab's contents.
84
+ The contents can be defined as primary text, attached blocks, or both.
85
+ If the attached blocks are themselves enclosed in a single open block, the open block enclosure itself is discarded upon conversion.
86
+
87
+ You may decide to extend the block delimiter length instead of using the typical 4 characters to avoid conflicts with any example blocks inside the tab block (or just as a manner of style).
88
+
89
+ [,asciidoc]
90
+ ----
91
+ [tabs]
92
+ ======
93
+ Tab A::
94
+ +
95
+ ====
96
+ Example block in Tab A.
97
+ ====
98
+
99
+ Tab B:: Just text.
100
+ ======
101
+ ----
102
+
79
103
  == Usage
80
104
 
81
105
  === CLI
@@ -83,11 +107,12 @@ Contains more than one block.
83
107
  $ asciidoctor -r asciidoctor-tabs document-with-tabs.adoc
84
108
 
85
109
  You can specify an alternate stylesheet for tabs using the `tabs-stylesheet` document attribute.
86
- The value of this attribute is handled in the same way as the built-in `stylesheet` document attribute.
87
- A relative path is resolved starting from the value of the `stylesdir` document attribute, which defaults to the directory of the document.
88
110
 
89
111
  $ asciidoctor -r asciidoctor-tabs -a tabs-stylesheet=my-tabs.css document-with-tabs.adoc
90
112
 
113
+ The value of the `tabs-stylesheet` attribute is handled in the same way as the built-in `stylesheet` document attribute.
114
+ A relative path is resolved starting from the value of the `stylesdir` document attribute, which defaults to the directory of the document.
115
+
91
116
  === API
92
117
 
93
118
  There are two ways to use the extension with the Asciidoctor API.
@@ -116,13 +141,35 @@ Asciidoctor::Tabs::Extensions.register registry
116
141
  Asciidoctor.convert_file 'document-with-tabs.adoc', extension_registry: registry, safe: :safe
117
142
  ----
118
143
 
119
- If you're not using other scoped extensions, you can pass in the extensions group without creating a registry instance:
144
+ If you're not using other scoped extensions, you can pass in the extensions group without first creating a registry instance:
120
145
 
121
146
  [,js]
122
147
  ----
123
148
  Asciidoctor.convert_file 'document-with-tabs.adoc', extensions: Asciidoctor::Tabs::Extensions.group, safe: :safe
124
149
  ----
125
150
 
151
+ == How it Works
152
+
153
+ This extension works by transforming the dlist inside the example block into a tabbed interface.
154
+ The example block enclosure is discarded.
155
+ The tabbed interface is supported by a stylesheet (style) and script (behavior) that are added to the HTML document by this extension.
156
+ (These assets can be found in the [.path]_data_ folder of the gem).
157
+
158
+ NOTE: The stylesheet and script are only added when producing a standalone document.
159
+ The stylesheet is added to the end of the `<head>` tag and the script added to the end of the `<body>` tag.
160
+ If the `linkcss` attribute is set by the API, the CLI, the document, or the safe mode, the HTML links to these assets.
161
+ Otherwise, the contents of these assets are embedded into the HTML.
162
+
163
+ The tabbed interface consists of two output elements.
164
+ The first element contains an unordered list of all the tab labels in document order.
165
+ The second element contains all the tab panes.
166
+ The labels and panes are correlated through the use of a unique ID.
167
+ Each tab is assigned an `id` attribute and each pane is assigned an `aria-labelledby` attribute that references the corresponding ID.
168
+ The added stylesheet sets up the appearance of the tabbed interface and the added script supports the interaction (i.e., tab selection).
169
+
170
+ A tab can be selected when the page loads using a URL fragment (e.g., `#id-of-tab-here`).
171
+ Otherwise, the first tab is selected when the page loads.
172
+
126
173
  == Authors
127
174
 
128
175
  Asciidoctor Tabs was written by Dan Allen of OpenDevise Inc. and contributed to the Asciidoctor project.
data/data/js/tabs.js CHANGED
@@ -2,8 +2,11 @@
2
2
  ;(function () {
3
3
  'use strict'
4
4
 
5
- var hash = window.location.hash
6
- find('.tabset').forEach(function (tabset) {
5
+ var tabsets = find('.tabset')
6
+ if (!tabsets.length) return
7
+ var fragment = decodeFragment(window.location.hash)
8
+
9
+ tabsets.forEach(function (tabset) {
7
10
  var active
8
11
  var tabs = tabset.querySelector('.tabs')
9
12
  if (tabs) {
@@ -14,7 +17,7 @@
14
17
  var pane = tabset.querySelector('.tab-pane[aria-labelledby~="' + id + '"]')
15
18
  if (!pane) return
16
19
  if (!idx) first = { tab: tab, pane: pane }
17
- if (!active && hash === '#' + id && (active = true)) {
20
+ if (!active && fragment === id && (active = true)) {
18
21
  tab.classList.add('is-active')
19
22
  if (pane) pane.classList.add('is-active')
20
23
  } else if (!idx) {
@@ -31,15 +34,36 @@
31
34
  tabset.classList.remove('is-loading')
32
35
  })
33
36
 
37
+ tabsets = undefined
38
+ window.addEventListener('hashchange', onHashChange)
39
+
34
40
  function activateTab (e) {
35
41
  var tab = this.tab
36
42
  var pane = this.pane
37
43
  find('.tabs li, .tab-pane', this.tabset).forEach(function (it) {
38
44
  it === tab || it === pane ? it.classList.add('is-active') : it.classList.remove('is-active')
39
45
  })
46
+ if (!e) return
47
+ var hashIdx = window.location.hash ? window.location.href.indexOf('#') : -1
48
+ if (~hashIdx) window.history.replaceState(null, '', window.location.href.slice(0, hashIdx))
40
49
  e.preventDefault()
41
50
  }
42
51
 
52
+ function decodeFragment (hash) {
53
+ return hash && (~hash.indexOf('%') ? decodeURIComponent(hash.slice(1)) : hash.slice(1))
54
+ }
55
+
56
+ function onHashChange () {
57
+ var id = decodeFragment(window.location.hash)
58
+ if (!id) return
59
+ var tab = document.getElementById(id)
60
+ if (!(tab && document.querySelector('.tabset .tabs [id="' + id + '"]'))) return
61
+ if (tab.tagName === 'A') tab = tab.parentNode
62
+ var tabset = tab.closest('.tabset')
63
+ var pane = tabset.querySelector('.tab-pane[aria-labelledby~="' + id + '"]')
64
+ activateTab.call({ tabset: tabset, tab: tab, pane: pane })
65
+ }
66
+
43
67
  function find (selector, from) {
44
68
  return Array.prototype.slice.call((from || document).querySelectorAll(selector))
45
69
  }
@@ -11,36 +11,39 @@ module Asciidoctor
11
11
  children = (parse_content block, reader).blocks
12
12
  return block unless children.size == 1 && (source_tabs = children[0]).context == :dlist && source_tabs.items?
13
13
  unless (doc = parent.document).attr? 'filetype', 'html'
14
- source_tabs.id ||= attrs['id']
15
- (reftext = attrs['reftext']) && (source_tabs.set_attr 'reftext', reftext) unless source_tabs.attr? 'reftext'
16
- return source_tabs
14
+ (id = attrs['id']) && (doc.register :refs, [(source_tabs.id = id), source_tabs]) unless source_tabs.id
15
+ (reftext = attrs['reftext']) && (source_tabs.set_attr 'reftext', reftext) unless source_tabs.reftext?
16
+ parent << source_tabs
17
+ return
17
18
  end
18
19
  tabset_number = doc.counter 'tabset-number'
19
- id = attrs['id'] ||
20
- %(#{doc.attributes['idprefix'] || '_'}tabset#{doc.attributes['idseparator'] || '_'}#{tabset_number})
21
- parent << (create_html_fragment parent, %(<div id="#{id}" class="tabset is-loading">))
20
+ tabs_id = attrs['id'] || (generate_id %(tabset #{tabset_number}), doc)
21
+ parent << (create_html_fragment parent, %(<div id="#{tabs_id}" class="tabset is-loading">))
22
+ if (title = attrs['title'])
23
+ parent << (create_html_fragment parent, %(<div class="title">#{parent.apply_subs title}</div>))
24
+ end
22
25
  (tabs = create_list parent, :ulist).add_role 'tabs'
23
26
  panes = {}
24
27
  set_id_on_tab = (doc.backend == 'html5') || (list_item_supports_id? doc)
25
28
  source_tabs.items.each do |labels, content|
26
29
  tab_ids = labels.map do |tab|
27
30
  tabs << tab
28
- tab_id = generate_id tab.text, id, doc
29
- set_id_on_tab ? (tab.id = tab_id) : (tab.text = %([[#{tab_id}]]#{tab.instance_variable_get :@text}))
31
+ tab_id = generate_id tab.text, doc, tabs_id
32
+ tab_source_text = tab.instance_variable_get :@text
33
+ set_id_on_tab ? (tab.id = tab_id) : (tab.text = %([[#{tab_id}]]#{tab_source_text}))
34
+ (doc.register :refs, [tab_id, tab]).set_attr 'reftext', tab_source_text
30
35
  tab_id
31
36
  end
32
37
  if content
33
- text = create_paragraph parent, (content.instance_variable_get :@text), nil if content.text?
38
+ tab_blocks = content.text? ? [(create_paragraph parent, (content.instance_variable_get :@text), nil)] : []
34
39
  if content.blocks?
35
40
  if (block0 = (blocks = content.blocks)[0]).context == :open && blocks.size == 1 && block0.blocks?
36
41
  blocks = block0.blocks
37
42
  end
38
- blocks.unshift text if text
39
- elsif text
40
- blocks = [text]
43
+ tab_blocks.push(*blocks)
41
44
  end
42
45
  end
43
- panes[tab_ids] = blocks || []
46
+ panes[tab_ids] = tab_blocks || []
44
47
  end
45
48
  parent << tabs
46
49
  parent << (create_html_fragment parent, '<div class="content">')
@@ -50,7 +53,7 @@ module Asciidoctor
50
53
  parent << (create_html_fragment parent, '</div>')
51
54
  end
52
55
  parent << (create_html_fragment parent, '</div>')
53
- create_html_fragment parent, '</div>', 'id' => id
56
+ create_html_fragment parent, '</div>', 'id' => tabs_id
54
57
  end
55
58
 
56
59
  private
@@ -59,12 +62,14 @@ module Asciidoctor
59
62
  create_block parent, :pass, html, attributes
60
63
  end
61
64
 
62
- def generate_id str, base_id, doc
63
- restore_idprefix = (attrs = doc.attributes)['idprefix']
64
- attrs['idprefix'] = %(#{base_id}#{attrs['idseparator'] || '_'})
65
+ def generate_id str, doc, base_id = nil
66
+ if base_id
67
+ restore_idprefix = (attrs = doc.attributes)['idprefix']
68
+ attrs['idprefix'] = %(#{base_id}#{attrs['idseparator'] || '_'})
69
+ end
65
70
  ::Asciidoctor::Section.generate_id str, doc
66
71
  ensure
67
- restore_idprefix ? (attrs['idprefix'] = restore_idprefix) : (attrs.delete 'idprefix')
72
+ restore_idprefix ? (attrs['idprefix'] = restore_idprefix) : (attrs.delete 'idprefix') if base_id
68
73
  end
69
74
 
70
75
  def list_item_supports_id? doc
@@ -4,12 +4,12 @@ module Asciidoctor
4
4
  module Tabs
5
5
  module Docinfo
6
6
  if RUBY_ENGINE == 'opal'
7
- DATA_DIR = ::File.absolute_path '../data', %x(__dirname)
7
+ DATA_DIR = ::File.absolute_path '../dist', %x(__dirname)
8
8
  else
9
9
  DATA_DIR = ::File.join (::File.absolute_path '../../..', __dir__), 'data'
10
10
  end
11
11
 
12
- class Styles < ::Asciidoctor::Extensions::DocinfoProcessor
12
+ class Style < ::Asciidoctor::Extensions::DocinfoProcessor
13
13
  use_dsl
14
14
  at_location :head
15
15
 
@@ -17,10 +17,14 @@ module Asciidoctor
17
17
 
18
18
  def process doc
19
19
  return unless (path = doc.attr 'tabs-stylesheet')
20
- return unless (styles = path.empty? ?
21
- (doc.read_asset DEFAULT_STYLESHEET_FILE) :
22
- (doc.read_contents path, start: (doc.attr 'stylesdir'), warn_on_failure: true, label: 'tabs stylesheet'))
23
- %(<style>\n#{styles.chomp}\n</style>)
20
+ if doc.attr? 'linkcss'
21
+ href = doc.normalize_web_path (path.empty? ? 'asciidoctor-tabs.css' : path), (doc.attr 'stylesdir')
22
+ %(<link rel="stylesheet" href="#{href}"#{(doc.attr? 'htmlsyntax', 'xml') ? '/' : ''}>) # rubocop:disable Style/TernaryParentheses
23
+ elsif (styles = path.empty? ?
24
+ (doc.read_asset DEFAULT_STYLESHEET_FILE) :
25
+ (doc.read_contents path, start: (doc.attr 'stylesdir'), warn_on_failure: true, label: 'tabs stylesheet'))
26
+ %(<style>\n#{styles.chomp}\n</style>)
27
+ end
24
28
  end
25
29
  end
26
30
 
@@ -31,8 +35,12 @@ module Asciidoctor
31
35
  JAVASCRIPT_FILE = ::File.join DATA_DIR, 'js/tabs.js'
32
36
 
33
37
  def process doc
34
- return unless (script = doc.read_asset JAVASCRIPT_FILE)
35
- %(<script>\n#{script.chomp}\n</script>)
38
+ if doc.attr? 'linkcss'
39
+ src = doc.normalize_web_path 'asciidoctor-tabs.js', (doc.attr 'scriptsdir')
40
+ %(<script src="#{src}"></script>)
41
+ elsif (script = doc.read_asset JAVASCRIPT_FILE)
42
+ %(<script>\n#{script.chomp}\n</script>)
43
+ end
36
44
  end
37
45
  end
38
46
  end
@@ -21,7 +21,7 @@ module Asciidoctor
21
21
  ((doc.options[:attributes] || {}).transform_keys {|it| it.delete '@!' }.key? 'tabs-stylesheet')
22
22
  doc.set_attr 'tabs-stylesheet'
23
23
  end
24
- docinfo_processor Docinfo::Styles
24
+ docinfo_processor Docinfo::Style
25
25
  docinfo_processor Docinfo::Behavior
26
26
  nil
27
27
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Asciidoctor
4
4
  module Tabs
5
- VERSION = '1.0.0.alpha.4'
5
+ VERSION = '1.0.0.alpha.6'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asciidoctor-tabs
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.alpha.4
4
+ version: 1.0.0.alpha.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Allen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-10-08 00:00:00.000000000 Z
11
+ date: 2022-11-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: asciidoctor