jekyll_outline 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ed799d887e818fc21f0892c7c7fe550081352b98554bc4dae0fc8d6fb04b0a90
4
- data.tar.gz: ae4fd7f8a48d45abcabad5207566a8f96d0fe8b14e0016b294f54c9ba576f7fc
3
+ metadata.gz: 3efed359f1a20b1b255dff89ae002fc464162ae11f2ffbaaf2463cfdce031cfa
4
+ data.tar.gz: ba1a9378d1424cc673fb75bcc0bd8a0758b6861facb66474a24dad19a568940d
5
5
  SHA512:
6
- metadata.gz: ac864827baf9f274f85d9f52c84e38216bd8edd6ebd86be766b8002d966050cdc14e8f966bf905edbd7362386620bc012d7f66fd18c86c74eabafb564bdc8a04
7
- data.tar.gz: cc3cfd1e248224f34b242aa501a8cdf12f8d86dd26f46b09449f22505f4a33e6840892bccd875defcf558ae8822af68085751808318a9c2cb823eee35342438f
6
+ metadata.gz: a1147061ffb817c16a64002a8b300380943a319eb44c0077c54f76b9d6cd2f6d4500778fd369deed65f7256357feb5140129bda26be08344b2149bce00861b06
7
+ data.tar.gz: d03d8db73e90f7c39aa5b6f8f379ab2cfe8d47dae740e2e0a9d6355ac486713db28e02af07145e33279cba2d9aba982ae10f07c08087c192c953851d7fd51f25
data/.rubocop.yml CHANGED
@@ -25,7 +25,7 @@ Layout/LineLength:
25
25
  Metrics/BlockLength:
26
26
  Exclude:
27
27
  - jekyll_outline.gemspec
28
- Max: 30
28
+ Max: 40
29
29
 
30
30
  Metrics/MethodLength:
31
31
  Max: 30
data/CHANGELOG.md CHANGED
@@ -1,8 +1,14 @@
1
+ ## 1.1.0 / 2023-03-14
2
+ * `outline_js` tag added, for including Javascript necessary to position images relating to the outline.
3
+ * Now generates a series of divs, instead of one big div.
4
+ * Now interprets numbers as decimal instead of octal.
5
+ * CSS documented and new `post_title` class defined.
6
+
1
7
  ## 1.0.2 / 2023-02-16
2
- * Updated to `jekyll_plugin_support` v0.5.0
8
+ * Updated to `jekyll_plugin_support` v0.5.1
3
9
 
4
10
  ## 1.0.1 / 2023-02-14
5
11
  * Now dependent upon `jekyll_plugin_support`
6
12
 
7
13
  ## 1.0.0 / 2022-04-02
8
- * Initial version
14
+ * Initial version, this Jekyll plugin defines a block tag called `outline`.
data/README.md CHANGED
@@ -18,6 +18,102 @@ And then execute:
18
18
  $ bundle install
19
19
 
20
20
 
