jekyll-contentblocks 1.1.0 → 2.0.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.
Files changed (53) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ci.yml +110 -0
  3. data/.gitignore +1 -1
  4. data/Appraisals +50 -24
  5. data/Gemfile +15 -5
  6. data/README.md +118 -20
  7. data/gemfiles/jekyll_3.0.5.gemfile +15 -0
  8. data/gemfiles/jekyll_3.1.6.gemfile +15 -0
  9. data/gemfiles/jekyll_3.10.0.gemfile +16 -0
  10. data/gemfiles/jekyll_3.2.1.gemfile +15 -0
  11. data/gemfiles/jekyll_3.3.1.gemfile +15 -0
  12. data/gemfiles/jekyll_3.4.5.gemfile +15 -0
  13. data/gemfiles/jekyll_3.5.2.gemfile +15 -0
  14. data/gemfiles/jekyll_3.6.3.gemfile +15 -0
  15. data/gemfiles/jekyll_3.7.4.gemfile +15 -0
  16. data/gemfiles/jekyll_3.8.7.gemfile +15 -0
  17. data/gemfiles/jekyll_3.9.5.gemfile +16 -0
  18. data/gemfiles/jekyll_4.0.1.gemfile +15 -0
  19. data/gemfiles/jekyll_4.1.1.gemfile +15 -0
  20. data/gemfiles/jekyll_4.2.2.gemfile +15 -0
  21. data/gemfiles/jekyll_4.3.4.gemfile +15 -0
  22. data/gemfiles/jekyll_4.4.1.gemfile +15 -0
  23. data/jekyll-contentblocks.gemspec +7 -2
  24. data/lib/jekyll/content_blocks/content_block_tag.rb +34 -7
  25. data/lib/jekyll/content_blocks/pre_render_hook.rb +11 -0
  26. data/lib/jekyll/content_blocks/version.rb +1 -2
  27. data/lib/jekyll/tags/content_block.rb +2 -9
  28. data/lib/jekyll/tags/content_for.rb +18 -3
  29. data/lib/jekyll-contentblocks.rb +15 -22
  30. data/mise.toml +5 -0
  31. data/spec/jekyll_content_blocks_spec.rb +115 -55
  32. data/spec/spec_helper.rb +11 -12
  33. data/test/_layouts/default.html +14 -0
  34. data/test/_plugins/require.rb +1 -0
  35. data/test/emptyblock.md +8 -0
  36. data/test/page2.md +12 -0
  37. data/test/page3.md +27 -0
  38. metadata +44 -27
  39. data/gemfiles/jekyll_1.0.4.gemfile +0 -12
  40. data/gemfiles/jekyll_1.1.2.gemfile +0 -12
  41. data/gemfiles/jekyll_1.2.1.gemfile +0 -12
  42. data/gemfiles/jekyll_1.3.1.gemfile +0 -12
  43. data/gemfiles/jekyll_1.4.3.gemfile +0 -12
  44. data/gemfiles/jekyll_1.5.1.gemfile +0 -12
  45. data/gemfiles/jekyll_2.0.3.gemfile +0 -12
  46. data/gemfiles/jekyll_2.1.1.gemfile +0 -12
  47. data/gemfiles/jekyll_2.2.0.gemfile +0 -12
  48. data/gemfiles/jekyll_2.3.0.gemfile +0 -12
  49. data/gemfiles/jekyll_2.4.0.gemfile +0 -12
  50. data/gemfiles/jekyll_2.5.3.gemfile +0 -12
  51. data/lib/jekyll/content_blocks/convertible.rb +0 -27
  52. data/lib/jekyll/content_blocks/renderer.rb +0 -11
  53. data/test/_plugins/bundler.rb +0 -4
