jekyll_outline 1.0.2 → 1.1.0

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: a9d31ca01b4964fe4a2f449ae0af3e9c62778378dbcfd2e093aea52bf5bd4cc5
4
- data.tar.gz: 0c9eefb3062c192bbc31c9dc972e363c3c62ff9ad1bbe92479337cf46f0f1a75
3
+ metadata.gz: 3efed359f1a20b1b255dff89ae002fc464162ae11f2ffbaaf2463cfdce031cfa
4
+ data.tar.gz: ba1a9378d1424cc673fb75bcc0bd8a0758b6861facb66474a24dad19a568940d
5
5
  SHA512:
6
- metadata.gz: d60b91075f29d828182822dea631af65b31e436a2301ff505fb29febdf1554b8b8e0a85879c472f30a309daaa204b8869d8dcf4be38771088cf644c2399832bf
7
- data.tar.gz: a0dfba650a90e1c34ba3bffaaf95cf31552a0f7a4589086f4debba869fed0fcc819438057ab201f2b78913f0feb0fb5bce965b8686d6aa2da5555ea8610609b4
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,3 +1,9 @@
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
8
  * Updated to `jekyll_plugin_support` v0.5.1
3
9
 
@@ -5,4 +11,4 @@
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'
36
- spec.add_dependency 'jekyll_plugin_support', '~> 0.5.1'
38
+ spec.add_dependency 'jekyll_draft', '~> 1.1.0'
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.2'.freeze
2
+ VERSION = '1.1.0'.freeze
3
3
  end
@@ -1,112 +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'
7
- require_relative 'jekyll_outline/version'
1
+ require_relative './outline_js'
2
+ require_relative './outline_tag'
8
3
 
9
4
  module Outline
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
- <<~END_STR
24
- <h3 id="title_#{order}">#{title}</h3>
25
- END_STR
26
- end
27
- end
28
-
29
- class OutlineTag < JekyllSupport::JekyllBlock
30
- include JekyllOutlineVersion
31
-
32
- FIXNUM_MAX = (2**((0.size * 8) - 2)) - 1
33
-
34
- def render_impl(text)
35
- @collection_name = argument_string.strip
36
- abort 'OutlineTag: collection_name was not specified' unless @collection_name
37
-
38
- headers = make_headers(super) # Process the block content.
39
- collection = headers + obtain_docs(@collection_name)
40
- <<~HEREDOC
41
- <div class="posts">
42
- #{make_entries(collection).join("\n")}
43
- </div>
44
- HEREDOC
45
- end
46
-
47
- private
48
-
49
- def header?(variable)
50
- variable.instance_of?(Header)
51
- end
52
-
53
- def make_headers(content)
54
- yaml = YAML.safe_load content
55
- yaml.map { |entry| Header.new entry }
56
- end
57
-
58
- def make_entries(collection)
59
- sorted = collection.sort_by(&obtain_order)
60
- pruned = remove_empty_headers(sorted)
61
- pruned.map do |entry|
62
- if entry.instance_of? Header
63
- <<~END_ENTRY
64
- <span></span> <span>#{entry}</span>
65
- END_ENTRY
66
- else
67
- date = entry.data['last_modified_at'] # "%Y-%m-%d"
68
- draft = Jekyll::Draft.draft_html(entry)
69
- <<~END_ENTRY
70
- <span>#{date}</span> <span><a href="#{entry.url}">#{entry.data['title']}</a>#{draft}</span>
71
- END_ENTRY
72
- end
73
- end
74
- end
75
-
76
- # Ignores files called index.html
77
- def obtain_docs(collection_name)
78
- abort "#{@collection_name} is not a valid collection." unless @site.collections.key? @collection_name
79
- @site
80
- .collections[collection_name]
81
- .docs
82
- .reject { |doc| doc.path.end_with? 'index.html' }
83
- end
84
-
85
- # Sort entries without an order property at the end
86
- def obtain_order
87
- proc do |entry|
88
- if entry.respond_to? :data
89
- entry.data.key?('order') ? entry.data['order'] : FIXNUM_MAX
90
- else
91
- entry.order
92
- end
93
- end
94
- end
95
-
96
- def remove_empty_headers(array)
97
- i = 0
98
- while i < array.length - 1
99
- if header?(array[i]) && header?(array[i + 1])
100
- array.delete_at(i)
101
- else
102
- i += 1
103
- end
104
- end
105
-
106
- array.delete_at(array.length - 1) if header?(array.last)
107
- array
108
- end
109
-
110
- JekyllPluginHelper.register(self, PLUGIN_NAME)
111
- end
5
+ include OutlineTag
6
+ include OutlineJsTag
112
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.2
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-17 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,28 +30,28 @@ 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
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 0.5.1
47
+ version: 0.5.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 0.5.1
54
+ version: 0.5.0
55
55
  description: 'Jekyll tag plugin that creates a clickable table of contents.
56
56
 
57
57
  '
@@ -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