21
+ ### CSS
22
+ The CSS used for the demo website should be copied to your project.
23
+ See the section of `demo/assets/css/styles.css` as shown:
24
+
25
+ ```css
26
+ /* Start of jekyll_outline css */
27
+ ... copy this portion ...
28
+ /* End of jekyll_outline css */
29
+ ```
30
+
31
+ ### JavaScript
32
+ This project's `outline_js` tag returns the Javascript necessary to position images relating to the outline. If used without parameters it just returns the JavaScript:
33
+
34
+ ```html
35
+ <script>
36
+ {%= outline_js %}
37
+ </script>
38
+ ```
39
+
40
+ If passed the `wrap_in_script_tag` parameter, it wraps the JavaScript in `<script></script>`:
41
+
42
+ ```html
43
+ {% outline_js wrap_in_script_tag %}
44
+ ```
45
+
46
+
47
+ ## Explanation
48
+
49
+ Given an outline that looks like this:
50
+ ```html
51
+ {% outline stuff %}
52
+ 000: Topic 0..19
53
+ 020: Topic 20..39
54
+ 040: Topic 40..
55
+ {% endoutline %}
56
+ ```
57
+
58
+ ...and given pages in the `stuff` collection with the following names:
59
+
60
+ - 010-published.html has title **Published Stuff Post 010**
61
+ - 020-unpublished.html has title **Unpublished Post 020**
62
+ - 030-unpublished.html has title **Unpublished Post 030**
63
+
64
+ Then links to the pages in the `stuff` collection's pages are interleaved into the generated outline like this:
65
+ ```html
66
+ <div class="outer_posts">
67
+ <h3 class='post_title clear' id="title_0">Topic 0..19</h3>
68
+ <div id='posts_wrapper_0' class='clearfix'>
69
+ <div id='posts_0' class='posts'>
70
+ <span>2022-04-01</span> <span><a href='/stuff/010-published.html'>Published Stuff Post 010</a></span>
71
+ <span>2022-04-17</span> <span><a href='/stuff/020-unpublished.html'>Unpublished Post 020</a> <i class='jekyll_draft'>Draft</i></span>
72
+ </div>
73
+ </div>
74
+ <h3 class='post_title clear' id="title_20">Topic 20..39</h3>
75
+ <div id='posts_wrapper_20' class='clearfix'>
76
+ <div id='posts_20' class='posts'>
77
+ <span>2022-04-17</span> <span><a href='/stuff/030-unpublished.html'>Unpublished Post 030</a> <i class='jekyll_draft'>Draft</i></span>
78
+ </div>
79
+ </div>
80
+ </div>
81
+ ```
82
+
83
+ The JavaScript searches for images in the current page that were created by the [`img`](https://github.com/mslinn/jekyll_img) tag plugin,
84
+ and have `id`s that correspond to outline sections.
85
+
86
+ Each of following image's `id`s have a `outline_` prefix, followed by a number, which corresponds to one of the sections.
87
+ Note that leading zeros in the first column above are not present in the `id`s below.
88
+ ```html
89
+ {% img align="right"
90
+ id="outline_0"
91
+ size="quartersize"
92
+ src="/assets/images/porcelain_washbasin.webp"
93
+ style="margin-top: 0"
94
+ wrapper_class="clear"
95
+ %}
96
+ {% img align="right"
97
+ id="outline_20"
98
+ size="quartersize"
99
+ src="/assets/images/pipes.webp"
100
+ style="margin-top: 0"
101
+ wrapper_class="clear"
102
+ %}
103
+ {% img align="right"
104
+ id="outline_40"
105
+ size="quartersize"
106
+ src="/assets/images/libgit2.webp"
107
+ style="margin-top: 0"
108
+ wrapper_class="clear"
109
+ %}
110
+ ```
111
+ The JavaScript identifies the images and repositions them in the DOM such that they follow the appropriate heading.
112
+ If no image corresponds to a heading, no error or warning is generated.
113
+ The images can be located anywhere on the page; they will be relocated appropriately.
114
+ If an image does not correspond to a heading, it is deleted.
115
+
116
+
21
117
  ## Additional Information
22
118
  More information is available on
23
119
  [Mike Slinn&rsquo;s website](https://www.mslinn.com/jekyll/3000-jekyll-plugins.html#outline).
@@ -0,0 +1,31 @@
1
+ // jekyll_img generates picture tags wrapped within divs
2
+ // We move the entire div, not just the picture tag
3
+ // If an image does not correspond to a heading, delete it
4
+ function position_outline_image(picture, before_id) {
5
+ var img = picture.parentElement;
6
+ var before_element = document.getElementById(before_id);
7
+ if (before_element) {
8
+ var parent = before_element.parentElement;
9
+ parent.insertBefore(img, before_element);
10
+ } else {
11
+ img.remove();
12
+ }
13
+ }
14
+
15
+ function getElementsByIdPrefix(selectorTag, prefix) {
16
+ var items = [];
17
+ var myPosts = document.getElementsByTagName(selectorTag);
18
+ for (var i = 0; i < myPosts.length; i++) {
19
+ //omitting undefined null check for brevity
20
+ if (myPosts[i].id.lastIndexOf(prefix, 0) === 0)
21
+ items.push(myPosts[i]);
22
+ }
23
+ return items;
24
+ }
25
+
26
+ window.onload = (event) => {
27
+ getElementsByIdPrefix("picture", "outline_").forEach(picture => {
28
+ num = picture.id.substring("outline_".length)
29
+ position_outline_image(picture, `posts_wrapper_${num}`)
30
+ });
31
+ }
@@ -9,7 +9,10 @@ Gem::Specification.new do |spec|
9
9
  Jekyll tag plugin that creates a clickable table of contents.
10
10
  END_OF_DESC
11
11
  spec.email = ['mslinn@mslinn.com']
12
- spec.files = Dir['.rubocop.yml', 'LICENSE.*', 'Rakefile', '{lib,spec}/**/*', '*.gemspec', '*.md']
12
+ spec.files = Dir[
13
+ '.rubocop.yml', 'LICENSE.*', 'Rakefile', '{lib,spec}/**/*', '*.gemspec', '*.md',
14
+ 'demo/assets/js/jekyll_outline.js'
15
+ ]
13
16
  spec.homepage = 'https://www.mslinn.com/blog/2020/10/03/jekyll-plugins.html#outline'
14
17
  spec.license = 'MIT'
15
18
  spec.metadata = {
@@ -32,6 +35,6 @@ Gem::Specification.new do |spec|
32
35
  spec.version = JekyllOutlineVersion::VERSION
33
36
 
34
37
  spec.add_dependency 'jekyll', '>= 3.5.0'
35
- spec.add_dependency 'jekyll_draft', '~> 1.1.1'
38
+ spec.add_dependency 'jekyll_draft', '~> 1.1.0'
36
39
  spec.add_dependency 'jekyll_plugin_support', '~> 0.5.0'
37
40
  end
@@ -1,3 +1,3 @@
1
1
  module JekyllOutlineVersion
2
- VERSION = '1.0.1'.freeze
2
+ VERSION = '1.1.0'.freeze
3
3
  end
@@ -1,111 +1,7 @@
1
- # @author Copyright 2022 {https://www.mslinn.com Michael Slinn}
2
-
3
- require 'jekyll_draft'
4
- require 'jekyll_plugin_logger'
5
- require 'jekyll_plugin_support'
6
- require 'yaml'
1
+ require_relative './outline_js'
2
+ require_relative './outline_tag'
7
3
 
8
4
  module Outline
9
- PLUGIN_NAME = 'outline'.freeze
10
-
11
- # Interleaves with docs
12
- class Header
13
- attr_accessor :order, :title
14
-
15
- def initialize(yaml)
16
- @order = yaml[0]
17
- @published = true
18
- @title = yaml[1]
19
- end
20
-
21
- def to_s
22
- <<~END_STR
23
- <h3 id="title_#{order}">#{title}</h3>
24
- END_STR
25
- end
26
- end
27
-
28
- class OutlineTag < JekyllSupport::JekyllBlock
29
- include JekyllOutlineVersion
30
-
31
- FIXNUM_MAX = (2**((0.size * 8) - 2)) - 1
32
-
33
- def render_impl(text)
34
- @collection_name = argument_string.strip
35
- abort 'OutlineTag: collection_name was not specified' unless @collection_name
36
-
37
- headers = make_headers(super) # Process the block content.
38
- collection = headers + obtain_docs(@collection_name)
39
- <<~HEREDOC
40
- <div class="posts">
41
- #{make_entries(collection).join("\n")}
42
- </div>
43
- HEREDOC
44
- end
45
-
46
- private
47
-
48
- def header?(variable)
49
- variable.instance_of?(Header)
50
- end
51
-
52
- def make_headers(content)
53
- yaml = YAML.safe_load content
54
- yaml.map { |entry| Header.new entry }
55
- end
56
-
57
- def make_entries(collection)
58
- sorted = collection.sort_by(&obtain_order)
59
- pruned = remove_empty_headers(sorted)
60
- pruned.map do |entry|
61
- if entry.instance_of? Header
62
- <<~END_ENTRY
63
- <span></span> <span>#{entry}</span>
64
- END_ENTRY
65
- else
66
- date = entry.data['last_modified_at'] # "%Y-%m-%d"
67
- draft = Jekyll::Draft.draft_html(entry)
68
- <<~END_ENTRY
69
- <span>#{date}</span> <span><a href="#{entry.url}">#{entry.data['title']}</a>#{draft}</span>
70
- END_ENTRY
71
- end
72
- end
73
- end
74
-
75
- # Ignores files called index.html
76
- def obtain_docs(collection_name)
77
- abort "#{@collection_name} is not a valid collection." unless @site.collections.key? @collection_name
78
- @site
79
- .collections[collection_name]
80
- .docs
81
- .reject { |doc| doc.path.end_with? 'index.html' }
82
- end
83
-
84
- # Sort entries without an order property at the end
85
- def obtain_order
86
- proc do |entry|
87
- if entry.respond_to? :data
88
- entry.data.key?('order') ? entry.data['order'] : FIXNUM_MAX
89
- else
90
- entry.order
91
- end
92
- end
93
- end
94
-
95
- def remove_empty_headers(array)
96
- i = 0
97
- while i < array.length - 1
98
- if header?(array[i]) && header?(array[i + 1])
99
- array.delete_at(i)
100
- else
101
- i += 1
102
- end
103
- end
104
-
105
- array.delete_at(array.length - 1) if header?(array.last)
106
- array
107
- end
108
-
109
- JekyllPluginHelper.register(self, PLUGIN_NAME)
110
- end
5
+ include OutlineTag
6
+ include OutlineJsTag
111
7
  end
data/lib/outline_js.rb ADDED
@@ -0,0 +1,40 @@
1
+ require 'jekyll_plugin_support'
2
+ require_relative 'jekyll_outline/version'
3
+
4
+ module OutlineJsTag
5
+ PLUGIN_JS_NAME = 'outline_js'.freeze
6
+
7
+ class OutlineJsTag < JekyllSupport::JekyllTag
8
+ include JekyllOutlineVersion
9
+
10
+ def render_impl
11
+ wrap_in_script_tag = @helper.parameter_specified?('wrap_in_script_tag')
12
+
13
+ gem_path = Gem::Specification.find_by_name('jekyll_outline').full_gem_path
14
+ js_path = File.join(gem_path, 'demo/assets/js/jekyll_outline.js')
15
+ js = File.read(js_path)
16
+
17
+ if wrap_in_script_tag
18
+ <<~END_JS
19
+ <script>
20
+ #{indent(js)}
21
+ </script>
22
+ END_JS
23
+ else
24
+ js
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def indent(multiline)
31
+ multiline
32
+ .strip
33
+ .split("\n")
34
+ .map { |x| " #{x}" }
35
+ .join("\n")
36
+ end
37
+
38
+ JekyllPluginHelper.register(self, PLUGIN_JS_NAME)
39
+ end
40
+ end
@@ -0,0 +1,132 @@
1
+ # @author Copyright 2022 {https://www.mslinn.com Michael Slinn}
2
+
3
+ require 'jekyll_draft'
4
+ require 'jekyll_plugin_logger'
5
+ require 'jekyll_plugin_support'
6
+ require 'yaml'
7
+ require_relative 'jekyll_outline/version'
8
+
9
+ module OutlineTag
10
+ PLUGIN_NAME = 'outline'.freeze
11
+
12
+ # Interleaves with docs
13
+ class Header
14
+ attr_accessor :order, :title
15
+
16
+ def initialize(yaml)
17
+ @order = yaml[0]
18
+ @published = true
19
+ @title = yaml[1]
20
+ end
21
+
22
+ def to_s
23
+ " <h3 class='post_title clear' id=\"title_#{order}\">#{title}</h3>"
24
+ end
25
+ end
26
+
27
+ class OutlineTag < JekyllSupport::JekyllBlock
28
+ include JekyllOutlineVersion
29
+
30
+ FIXNUM_MAX = (2**((0.size * 8) - 2)) - 1
31
+
32
+ def render_impl(text)
33
+ @collection_name = argument_string.strip
34
+ abort 'OutlineTag: collection_name was not specified' unless @collection_name
35
+
36
+ headers = make_headers(super) # Process the block content.
37
+ collection = headers + obtain_docs(@collection_name)
38
+ <<~HEREDOC
39
+ <div class="outer_posts">
40
+ #{make_entries(collection).join("\n")}
41
+ </div>
42
+ HEREDOC
43
+ end
44
+
45
+ private
46
+
47
+ def header?(variable)
48
+ variable.instance_of?(Header)
49
+ end
50
+
51
+ def make_headers(content)
52
+ yaml = YAML.safe_load(remove_leading_zeros(content))
53
+ yaml.map { |entry| Header.new entry }
54
+ end
55
+
56
+ # @section_state can have values: :head, :in_body
57
+ # @param collection Array of Jekyll::Document and Outline::Header
58
+ # @return Array of String
59
+ def make_entries(collection) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Layout/LineEndStringConcatenationIndentation
60
+ sorted = collection.sort_by(&obtain_order)
61
+ pruned = remove_empty_headers(sorted)
62
+ @section_state = :head
63
+ @section_id = 0
64
+ result = pruned.map do |entry|
65
+ if entry.instance_of? Header
66
+ @header_order = entry.order
67
+ section_end = " </div>\n" if @section_state == :in_body
68
+ @section_state = :head
69
+ entry = section_end + entry.to_s if section_end
70
+ entry
71
+ else
72
+ if @section_state == :head
73
+ section_start = "<div id='posts_wrapper_#{@header_order}' class='clearfix'>\n " \
74
+ "<div id='posts_#{@header_order}' class='posts'>\n"
75
+ end
76
+ @section_state = :in_body
77
+ date = entry.data['last_modified_at'] # "%Y-%m-%d"
78
+ draft = Jekyll::Draft.draft_html(entry)
79
+ result = " <span>#{date}</span> <span><a href='#{entry.url}'>#{entry.data['title']}</a>#{draft}</span>"
80
+ result = section_start + result if section_start
81
+ result
82
+ end
83
+ end
84
+ result << " </div>\n </div>" if @section_state == :in_body
85
+ result
86
+ end
87
+
88
+ # Ignores files called index.html
89
+ def obtain_docs(collection_name)
90
+ abort "#{@collection_name} is not a valid collection." unless @site.collections.key? @collection_name
91
+ @site
92
+ .collections[collection_name]
93
+ .docs
94
+ .reject { |doc| doc.path.end_with? 'index.html' }
95
+ end
96
+
97
+ # Sort entries without an order property at the end
98
+ def obtain_order
99
+ proc do |entry|
100
+ if entry.respond_to? :data
101
+ entry.data.key?('order') ? entry.data['order'] : FIXNUM_MAX
102
+ else
103
+ entry.order
104
+ end
105
+ end
106
+ end
107
+
108
+ def remove_empty_headers(array)
109
+ i = 0
110
+ while i < array.length - 1
111
+ if header?(array[i]) && header?(array[i + 1])
112
+ array.delete_at(i)
113
+ else
114
+ i += 1
115
+ end
116
+ end
117
+
118
+ array.delete_at(array.length - 1) if header?(array.last)
119
+ array
120
+ end
121
+
122
+ def remove_leading_zeros(multiline)
123
+ multiline
124
+ .strip
125
+ .split("\n")
126
+ .map { |x| x.gsub(/(?<= |\A)0+(?=\d)/, '') }
127
+ .join("\n")
128
+ end
129
+
130
+ JekyllPluginHelper.register(self, PLUGIN_NAME)
131
+ end
132
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll_outline
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Slinn
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-02-16 00:00:00.000000000 Z
11
+ date: 2023-03-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jekyll
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.1.1
33
+ version: 1.1.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 1.1.1
40
+ version: 1.1.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: jekyll_plugin_support
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -66,9 +66,12 @@ files:
66
66
  - LICENSE.txt
67
67
  - README.md
68
68
  - Rakefile
69
+ - demo/assets/js/jekyll_outline.js
69
70
  - jekyll_outline.gemspec
70
71
  - lib/jekyll_outline.rb
71
72
  - lib/jekyll_outline/version.rb
73
+ - lib/outline_js.rb
74
+ - lib/outline_tag.rb
72
75
  - spec/outline_spec.rb
73
76
  - spec/spec_helper.rb
74
77
  homepage: https://www.mslinn.com/blog/2020/10/03/jekyll-plugins.html#outline