@@ -0,0 +1,15 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "jekyll", "4.3.4"
6
+ gem "rexml"
7
+ gem "appraisal", "~> 2.5.0"
8
+ gem "pry"
9
+ gem "rspec", "~> 3.13.0"
10
+ gem "nokogiri"
11
+ gem "base64"
12
+ gem "bigdecimal"
13
+ gem "csv"
14
+
15
+ gemspec path: "../"
@@ -0,0 +1,15 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "jekyll", "4.4.1"
6
+ gem "rexml"
7
+ gem "appraisal", "~> 2.5.0"
8
+ gem "pry"
9
+ gem "rspec", "~> 3.13.0"
10
+ gem "nokogiri"
11
+ gem "base64"
12
+ gem "bigdecimal"
13
+ gem "csv"
14
+
15
+ gemspec path: "../"
@@ -11,11 +11,16 @@ Gem::Specification.new do |gem|
11
11
  gem.description = %q{Provides a mechanism for passing content up to the layout, like Rails' content_for}
12
12
  gem.summary = %q{A Jekyll plugin kind of like Rails' content_for}
13
13
  gem.homepage = "https://github.com/rustygeldmacher/jekyll-contentblocks"
14
+ gem.license = "MIT"
14
15
 
15
- gem.files = `git ls-files`.split($/)
16
+ gem.files = `git ls-files`.split($/) - ["Gemfile.lock"]
16
17
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
18
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
19
  gem.require_paths = ["lib"]
19
20
 
20
- gem.add_dependency('jekyll')
21
+ # Jekyll 3.0–3.7 rely on APIs removed in Ruby 3, so 2.7 is the effective floor.
22
+ gem.required_ruby_version = ">= 2.7.0"
23
+
24
+ # Supports the Jekyll 3.x and 4.x series; excludes the announced-breaking 5.x.
25
+ gem.add_dependency('jekyll', '>= 3.0', '< 5.0')
21
26
  end
@@ -7,7 +7,7 @@ module Jekyll
7
7
  def initialize(tag_name, markup, tokens)
8
8
  super
9
9
  parse_options(markup)
10
- if content_block_name == ''
10
+ if content_block_name == ""
11
11
  raise SyntaxError.new("No block name given in #{tag_name} tag")
12
12
  end
13
13
  end
@@ -15,20 +15,47 @@ module Jekyll
15
15
  private
16
16
 
17
17
  def parse_options(markup)
18
- options = (markup || '').split(' ').map(&:strip)
18
+ options = (markup || "").split(" ").map(&:strip)
19
19
  self.content_block_name = options.shift
20
20
  self.content_block_options = options
21
21
  end
22
22
 
23
23
  def block_has_content?(context)
24
- block_content = content_for_block(context).join
25
- !(block_content.nil? || block_content.empty?)
24
+ !raw_block_content(context).empty?
26
25
  end
27
26
 
27
+ # Write accessor for the contentfor tag: returns the block's array, creating
28
+ # it if needed. Each stored block is a hash: "raw" (the block body), "content"
29
+ # (that body converted) and "data" (its own front matter). The store is
30
+ # exposed to layouts as contentblocks.<name> so they can be looped over.
28
31
  def content_for_block(context)
29
- environment = context.environments.first
30
- environment['contentblocks'] ||= {}
31
- environment['contentblocks'][content_block_name] ||= []
32
+ store = (context.environments.first["contentblocks"] ||= {})
33
+ store[content_block_name] ||= []
34
+ end
35
+
36
+ # Read-only view — does NOT create an empty entry. Reading a never-defined
37
+ # block therefore leaves contentblocks.<name> nil (falsy) rather than an
38
+ # empty array (which Liquid would treat as truthy).
39
+ def blocks_for(context)
40
+ (context.environments.first["contentblocks"] || {})[content_block_name] || []
41
+ end
42
+
43
+ def raw_block_content(context)
44
+ blocks_for(context).map { |block| block["raw"] }.join
45
+ end
46
+
47
+ # Convert content with the document's converters, derived from the render
48
+ # context (so we don't depend on the pre-render hook stashing them).
49
+ def converted_content(content, context)
50
+ Array(converters_for(context)).reduce(content) do |result, converter|
51
+ converter.convert(result)
52
+ end
53
+ end
54
+
55
+ def converters_for(context)
56
+ site = context.registers[:site]
57
+ extension = File.extname(context.registers[:page]["path"].to_s)
58
+ site.converters.select { |converter| converter.matches(extension) }
32
59
  end
33
60
  end
34
61
  end
@@ -0,0 +1,11 @@
1
+ module Jekyll
2
+ module ContentBlocks
3
+ class PreRenderHook
4
+ def self.call(document, payload)
5
+ # Reset the per-document block store. Converters are derived on demand by
6
+ # the contentblock tag from the render context, so they aren't stashed here.
7
+ payload["contentblocks"] = {}
8
+ end
9
+ end
10
+ end
11
+ end
@@ -1,6 +1,5 @@
1
1
  module Jekyll
2
2
  module ContentBlocks
3
- VERSION = "1.1.0"
3
+ VERSION = "2.0.0"
4
4
  end
5
5
  end
6
-
@@ -4,7 +4,7 @@ module Jekyll
4
4
  include ::Jekyll::ContentBlocks::ContentBlockTag
5
5
 
6
6
  def render(context)
7
- block_content = content_for_block(context).join
7
+ block_content = raw_block_content(context)
8
8
  if convert_content?
9
9
  converted_content(block_content, context)
10
10
  else
@@ -15,14 +15,7 @@ module Jekyll
15
15
  private
16
16
 
17
17
  def convert_content?
18
- !content_block_options.include?('no-convert')
19
- end
20
-
21
- def converted_content(block_content, context)
22
- converters = context.environments.first['converters']
23
- Array(converters).reduce(block_content) do |content, converter|
24
- converter.convert(content)
25
- end
18
+ !content_block_options.include?("no-convert")
26
19
  end
27
20
  end
28
21
  end
@@ -5,10 +5,25 @@ module Jekyll
5
5
  alias_method :render_block, :render
6
6
 
7
7
  def render(context)
8
- content_for_block(context) << render_block(context)
9
- ''
8
+ data, body = split_front_matter(render_block(context))
9
+ content_for_block(context) <<
10
+ {
11
+ "raw" => body,
12
+ "content" => converted_content(body, context),
13
+ "data" => data
14
+ }
15
+ ""
16
+ end
17
+
18
+ private
19
+
20
+ def split_front_matter(rendered)
21
+ if rendered.lstrip =~ Jekyll::Document::YAML_FRONT_MATTER_REGEXP
22
+ [SafeYAML.load(Regexp.last_match(1)) || {}, $POSTMATCH]
23
+ else
24
+ [{}, rendered]
25
+ end
10
26
  end
11
27
  end
12
28
  end
13
29
  end
14
-
@@ -1,28 +1,21 @@
1
- require 'jekyll'
1
+ require "jekyll"
2
2
 
3
- module Jekyll
4
- def self.version_less_than?(version)
5
- Gem::Version.new(VERSION) < Gem::Version.new(version)
6
- end
3
+ require "jekyll/content_blocks/pre_render_hook"
7
4
 
8
- def self.supports_collections?
9
- !version_less_than?('2.0.0')
5
+ [:documents, :pages, :posts].each do |content_type|
6
+ Jekyll::Hooks.register(content_type, :pre_render) do |doc, payload|
7
+ Jekyll::ContentBlocks::PreRenderHook.call(doc, payload)
10
8
  end
11
9
  end
12
10
 
13
- require 'jekyll/content_blocks/convertible'
14
- unless Jekyll.version_less_than?('2.0.0')
15
- require 'jekyll/content_blocks/renderer'
16
- end
17
-
18
- require 'jekyll/content_blocks/version'
19
- require 'jekyll/content_blocks/content_block_tag'
20
- require 'jekyll/tags/content_for'
21
- require 'jekyll/tags/if_has_content'
22
- require 'jekyll/tags/if_not_has_content'
23
- require 'jekyll/tags/content_block'
11
+ require "jekyll/content_blocks/version"
12
+ require "jekyll/content_blocks/content_block_tag"
13
+ require "jekyll/tags/content_for"
14
+ require "jekyll/tags/if_has_content"
15
+ require "jekyll/tags/if_not_has_content"
16
+ require "jekyll/tags/content_block"
24
17
 
25
- Liquid::Template.register_tag('contentfor', Jekyll::Tags::ContentFor)
26
- Liquid::Template.register_tag('ifhascontent', Jekyll::Tags::IfHasContent)
27
- Liquid::Template.register_tag('ifnothascontent', Jekyll::Tags::IfNotHasContent)
28
- Liquid::Template.register_tag('contentblock', Jekyll::Tags::ContentBlock)
18
+ Liquid::Template.register_tag("contentfor", Jekyll::Tags::ContentFor)
19
+ Liquid::Template.register_tag("ifhascontent", Jekyll::Tags::IfHasContent)
20
+ Liquid::Template.register_tag("ifnothascontent", Jekyll::Tags::IfNotHasContent)
21
+ Liquid::Template.register_tag("contentblock", Jekyll::Tags::ContentBlock)
data/mise.toml ADDED
@@ -0,0 +1,5 @@
1
+ [tools]
2
+ ruby = "3.3"
3
+ # rubyfmt isn't in the mise registry, so install it from its GitHub releases
4
+ # via the github backend (github.com/fables-tales/rubyfmt).
5
+ "github:fables-tales/rubyfmt" = "0.14.1"
@@ -1,95 +1,155 @@
1
- require 'spec_helper'
1
+ require "spec_helper"
2
2
 
3
3
  describe Jekyll::ContentBlocks do
4
- puts "jekyll #{jekyll_version}"
4
+ puts("jekyll #{jekyll_version}")
5
5
 
6
- context "against jekyll #{jekyll_version}" do
6
+ context("against jekyll #{jekyll_version}") do
7
7
  before(:all) do
8
- expect(generate_test_site).to be true
8
+ expect(generate_test_site).to(be(true))
9
9
  end
10
10
 
11
- let(:index) { load_html('index.html') }
11
+ let(:index) { load_html("index.html") }
12
12
 
13
- describe 'index.html' do
14
- let(:sidebar) { index.css('body > div > h2#sidebar').first }
13
+ describe "index.html" do
14
+ let(:sidebar) { index.css("body > div > h2#sidebar").first }
15
15
 
16
- it 'does not render the css block' do
17
- expect(index.css('style')).to be_empty
16
+ it "does not render the css block" do
17
+ expect(index.css("style")).to(be_empty)
18
18
  end
19
19
 
20
- it 'renders the custom sidebar' do
21
- expect(index.css('div.custom-sidebar')).not_to be_empty
22
- expect(index.css('div.sidebar-default')).to be_empty
20
+ it "renders the custom sidebar" do
21
+ expect(index.css("div.custom-sidebar")).not_to(be_empty)
22
+ expect(index.css("div.sidebar-default")).to(be_empty)
23
23
  end
24
24
 
25
- it 'renders the sidebar content block' do
26
- expect(sidebar).not_to be_nil
27
- expect(sidebar.text).to eq 'SIDEBAR'
25
+ it "renders the sidebar content block" do
26
+ expect(sidebar).not_to(be_nil)
27
+ expect(sidebar.text).to(eq("SIDEBAR"))
28
28
  end
29
29
 
30
- it 'renders Liquid within a content block' do
31
- rendered_liquid = sidebar.css('+ p')
32
- expect(rendered_liquid).not_to be_nil
33
- expect(rendered_liquid.text).to eq '3'
30
+ it "renders Liquid within a content block" do
31
+ rendered_liquid = sidebar.css("+ p")
32
+ expect(rendered_liquid).not_to(be_nil)
33
+ expect(rendered_liquid.text).to(eq("3"))
34
34
  end
35
35
 
36
- it 'does not render a block without content' do
37
- expect(index.css('head > style')).to be_empty
36
+ it "does not render a block without content" do
37
+ expect(index.css("head > style")).to(be_empty)
38
38
  end
39
39
  end
40
40
 
41
- describe 'page.html' do
42
- let(:page) { load_html('page.html') }
43
- let(:sidebar) { index.css('body > div > h2#sidebar').first }
41
+ describe "page.html" do
42
+ let(:page) { load_html("page.html") }
44
43
 
45
- it 'renders the css block' do
46
- expect(page.css('style')).not_to be_empty
44
+ it "renders the css block" do
45
+ expect(page.css("style")).not_to(be_empty)
47
46
  end
48
47
 
49
- it 'does not process Markdown in the CSS block' do
50
- styles = page.css('style').text.gsub(/\s/, '')
51
- expect(styles).to eq 'div{font-weight:bold;}'
48
+ it "does not process Markdown in the CSS block" do
49
+ styles = page.css("style").text.gsub(/\s/, "")
50
+ expect(styles).to(eq("div{font-weight:bold;}"))
52
51
  end
53
52
 
54
- it 'renders the custom footer' do
55
- expect(page.css('div#footer')).to be_empty
56
- expect(page.css('div#custom-footer')).not_to be_empty
53
+ it "renders the custom footer" do
54
+ expect(page.css("div#footer")).to(be_empty)
55
+ expect(page.css("div#custom-footer")).not_to(be_empty)
57
56
  end
58
57
 
59
- it 'renders the default sidebar' do
60
- expect(page.css('div.sidebar-default')).not_to be_empty
61
- expect(page.css('div.custom-sidebar')).to be_empty
58
+ it "renders the default sidebar" do
59
+ expect(page.css("div.sidebar-default")).not_to(be_empty)
60
+ expect(page.css("div.custom-sidebar")).to(be_empty)
62
61
  end
63
62
  end
64
63
 
65
- describe 'ifnothascontent' do
66
- it 'renders defaults when content is not supplied' do
67
- expect(index.css('div#footer')).not_to be_empty
64
+ describe "page2.html" do
65
+ let(:page) { load_html("page2.html") }
66
+
67
+ it "renders only the page2 sidebar" do
68
+ sidebar = page.css("div.custom-sidebar")
69
+ expect(sidebar).not_to(be_empty)
70
+ expect(sidebar.text.strip).to(eq("A pretty simple sidebar."))
71
+ end
72
+ end
73
+
74
+ describe "ifnothascontent" do
75
+ it "renders defaults when content is not supplied" do
76
+ expect(index.css("div#footer")).not_to(be_empty)
68
77
  end
69
78
 
70
- it 'does not render when there is content' do
71
- expect(index.css('div[class=sidebar-default]')).to be_empty
79
+ it "does not render when there is content" do
80
+ expect(index.css("div[class=sidebar-default]")).to(be_empty)
72
81
  end
73
82
  end
74
83
 
75
- if Jekyll.supports_collections?
76
- describe 'content blocks in a collection' do
77
- let(:item_one) { load_item_html('one') }
78
- let(:item_two) { load_item_html('two') }
84
+ describe "content blocks in a collection" do
85
+ let(:item_one) { load_item_html("one") }
86
+ let(:item_two) { load_item_html("two") }
87
+
88
+ it "should render the content block" do
89
+ expect(item_one.css("div[class=sidebar-default]")).to(be_empty)
90
+ expect(item_one.css("div[class=custom-sidebar]")).not_to(be_empty)
91
+ end
92
+
93
+ it "should skip a content block that was not defined" do
94
+ expect(item_two.css("div[class=sidebar-default]")).not_to(be_empty)
95
+ expect(item_two.css("div[class=custom-sidebar]")).to(be_empty)
96
+ end
79
97
 
80
- it 'should render the content block' do
81
- expect(item_one.css('div[class=sidebar-default]')).to be_empty
82
- expect(item_one.css('div[class=custom-sidebar]')).not_to be_empty
83
- end
98
+ it "should process Markdown inside the content block" do
99
+ expect(item_one.css("div[class=custom-sidebar] ul li")).not_to(be_empty)
100
+ end
101
+ end
102
+
103
+ describe "page3.html (repeated blocks and front matter)" do
104
+ let(:page) { load_html("page3.html") }
105
+ let(:testimonials) { page.css("div.testimonials div.testimonial") }
106
+
107
+ it "collects each same-named block into contentblocks" do
108
+ expect(testimonials.length).to(eq(3))
109
+ end
110
+
111
+ it "exposes each block's front matter under data" do
112
+ expect(testimonials[0]["data-author"]).to(eq("Ada Lovelace"))
113
+ expect(testimonials[1]["data-author"]).to(eq("Alan Turing"))
114
+ end
84
115
 
85
- it 'should skip a content block that was not defined' do
86
- expect(item_two.css('div[class=sidebar-default]')).not_to be_empty
87
- expect(item_two.css('div[class=custom-sidebar]')).to be_empty
88
- end
116
+ it "leaves data empty for a block without front matter" do
117
+ expect(testimonials[2]["data-author"].to_s).to(eq(""))
118
+ end
119
+
120
+ it "converts each block's Markdown content" do
121
+ expect(testimonials[0].css("strong").text).to(eq("delightful"))
122
+ end
123
+
124
+ it "does not render the section on pages without those blocks" do
125
+ expect(index.css("div.testimonials")).to(be_empty)
126
+ end
127
+ end
128
+
129
+ describe "contentblocks variable" do
130
+ it "is present for a block that has content" do
131
+ expect(index.css("span#cb-sidebar-present")).not_to(be_empty)
132
+ end
133
+
134
+ it "stays nil for a block referenced by tags but with no content" do
135
+ # page.html renders {% ifhascontent sidebar %} but never defines a sidebar,
136
+ # so contentblocks.sidebar must not have been created as an empty array.
137
+ expect(load_html("page.html").css("span#cb-sidebar-present")).to(be_empty)
138
+ end
139
+ end
140
+
141
+ describe "a block defined but left empty" do
142
+ # `{% if contentblocks.x %}` tests whether the block was defined, while
143
+ # `ifhascontent` tests for non-empty content — so they diverge here.
144
+ let(:page) { load_html("emptyblock.html") }
145
+
146
+ it "is present in contentblocks (the block was defined)" do
147
+ expect(page.css("span#cb-sidebar-present")).not_to(be_empty)
148
+ end
89
149
 
90
- it 'should process Markdown inside the content block' do
91
- expect(item_one.css('div[class=custom-sidebar] ul li')).not_to be_empty
92
- end
150
+ it "counts as no content for ifhascontent / ifnothascontent" do
151
+ expect(page.css("div.custom-sidebar")).to(be_empty)
152
+ expect(page.css("div.sidebar-default")).not_to(be_empty)
93
153
  end
94
154
  end
95
155
  end
data/spec/spec_helper.rb CHANGED
@@ -1,31 +1,30 @@
1
- require 'nokogiri'
2
- require 'jekyll-contentblocks'
3
- require 'pry-byebug'
1
+ require "nokogiri"
2
+ require "jekyll-contentblocks"
3
+ require "open3"
4
4
 
5
5
  module SpecHelpers
6
6
  def jekyll_version
7
- @jekyll_version ||= `jekyll --version`.strip.gsub('jekyll ', '')
7
+ @jekyll_version ||= `jekyll --version`.strip.gsub("jekyll ", "")
8
8
  end
9
9
 
10
10
  def generate_test_site
11
- system 'rm -rf test/_site'
12
- system 'jekyll build -s test/ -d test/_site &> /dev/null'
11
+ FileUtils.rm_rf("test/_site")
12
+ output, status = Open3.capture2e("jekyll build -s test/ -d test/_site")
13
+ # Keep passing runs quiet; only surface the build log when it actually fails.
14
+ warn(output) unless status.success?
15
+ status.success?
13
16
  end
14
17
 
15
18
  def load_html(file)
16
19
  path = "test/_site/#{file}"
17
- if File.exists?(path)
20
+ if File.exist?(path)
18
21
  index_html = File.read(path)
19
22
  Nokogiri::Slop(index_html).html
20
23
  end
21
24
  end
22
25
 
23
26
  def load_item_html(item)
24
- if Jekyll.version_less_than?('2.1.0')
25
- load_html("items/#{item}.html")
26
- else
27
- load_html("items/#{item}/index.html")
28
- end
27
+ load_html("items/#{item}/index.html")
29
28
  end
30
29
  end
31
30
 
@@ -25,6 +25,10 @@
25
25
  </div>
26
26
  {% endifnothascontent %}
27
27
 
28
+ {% if contentblocks.sidebar %}
29
+ <span id="cb-sidebar-present"></span>
30
+ {% endif %}
31
+
28
32
  {% ifhascontent footer %}
29
33
  {% contentblock footer %}
30
34
  {% endifhascontent %}
@@ -34,6 +38,16 @@
34
38
  This is the default footer.
35
39
  </div>
36
40
  {% endifnothascontent %}
41
+
42
+ {% if contentblocks.testimonial %}
43
+ <div class="testimonials">
44
+ {% for testimonial in contentblocks.testimonial %}
45
+ <div class="testimonial" data-author="{{ testimonial.data.author }}">
46
+ {{ testimonial.content }}
47
+ </div>
48
+ {% endfor %}
49
+ </div>
50
+ {% endif %}
37
51
  </body>
38
52
  </html>
39
53
 
@@ -0,0 +1 @@
1
+ require "jekyll-contentblocks"
@@ -0,0 +1,8 @@
1
+ ---
2
+ title: Empty Block
3
+ layout: default
4
+ ---
5
+
6
+ This page defines a sidebar block but leaves it empty.
7
+
8
+ {% contentfor sidebar %}{% endcontentfor %}
data/test/page2.md ADDED
@@ -0,0 +1,12 @@
1
+ ---
2
+ title: Page Two
3
+ layout: default
4
+ ---
5
+
6
+ # CONTENT
7
+
8
+ This page also has a sidebar.
9
+
10
+ {% contentfor sidebar %}
11
+ A pretty simple sidebar.
12
+ {% endcontentfor %}
data/test/page3.md ADDED
@@ -0,0 +1,27 @@
1
+ ---
2
+ title: Page Three
3
+ layout: default
4
+ ---
5
+
6
+ # CONTENT
7
+
8
+ This page defines several blocks with the same name, each with its own front
9
+ matter, and the layout loops over them.
10
+
11
+ {% contentfor testimonial %}
12
+ ---
13
+ author: Ada Lovelace
14
+ ---
15
+ A **delightful** plugin.
16
+ {% endcontentfor %}
17
+
18
+ {% contentfor testimonial %}
19
+ ---
20
+ author: Alan Turing
21
+ ---
22
+ Saved us hours of work.
23
+ {% endcontentfor %}
24
+
25
+ {% contentfor testimonial %}
26
+ Anonymous, but happy.
27
+ {% endcontentfor %}