middleman-blog 3.4.1 → 3.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +0 -6
- data/CHANGELOG.md +32 -1
- data/Gemfile +5 -9
- data/README.md +3 -2
- data/features/article_cli.feature +10 -1
- data/features/custom_collections.feature +11 -0
- data/features/language.feature +82 -0
- data/features/multiblog.feature +4 -2
- data/features/permalink-data.feature +12 -0
- data/features/summary.feature +13 -0
- data/features/support/env.rb +3 -0
- data/features/tags.feature +18 -1
- data/features/time_zone.feature +1 -1
- data/fixtures/custom-article-template-app/config.rb +3 -0
- data/fixtures/custom-article-template-app/my_custom_article.tt +7 -0
- data/fixtures/custom-article-template-app/source/index.html.erb +9 -0
- data/fixtures/custom-article-template-app/source/layout.erb +30 -0
- data/fixtures/custom-collections-sources-app/config.rb +11 -0
- data/fixtures/custom-collections-sources-app/source/articles/2011-01-02-another-article.html.markdown +8 -0
- data/fixtures/custom-collections-sources-app/source/category.html.erb +7 -0
- data/fixtures/custom-collections-sources-app/source/index.html.erb +5 -0
- data/fixtures/custom-collections-sources-app/source/layout.erb +13 -0
- data/fixtures/custom-collections-sources-app/source/news/2011-01-01-new-article.html.markdown +7 -0
- data/fixtures/language-app/config.rb +2 -0
- data/fixtures/language-app/locales/en.yml +4 -0
- data/fixtures/language-app/locales/ru.yml +4 -0
- data/fixtures/language-app/source/2013-09-07-english-article-with-lang-in-frontmatter.html.erb +6 -0
- data/fixtures/language-app/source/2013-09-07-russian-article-with-lang-in-frontmatter.html.erb +6 -0
- data/fixtures/language-app/source/en/2013-09-07-english-article-with-lang-in-path.html.erb +5 -0
- data/fixtures/language-app/source/layouts/layout.erb +8 -0
- data/fixtures/language-app/source/localizable/index.html.erb +5 -0
- data/fixtures/language-app/source/ru/2013-09-07-russian-article-with-lang-in-path.html.erb +5 -0
- data/fixtures/multiblog-app/source/blog1/index.html.erb +7 -0
- data/fixtures/permalink-data-app/config.rb +5 -0
- data/fixtures/permalink-data-app/source/index.html.erb +3 -0
- data/fixtures/permalink-data-app/source/layout.erb +14 -0
- data/fixtures/permalink-data-app/source/news/2011-01-01-new-article.html.markdown +7 -0
- data/fixtures/time-zone-app/source/blog/2013-06-24-hello.html.erb +1 -0
- data/lib/middleman-blog.rb +3 -8
- data/lib/middleman-blog/blog_article.rb +96 -60
- data/lib/middleman-blog/blog_data.rb +78 -76
- data/lib/middleman-blog/calendar_pages.rb +87 -119
- data/lib/middleman-blog/commands/article.rb +20 -14
- data/lib/middleman-blog/custom_pages.rb +30 -64
- data/lib/middleman-blog/extension.rb +175 -0
- data/lib/middleman-blog/helpers.rb +152 -0
- data/lib/middleman-blog/paginator.rb +127 -123
- data/lib/middleman-blog/tag_pages.rb +27 -45
- data/lib/middleman-blog/template.rb +17 -15
- data/lib/middleman-blog/template/config.tt +30 -33
- data/lib/middleman-blog/template/source/layout.erb +1 -0
- data/lib/middleman-blog/uri_templates.rb +58 -0
- data/lib/middleman-blog/version.rb +1 -1
- data/middleman-blog.gemspec +4 -1
- metadata +75 -9
- data/Gemfile-3.0 +0 -27
- data/lib/middleman-blog/extension_3_0.rb +0 -248
- data/lib/middleman-blog/extension_3_1.rb +0 -278
@@ -0,0 +1,14 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
</head>
|
5
|
+
<body>
|
6
|
+
<% if is_blog_article? %>
|
7
|
+
URL: <%= current_article.url %>
|
8
|
+
Category: <%= current_article.metadata[:page]['category'] %>
|
9
|
+
<%= yield %>
|
10
|
+
<% else %>
|
11
|
+
<%= yield %>
|
12
|
+
<% end %>
|
13
|
+
</body>
|
14
|
+
</html>
|
data/lib/middleman-blog.rb
CHANGED
@@ -5,11 +5,6 @@ require "middleman-blog/template"
|
|
5
5
|
require "middleman-blog/commands/article"
|
6
6
|
|
7
7
|
::Middleman::Extensions.register(:blog) do
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
else
|
12
|
-
require "middleman-blog/extension_3_0"
|
13
|
-
::Middleman::Blog
|
14
|
-
end
|
15
|
-
end
|
8
|
+
require "middleman-blog/extension"
|
9
|
+
::Middleman::BlogExtension
|
10
|
+
end
|
@@ -1,95 +1,93 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
1
2
|
require 'active_support/time_with_zone'
|
2
3
|
require 'active_support/core_ext/time/calculations'
|
3
4
|
|
4
5
|
module Middleman
|
5
6
|
module Blog
|
6
|
-
# A module that adds blog-article methods to Resources.
|
7
|
+
# A module that adds blog-article-specific methods to Resources.
|
8
|
+
# A {BlogArticle} can be retrieved via {Blog::Helpers#current_article} or
|
9
|
+
# methods on {BlogData} (like {BlogData#articles}).
|
10
|
+
# @see http://rdoc.info/github/middleman/middleman/Middleman/Sitemap/Resource Middleman::Sitemap::Resource
|
7
11
|
module BlogArticle
|
8
12
|
def self.extended(base)
|
9
13
|
base.class.send(:attr_accessor, :blog_controller)
|
10
14
|
end
|
11
15
|
|
16
|
+
# A reference to the {BlogData} for this article's blog.
|
17
|
+
# @return [BlogData]
|
12
18
|
def blog_data
|
13
|
-
|
14
|
-
self.blog_controller.data
|
15
|
-
else
|
16
|
-
app.blog
|
17
|
-
end
|
19
|
+
blog_controller.data
|
18
20
|
end
|
19
21
|
|
22
|
+
# The options for this article's blog.
|
23
|
+
# @return [ConfigurationManager]
|
20
24
|
def blog_options
|
21
|
-
|
22
|
-
self.blog_controller.options
|
23
|
-
else
|
24
|
-
app.blog.options
|
25
|
-
end
|
25
|
+
blog_controller.options
|
26
26
|
end
|
27
27
|
|
28
|
-
# Render this resource
|
28
|
+
# Render this resource to a string with the appropriate layout.
|
29
|
+
# Called automatically by Middleman.
|
29
30
|
# @return [String]
|
30
31
|
def render(opts={}, locs={}, &block)
|
31
32
|
if opts[:layout].nil?
|
32
|
-
|
33
|
-
opts[:layout] = metadata[:options][:layout]
|
34
|
-
end
|
33
|
+
opts[:layout] = metadata[:options][:layout]
|
35
34
|
opts[:layout] = blog_options.layout if opts[:layout].nil?
|
35
|
+
# Convert to a string unless it's a boolean
|
36
36
|
opts[:layout] = opts[:layout].to_s if opts[:layout].is_a? Symbol
|
37
37
|
end
|
38
38
|
|
39
39
|
content = super(opts, locs, &block)
|
40
40
|
|
41
41
|
unless opts[:keep_separator]
|
42
|
-
|
43
|
-
content.sub!(blog_options.summary_separator, "")
|
44
|
-
end
|
42
|
+
content.sub!(blog_options.summary_separator, "")
|
45
43
|
end
|
46
44
|
|
47
45
|
content
|
48
46
|
end
|
49
47
|
|
50
|
-
# The title of the article, set from frontmatter
|
48
|
+
# The title of the article, set from frontmatter.
|
51
49
|
# @return [String]
|
52
50
|
def title
|
53
51
|
data["title"]
|
54
52
|
end
|
55
53
|
|
56
|
-
# Whether or not this article has been published
|
54
|
+
# Whether or not this article has been published.
|
57
55
|
#
|
58
56
|
# An article is considered published in the following scenarios:
|
59
57
|
#
|
60
|
-
# 1.
|
61
|
-
# 2. published_future_dated is true or
|
62
|
-
# 3. article date is after the current time
|
58
|
+
# 1. Frontmatter does not set +published+ to false and either
|
59
|
+
# 2. The blog option +published_future_dated+ is true or
|
60
|
+
# 3. The article's date is after the current time
|
63
61
|
# @return [Boolean]
|
64
62
|
def published?
|
65
|
-
|
66
|
-
(blog_options.publish_future_dated || date <= Time.current)
|
63
|
+
data["published"] != false && (blog_options.publish_future_dated || date <= Time.current)
|
67
64
|
end
|
68
65
|
|
69
|
-
# The body of this article, in HTML. This is for
|
66
|
+
# The body of this article, in HTML (no layout). This is for
|
70
67
|
# things like RSS feeds or lists of articles - individual
|
71
68
|
# articles will automatically be rendered from their
|
72
69
|
# template.
|
73
70
|
# @return [String]
|
74
71
|
def body
|
75
|
-
render
|
72
|
+
render layout: false
|
76
73
|
end
|
77
74
|
|
78
75
|
# The summary for this article, in HTML. The summary is either
|
79
|
-
# everything before the summary separator (set via
|
80
|
-
# and defaulting to "READMORE") or the first
|
81
|
-
# characters of the post.
|
76
|
+
# everything before the summary separator (set via the blog option
|
77
|
+
# +summary_separator+ and defaulting to "READMORE") or the first
|
78
|
+
# +summary_length+ characters of the post.
|
82
79
|
#
|
83
|
-
#
|
84
|
-
# custom summary generation. The Proc is provided
|
85
|
-
#
|
80
|
+
# The blog option +summary_generator+ can be set to a +Proc+ in order to provide
|
81
|
+
# custom summary generation. The +Proc+ is provided
|
82
|
+
# the rendered content of the article (without layout), the
|
86
83
|
# desired length to trim the summary to, and the ellipsis string to use.
|
84
|
+
# Otherwise the {#default_summary_generator} will be used.
|
87
85
|
#
|
88
86
|
# @param [Number] length How many characters to trim the summary to.
|
89
87
|
# @param [String] ellipsis The ellipsis string to use when content is trimmed.
|
90
88
|
# @return [String]
|
91
89
|
def summary(length=blog_options.summary_length, ellipsis='...')
|
92
|
-
rendered = render
|
90
|
+
rendered = render layout: false, keep_separator: true
|
93
91
|
|
94
92
|
if blog_options.summary_separator && rendered.match(blog_options.summary_separator)
|
95
93
|
rendered.split(blog_options.summary_separator).first
|
@@ -100,12 +98,18 @@ module Middleman
|
|
100
98
|
end
|
101
99
|
end
|
102
100
|
|
101
|
+
# The default summary generator first tries to find the +summary_separator+ and
|
102
|
+
# take the text before it. If that doesn't work, it will truncate text without splitting
|
103
|
+
# the middle of an HTML tag, using a Nokogiri-based {TruncateHTML} utility.
|
104
|
+
#
|
105
|
+
# @param [String] rendered The rendered blog article
|
106
|
+
# @param [Integer] length The length in characters to truncate to.
|
107
|
+
# -1 or +nil+ will return the whole article.
|
103
108
|
def default_summary_generator(rendered, length, ellipsis)
|
104
|
-
|
105
|
-
|
106
|
-
if rendered =~ blog_options.summary_separator
|
109
|
+
if blog_options.summary_separator && rendered =~ blog_options.summary_separator
|
107
110
|
rendered.split(blog_options.summary_separator).first
|
108
|
-
elsif length
|
111
|
+
elsif length && length >= 0
|
112
|
+
require 'middleman-blog/truncate_html'
|
109
113
|
TruncateHTML.truncate_html(rendered, length, ellipsis)
|
110
114
|
else
|
111
115
|
rendered
|
@@ -113,23 +117,39 @@ module Middleman
|
|
113
117
|
end
|
114
118
|
|
115
119
|
# A list of tags for this article, set from frontmatter.
|
116
|
-
# @return [Array<String>] (never nil)
|
120
|
+
# @return [Array<String>] (never +nil+)
|
117
121
|
def tags
|
118
122
|
article_tags = data["tags"]
|
119
123
|
|
120
124
|
if article_tags.is_a? String
|
121
125
|
article_tags.split(',').map(&:strip)
|
122
126
|
else
|
123
|
-
article_tags
|
127
|
+
Array(article_tags)
|
124
128
|
end
|
125
129
|
end
|
126
130
|
|
127
|
-
#
|
128
|
-
#
|
129
|
-
#
|
130
|
-
|
131
|
-
|
132
|
-
|
131
|
+
# The language of the article. The language can be present in the
|
132
|
+
# frontmatter or in the source path. If both are present, they
|
133
|
+
# must match. If neither specifies a lang, I18n's default_locale will
|
134
|
+
# be used. If +lang+ is set to nil, or the +:i18n+ extension is not
|
135
|
+
# activated at all, +nil+ will be returned.
|
136
|
+
#
|
137
|
+
# @return [Symbol] Language code (for example, +:en+ or +:de+)
|
138
|
+
def lang
|
139
|
+
frontmatter_lang = data["lang"]
|
140
|
+
|
141
|
+
if blog_options.sources.include? ":lang"
|
142
|
+
filename_lang = path_part("lang")
|
143
|
+
end
|
144
|
+
|
145
|
+
if frontmatter_lang && filename_lang && frontmatter_lang != filename_lang
|
146
|
+
raise "The lang in #{path}'s filename (#{filename_lang.inspect}) doesn't match the lang in its frontmatter (#{frontmatter_lang.inspect})"
|
147
|
+
end
|
148
|
+
|
149
|
+
locale_lang = I18n.default_locale if defined? I18n
|
150
|
+
|
151
|
+
lang = frontmatter_lang || filename_lang || locale_lang
|
152
|
+
lang && lang.to_sym
|
133
153
|
end
|
134
154
|
|
135
155
|
# Attempt to figure out the date of the post. The date should be
|
@@ -141,7 +161,7 @@ module Middleman
|
|
141
161
|
def date
|
142
162
|
return @_date if @_date
|
143
163
|
|
144
|
-
frontmatter_date = data[
|
164
|
+
frontmatter_date = data['date']
|
145
165
|
|
146
166
|
# First get the date from frontmatter
|
147
167
|
if frontmatter_date.is_a? Time
|
@@ -151,11 +171,12 @@ module Middleman
|
|
151
171
|
end
|
152
172
|
|
153
173
|
# Next figure out the date from the filename
|
154
|
-
|
155
|
-
|
156
|
-
|
174
|
+
source_vars = blog_data.source_template.variables
|
175
|
+
if source_vars.include?('year') &&
|
176
|
+
source_vars.include?('month') &&
|
177
|
+
source_vars.include?('day')
|
157
178
|
|
158
|
-
filename_date = Time.zone.local(path_part(
|
179
|
+
filename_date = Time.zone.local(path_part('year').to_i, path_part('month').to_i, path_part('day').to_i)
|
159
180
|
if @_date
|
160
181
|
raise "The date in #{path}'s filename doesn't match the date in its frontmatter" unless @_date.to_date == filename_date.to_date
|
161
182
|
else
|
@@ -168,37 +189,52 @@ module Middleman
|
|
168
189
|
@_date
|
169
190
|
end
|
170
191
|
|
171
|
-
# The "slug" of the article that shows up in its URL.
|
192
|
+
# The "slug" of the article that shows up in its URL. The article slug
|
193
|
+
# is a parameterized version of the {#title} (lowercase, spaces replaced
|
194
|
+
# with dashes, etc) and can be used in the blog +permalink+ as +:title+.
|
195
|
+
#
|
172
196
|
# @return [String]
|
173
197
|
def slug
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
path_part(
|
198
|
+
if data['slug']
|
199
|
+
data['slug']
|
200
|
+
elsif blog_data.source_template.variables.include?('title')
|
201
|
+
path_part('title')
|
178
202
|
elsif title
|
179
|
-
title
|
203
|
+
Blog::UriTemplates.safe_parameterize(title)
|
180
204
|
else
|
181
205
|
raise "Can't generate a slug for #{path} because it has no :title in its path pattern or title/slug in its frontmatter."
|
182
206
|
end
|
183
207
|
end
|
184
208
|
|
185
209
|
# The previous (chronologically earlier) article before this one
|
186
|
-
# or nil if this is the first article.
|
187
|
-
# @return [
|
210
|
+
# or +nil+ if this is the first article.
|
211
|
+
# @return [BlogArticle]
|
188
212
|
def previous_article
|
189
213
|
blog_data.articles.find {|a| a.date < self.date }
|
190
214
|
end
|
191
215
|
|
192
216
|
# The next (chronologically later) article after this one
|
193
|
-
# or nil if this is the most recent article.
|
217
|
+
# or +nil+ if this is the most recent article.
|
194
218
|
# @return [Middleman::Sitemap::Resource]
|
195
219
|
def next_article
|
196
220
|
blog_data.articles.reverse.find {|a| a.date > self.date }
|
197
221
|
end
|
198
222
|
|
223
|
+
# This is here to prevent out-of-memory on exceptions.
|
224
|
+
# @private
|
199
225
|
def inspect
|
200
226
|
"#<Middleman::Blog::BlogArticle: #{data.inspect}>"
|
201
227
|
end
|
228
|
+
|
229
|
+
private
|
230
|
+
|
231
|
+
# Retrieve a section of the source path template.
|
232
|
+
# @param [String] part The part of the path, e.g. "lang", "year", "month", "day", "title"
|
233
|
+
# @return [String]
|
234
|
+
def path_part(part)
|
235
|
+
@_path_parts ||= blog_data.source_template.extract(path)
|
236
|
+
@_path_parts[part.to_s]
|
237
|
+
end
|
202
238
|
end
|
203
239
|
end
|
204
240
|
end
|
@@ -1,16 +1,16 @@
|
|
1
|
+
require 'middleman-blog/uri_templates'
|
2
|
+
|
1
3
|
module Middleman
|
2
4
|
module Blog
|
3
5
|
# A store of all the blog articles in the site, with accessors
|
4
6
|
# for the articles by various dimensions. Accessed via "blog" in
|
5
7
|
# templates.
|
6
8
|
class BlogData
|
7
|
-
|
8
|
-
# @return [Regex]
|
9
|
-
attr_reader :path_matcher
|
9
|
+
include UriTemplates
|
10
10
|
|
11
|
-
# A
|
12
|
-
# @return [
|
13
|
-
attr_reader :
|
11
|
+
# A URITemplate for the source file path relative to :source_dir
|
12
|
+
# @return [URITemplate]
|
13
|
+
attr_reader :source_template
|
14
14
|
|
15
15
|
# The configured options for this blog
|
16
16
|
# @return [Thor::CoreExt::HashWithIndifferentAccess]
|
@@ -18,10 +18,8 @@ module Middleman
|
|
18
18
|
|
19
19
|
attr_reader :controller
|
20
20
|
|
21
|
-
DEFAULT_PERMALINK_COMPONENTS = [:year, :month, :day, :title]
|
22
|
-
|
23
21
|
# @private
|
24
|
-
def initialize(app,
|
22
|
+
def initialize(app, controller, options)
|
25
23
|
@app = app
|
26
24
|
@options = options
|
27
25
|
@controller = controller
|
@@ -29,26 +27,10 @@ module Middleman
|
|
29
27
|
# A list of resources corresponding to blog articles
|
30
28
|
@_articles = []
|
31
29
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
gsub(":day", "(\\d{2})").
|
37
|
-
sub(":title", "([^/]+)")
|
38
|
-
|
39
|
-
subdir_matcher = matcher.sub(/\\\.[^.]+$/, "(/.*)$")
|
40
|
-
|
41
|
-
@path_matcher = /^#{matcher}/
|
42
|
-
@subdir_matcher = /^#{subdir_matcher}/
|
43
|
-
|
44
|
-
# Build a hash of part name to capture index, e.g. {"year" => 0}
|
45
|
-
@matcher_indexes = {}
|
46
|
-
options.sources.scan(/:year|:month|:day|:title/).
|
47
|
-
each_with_index do |key, i|
|
48
|
-
@matcher_indexes[key[1..-1]] = i
|
49
|
-
end
|
50
|
-
# The path always appears at the end.
|
51
|
-
@matcher_indexes["path"] = @matcher_indexes.size
|
30
|
+
@source_template = uri_template options.sources
|
31
|
+
@permalink_template = uri_template options.permalink
|
32
|
+
@subdir_template = uri_template options.sources.sub(/\.[^.]+$/, "/{+path}")
|
33
|
+
@subdir_permalink_template = uri_template options.permalink.sub(/\.[^.]+$/, "/{+path}")
|
52
34
|
end
|
53
35
|
|
54
36
|
# A list of all blog articles, sorted by descending date
|
@@ -57,15 +39,15 @@ module Middleman
|
|
57
39
|
@_articles.sort_by(&:date).reverse
|
58
40
|
end
|
59
41
|
|
60
|
-
#
|
61
|
-
#
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
42
|
+
# A list of all blog articles with the given language,
|
43
|
+
# sorted by descending date
|
44
|
+
#
|
45
|
+
# @param [Symbol] lang Language to match (optional, defaults to I18n.locale).
|
46
|
+
# @return [Array<Middleman::Sitemap::Resource>]
|
47
|
+
def local_articles(lang=nil)
|
48
|
+
lang ||= I18n.locale
|
49
|
+
lang = lang.to_sym if lang.kind_of? String
|
50
|
+
articles.select {|article| article.lang == lang }
|
69
51
|
end
|
70
52
|
|
71
53
|
# Returns a map from tag name to an array
|
@@ -80,6 +62,7 @@ module Middleman
|
|
80
62
|
end
|
81
63
|
end
|
82
64
|
|
65
|
+
# Sort each tag's list of articles
|
83
66
|
tags.each do |tag, articles|
|
84
67
|
tags[tag] = articles.sort_by(&:date).reverse
|
85
68
|
end
|
@@ -95,43 +78,40 @@ module Middleman
|
|
95
78
|
used_resources = []
|
96
79
|
|
97
80
|
resources.each do |resource|
|
98
|
-
if resource.path
|
99
|
-
resource
|
81
|
+
if (params = @source_template.extract(resource.path))
|
82
|
+
article = convert_to_article(resource)
|
83
|
+
next unless publishable?(article)
|
100
84
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
# Skip articles that are not published (in non-development environments)
|
106
|
-
next unless @app.environment == :development || resource.published?
|
85
|
+
# Add extra parameters from the URL to the page metadata
|
86
|
+
extra_data = params.except *%w(year month day title lang)
|
87
|
+
article.add_metadata page: extra_data unless extra_data.empty?
|
107
88
|
|
108
89
|
# compute output path:
|
109
90
|
# substitute date parts to path pattern
|
110
|
-
|
91
|
+
article.destination_path = template_path @permalink_template, article
|
111
92
|
|
112
|
-
@_articles <<
|
93
|
+
@_articles << article
|
113
94
|
|
114
|
-
elsif resource.path
|
115
|
-
|
95
|
+
elsif (params = @subdir_template.extract(resource.path))
|
96
|
+
# It's not an article, but it's thhe companion files for an article
|
97
|
+
# (in a subdirectory named after the article)
|
98
|
+
# figure out the matching article for this subdirectory file
|
116
99
|
|
117
|
-
article_path =
|
118
|
-
%w(year month day title).each do |token|
|
119
|
-
article_path = article_path.sub(":#{token}", match[@matcher_indexes[token]]) if @matcher_indexes[token]
|
120
|
-
end
|
100
|
+
article_path = @source_template.expand(params).to_s
|
121
101
|
|
122
102
|
article = @app.sitemap.find_resource_by_path(article_path)
|
123
103
|
raise "Article for #{resource.path} not found" if article.nil?
|
124
|
-
article.extend BlogArticle
|
125
104
|
|
126
|
-
#
|
127
|
-
|
105
|
+
# The article may not yet have been processed, so convert it here.
|
106
|
+
article = convert_to_article(article)
|
107
|
+
next unless publishable?(article)
|
128
108
|
|
129
109
|
# The subdir path is the article path with the index file name
|
130
110
|
# or file extension stripped off.
|
131
|
-
|
132
|
-
|
111
|
+
path = params.fetch('path')
|
112
|
+
new_destination_path = template_path @subdir_permalink_template, article, path: path
|
133
113
|
|
134
|
-
resource.destination_path = Middleman::Util.normalize_path(
|
114
|
+
resource.destination_path = Middleman::Util.normalize_path(new_destination_path)
|
135
115
|
end
|
136
116
|
|
137
117
|
used_resources << resource
|
@@ -140,30 +120,52 @@ module Middleman
|
|
140
120
|
used_resources
|
141
121
|
end
|
142
122
|
|
143
|
-
def
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
123
|
+
def inspect
|
124
|
+
"#<Middleman::Blog::BlogData: #{articles.inspect}>"
|
125
|
+
end
|
126
|
+
|
127
|
+
# Whether or not a given article should be included in the sitemap.
|
128
|
+
# Skip articles that are not published unless the environment is +:development+.
|
129
|
+
# @param [BlogArticle] article A blog article
|
130
|
+
# @return [Boolean] whether it should be published
|
131
|
+
def publishable?(article)
|
132
|
+
@app.environment == :development || article.published?
|
133
|
+
end
|
149
134
|
|
150
|
-
|
151
|
-
|
135
|
+
private
|
136
|
+
|
137
|
+
# Generate a hash of options for substituting into the permalink URL template.
|
138
|
+
# @param [Sitemap::Resource] resource The resource to generate options for.
|
139
|
+
# @param [Hash] extra More options to be merged in on top.
|
140
|
+
# @return [Hash] options
|
141
|
+
def permalink_options(resource, extra={})
|
142
|
+
# Allow any frontmatter data to be substituted into the permalink URL
|
143
|
+
params = resource.metadata[:page].slice *@permalink_template.variables
|
144
|
+
params.each do |k, v|
|
145
|
+
params[k] = safe_parameterize(v)
|
152
146
|
end
|
153
147
|
|
154
|
-
|
148
|
+
params.
|
149
|
+
merge(date_to_params(resource.date)).
|
150
|
+
merge(lang: resource.lang.to_s, title: resource.slug).
|
151
|
+
merge(extra)
|
155
152
|
end
|
156
153
|
|
157
|
-
def
|
158
|
-
|
159
|
-
end
|
154
|
+
def convert_to_article(resource)
|
155
|
+
return resource if resource.is_a?(BlogArticle)
|
160
156
|
|
161
|
-
|
162
|
-
|
157
|
+
resource.extend BlogArticle
|
158
|
+
resource.blog_controller = controller
|
159
|
+
|
160
|
+
if !options.preserve_locale && (lang = resource.lang)
|
161
|
+
resource.add_metadata options: { lang: lang }, locals: { lang: lang }
|
162
|
+
end
|
163
|
+
|
164
|
+
resource
|
163
165
|
end
|
164
166
|
|
165
|
-
def
|
166
|
-
|
167
|
+
def template_path(template, article, extras={})
|
168
|
+
apply_uri_template template, permalink_options(article, extras)
|
167
169
|
end
|
168
170
|
end
|
169
171
|
end
|