jekyll-paginate-content 1.0.2 → 1.0.3

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.
@@ -0,0 +1,33 @@
1
+ module Jekyll
2
+ module Paginate::Content
3
+
4
+ class Document < Jekyll::Document
5
+ attr_accessor :pager
6
+
7
+ def initialize(orig_doc, site, collection)
8
+ super(orig_doc.path, { :site => site,
9
+ :collection => site.collections[collection]})
10
+ self.merge_data!(orig_doc.data)
11
+ end
12
+
13
+ def data
14
+ @data ||= {}
15
+ end
16
+
17
+ end
18
+
19
+ class Page < Jekyll::Page
20
+ def initialize(orig_page, site, dirname, filename)
21
+ @site = site
22
+ @base = site.source
23
+ @dir = dirname
24
+ @name = filename
25
+
26
+ self.process(filename)
27
+ self.data ||= {}
28
+ self.data.merge!(orig_page.data)
29
+ end
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,162 @@
1
+ module Jekyll
2
+ module Paginate::Content
3
+ class Generator < Jekyll::Generator
4
+ safe true
5
+
6
+ def generate(site)
7
+ start_time = Time.now
8
+
9
+ sconfig = site.config['paginate_content'] || {}
10
+
11
+ return unless sconfig["enabled"].nil? || sconfig["enabled"]
12
+
13
+ @debug = sconfig["debug"]
14
+
15
+ sconfig['collection'] = sconfig['collection'].split(/,\s*/) if sconfig['collection'].is_a?(String)
16
+
17
+ collections = [ sconfig['collection'], sconfig["collections"] ].flatten.compact.uniq;
18
+ collections = [ "posts", "pages" ] if collections.empty?
19
+
20
+ # Use this hash syntax to facilite merging _config.yml overrides
21
+ properties = {
22
+ 'all' => {
23
+ 'autogen' => 'jekyll-paginate-content',
24
+ 'hidden' => true,
25
+ 'tag' => nil,
26
+ 'tags' => nil,
27
+ 'category' => nil,
28
+ 'categories'=> nil
29
+ },
30
+
31
+ 'first' => {
32
+ 'hidden' => false,
33
+ 'tag' => '$',
34
+ 'tags' => '$',
35
+ 'category' => '$',
36
+ 'categories'=> '$'
37
+ },
38
+
39
+ 'part' => {},
40
+
41
+ 'last' => {},
42
+
43
+ 'single' => {}
44
+ }
45
+
46
+ base_url = (sconfig['prepend_baseurl'].nil? || sconfig['prepend_baseurl']) ? site.config['baseurl'] : ''
47
+
48
+ @config = {
49
+ :collections => collections,
50
+ :title => sconfig['title'],
51
+ :permalink => sconfig['permalink'] || '/:num/',
52
+ :trail => sconfig['trail'] || {},
53
+ :auto => sconfig['auto'],
54
+ :base_url => base_url,
55
+
56
+ :separator => sconfig['separator'] || '<!--page-->',
57
+ :header => sconfig['header'] || '<!--page_header-->',
58
+ :footer => sconfig['footer'] || '<!--page_footer-->',
59
+
60
+ :single_page => sconfig['single_page'] || '/view-all/',
61
+ :seo_canonical => sconfig['seo_canonical'].nil? || sconfig['seo_canonical'],
62
+ :toc_exclude => sconfig['toc_exclude'],
63
+
64
+ :properties => properties,
65
+ :user_props => sconfig['properties'] || {}
66
+ }
67
+
68
+ # Run through each specified collection
69
+
70
+ total_skipped = 0
71
+ total_single = 0
72
+
73
+ collections.each do |collection|
74
+ if collection == "pages"
75
+ items = site.pages
76
+ else
77
+ next if !site.collections.has_key?(collection)
78
+ items = site.collections[collection].docs
79
+ end
80
+
81
+ new_items = []
82
+ old_items = []
83
+
84
+ total_parts = 0
85
+ total_copies = 0
86
+
87
+ if @config[:auto]
88
+ if m = /^h(\d)/i.match(@config[:separator])
89
+ process = items.select { |item| /(\n|)(<h#{m[1]}|-{4,}|={4,})/.match?(item.content) }
90
+ else
91
+ process = items.select { |item| item.content.include?(@config[:separator]) }
92
+ end
93
+ else
94
+ process = items.select { |item| item.data['paginate'] }
95
+ end
96
+
97
+ process.each do |item|
98
+ paginator = Paginator.new(site, collection, item, @config)
99
+ if paginator.skipped
100
+ debug "[#{collection}] \"#{item.data['title']}\" skipped"
101
+ total_skipped += 1
102
+
103
+ elsif paginator.items.empty?
104
+ total_single += 1
105
+ debug "[#{collection}] \"#{item.data['title']}\" is a single page"
106
+ end
107
+
108
+ next if paginator.items.empty?
109
+
110
+ debug "[#{collection}] \"#{item.data['title']}\", #{paginator.items.length-1}+1 pages"
111
+ total_parts += paginator.items.length-1;
112
+ total_copies += 1
113
+ new_items << paginator.items
114
+ old_items << item
115
+ end
116
+
117
+ if !new_items.empty?
118
+ # Remove the old items at the original URLs
119
+ old_items.each do |item|
120
+ items.delete(item)
121
+ end
122
+
123
+ # Add the new items in
124
+ new_items.flatten!.each do |new_item|
125
+ items << new_item
126
+ end
127
+
128
+ info "[#{collection}] Generated #{total_parts}+#{total_copies} pages"
129
+ end
130
+ end
131
+
132
+ if total_skipped > 0
133
+ s = (total_skipped == 1 ? '' : 's')
134
+ info "Skipped #{total_skipped} unchanged item#{s}"
135
+ end
136
+
137
+ if total_single > 0
138
+ s = (total_single == 1 ? '' : 's')
139
+ info "#{total_single} page#{s} could not be split"
140
+ end
141
+
142
+ runtime = "%.6f" % (Time.now - start_time).to_f
143
+ debug "Runtime: #{runtime}s"
144
+ end
145
+
146
+ private
147
+ def info(msg)
148
+ Jekyll.logger.info "PaginateContent:", msg
149
+ end
150
+
151
+ def warn(msg)
152
+ Jekyll.logger.warn "PaginateContent:", msg
153
+ end
154
+
155
+ def debug(msg)
156
+ Jekyll.logger.warn "PaginateContent:", msg if @debug
157
+ end
158
+ end
159
+
160
+
161
+ end
162
+ end
@@ -0,0 +1,72 @@
1
+ module Jekyll
2
+ module Paginate::Content
3
+
4
+ class Pager
5
+ attr_accessor :activated, :first_page, :first_page_path,
6
+ :first_path, :has_next, :has_prev, :has_previous,
7
+ :is_first, :is_last, :last_page, :last_page_path,
8
+ :last_path, :next_is_last, :next_page, :next_page_path,
9
+ :next_path, :next_section, :page, :page_num, :page_path,
10
+ :page_trail, :pages, :paginated, :previous_is_first,
11
+ :prev_is_first, :previous_page, :prev_page, :previous_page_path,
12
+ :previous_path, :prev_path, :prev_section, :previous_section,
13
+ :section, :seo, :single_page, :toc, :total_pages, :view_all
14
+
15
+ def initialize(data)
16
+ data.each do |k,v|
17
+ instance_variable_set("@#{k}", v) if self.respond_to? k
18
+ end
19
+ end
20
+
21
+ def to_liquid
22
+ {
23
+ # Based on sverrir's jpv2
24
+ 'first_page' => first_page,
25
+ 'first_page_path' => first_page_path,
26
+ 'last_page' => last_page,
27
+ 'last_page_path' => last_page_path,
28
+ 'next_page' => next_page,
29
+ 'next_page_path' => next_page_path,
30
+ 'page' => page_num,
31
+ 'page_path' => page_path,
32
+ 'page_trail' => page_trail,
33
+ 'previous_page' => previous_page,
34
+ 'previous_page_path' => previous_page_path,
35
+ 'total_pages' => total_pages, # parts of the original page
36
+
37
+ # New stuff
38
+ 'has_next' => has_next,
39
+ 'has_previous' => has_previous,
40
+ 'is_first' => is_first,
41
+ 'is_last' => is_last,
42
+ 'next_is_last' => next_is_last,
43
+ 'previous_is_first' => previous_is_first,
44
+ 'paginated' => paginated,
45
+ 'seo' => seo,
46
+ 'single_page' => single_page,
47
+ 'section' => section,
48
+ 'toc' => toc,
49
+ 'next_section' => next_section,
50
+ 'previous_section' => previous_section,
51
+
52
+ # Aliases
53
+ 'activated' => paginated,
54
+ 'first_path' => first_page_path,
55
+ 'next_path' => next_page_path,
56
+ 'has_prev' => has_previous,
57
+ 'previous_path' => previous_page_path,
58
+ 'prev_path' => previous_page_path,
59
+ 'last_path' => last_page_path,
60
+ 'prev_page' => previous_page,
61
+ 'prev_is_first' => previous_is_first,
62
+ 'prev_section' => previous_section,
63
+ 'page_num' => page_num,
64
+ 'pages' => total_pages,
65
+ 'view_all' => single_page
66
+ }
67
+ end
68
+ end
69
+
70
+ end
71
+ end
72
+
@@ -0,0 +1,575 @@
1
+ module Jekyll
2
+ module Paginate::Content
3
+
4
+ class Paginator
5
+ attr_accessor :skipped
6
+
7
+ def initialize(site, collection, item, config)
8
+ @site = site
9
+ @collection = collection
10
+ @items = []
11
+ @skipped = false
12
+
13
+ source_prefix = item.is_a?(Jekyll::Page) ? site.source : ''
14
+ source = File.join(source_prefix, item.path)
15
+ html = item.destination('')
16
+
17
+ final_config = {}.merge(config)
18
+ if item.data.has_key?('paginate_content')
19
+ item.data['paginate_content'].each do |k,v|
20
+ s = k.downcase.strip.to_sym
21
+ final_config[s] = v
22
+ end
23
+ end
24
+ @config = final_config
25
+
26
+ if @config[:force] || (!File.exist?(html) || (File.mtime(html) < File.mtime(source)))
27
+ self.split(item)
28
+ else
29
+ @skipped = true
30
+ end
31
+ end
32
+
33
+ def items
34
+ @items
35
+ end
36
+
37
+ def split(item)
38
+ sep = @config[:separator].downcase.strip
39
+ # Update the header IDs the original document
40
+ content = item.content
41
+
42
+ # Escape special characters inside code blocks
43
+ content.scan(/(```|~~~+)(.*?)\1/m).each do |e|
44
+ escaped = e[1].gsub(/([#<\-=])/, '~|\1|')
45
+ content.gsub!(e[1], escaped)
46
+ end
47
+
48
+ # Generate TOC
49
+ toc = ""
50
+
51
+ seen_anchors = {}
52
+ list_chars = ['-','*','+']
53
+
54
+ if m = /^h([1-6])$/.match(sep)
55
+ base_level = m[1].to_i - 1
56
+ else
57
+ base_level = 5
58
+ end
59
+
60
+ lowest_level = 5
61
+
62
+ # TODO: Optimize this regex
63
+ content.scan(/(^|\r?\n)((#+)\s*([^\r\n#]+)#*\r?\n|([^\r\n]+)\r?\n(=+|\-{4,})\s*\r?\n|<h([1-6])[^>]*>([^\r\n<]+)(\s*<\/h\7>))/mi).each do |m|
64
+ header = m[3] || m[4] || m[7]
65
+
66
+ next if @config[:toc_exclude] && @config[:toc_exclude].include?(header)
67
+
68
+ markup = m[1].strip
69
+
70
+ # Level is 0-based for convenience
71
+ if m[3]
72
+ level = m[2].length - 1
73
+ elsif m[4]
74
+ level = m[5][0] == '=' ? 0 : 1
75
+ elsif m[7]
76
+ level = m[6].to_i - 1
77
+ end
78
+
79
+ lowest_level = [level, lowest_level].min
80
+
81
+ orig_anchor = anchor = header.downcase.gsub(/[[:punct:]]/, '').gsub(/\s+/, '-')
82
+
83
+ ctr = 1
84
+ while seen_anchors[anchor]
85
+ anchor = "#{orig_anchor}-#{ctr}"
86
+ ctr += 1
87
+ end
88
+ seen_anchors[anchor] = 1
89
+
90
+ # Escape the header so we don't match again
91
+ # for the same header text in a different location
92
+ escaped = Regexp.escape(markup)
93
+ markup = "$$_#{markup}_$$"
94
+
95
+ content.sub!(/#{escaped}\s*(?=#|\r?\n)/, "#{markup}#{$/}{: id=\"#{anchor}\"}#{$/}")
96
+
97
+ # Markdown indent
98
+ char = list_chars[level % 3]
99
+ indent = ' ' * level
100
+ toc << "#{indent}#{char} [#{header}](##{anchor})#{$/}"
101
+ end
102
+
103
+ if lowest_level > 0
104
+ excess = ' ' * lowest_level
105
+ toc.gsub!(/^#{excess}/, '')
106
+ end
107
+
108
+ # Restore original header text
109
+ content.gsub!(/\$\$_(.*?)_\$\$/m, '\1')
110
+
111
+ @toc = toc.empty? ? nil : toc
112
+
113
+ # Handle splitting by headers, h1-h6
114
+ if m = /^h([1-6])$/.match(sep)
115
+ # Split on <h2> etc.
116
+
117
+ level = m[1].to_i
118
+
119
+ init_pages = []
120
+
121
+ # atx syntax: Prefixed by one or more '#'
122
+ atx = "#" * level
123
+ atx_parts = content.split(/(?=^#{atx} )/)
124
+
125
+ # HTML symtax <h1> to <h6>
126
+ htx_parts = []
127
+ atx_parts.each do |section|
128
+ htx_parts << section.split(/(?=<#{sep}[^>]*>)/i)
129
+ end
130
+ htx_parts.flatten!
131
+
132
+ if level <= 2
133
+ # Setext syntax: underlined by '=' (h1) or '-' (h2)
134
+ # For now require four '-' to avoid confusion with <hr>
135
+ # or demo YAML front-matter
136
+ stx = level == 1 ? "=" : '-' * 4
137
+ htx_parts.each do |section|
138
+ init_pages << section.split(/(?=^.+\n#{stx}+$)/)
139
+ end
140
+
141
+ else
142
+ init_pages = htx_parts
143
+ end
144
+
145
+ init_pages.flatten!
146
+ else
147
+ init_pages = content.split(sep)
148
+ end
149
+
150
+ return if init_pages.length == 1
151
+
152
+ # Unescape special characters inside code blocks, for main content
153
+ # Main content was modified by adding header IDs
154
+ content.gsub!(/~\|(.)\|/, '\1')
155
+
156
+ # Make page length the minimum, if specified
157
+ if @config[:minimum]
158
+ pages = []
159
+ init_pages.each do |page_content|
160
+ i = pages.empty? ? 0 : pages.length - 1
161
+ if !pages[i] || pages[i].length < @config[:minimum]
162
+ pages[i] ||= ""
163
+ pages[i] << page_content
164
+ else
165
+ pages << page_content
166
+ i += 1
167
+ end
168
+ end
169
+
170
+ else
171
+ pages = init_pages
172
+ end
173
+
174
+ page_header = pages[0].split(@config[:header])
175
+ pages[0] = page_header[1] || page_header[0]
176
+ header = page_header[1] ? page_header[0] : ''
177
+
178
+ page_footer = pages[-1].split(@config[:footer])
179
+ pages[-1] = page_footer[0]
180
+ footer = page_footer[1] || ''
181
+
182
+ new_items = []
183
+ page_data = {}
184
+
185
+ dirname = ""
186
+ filename = ""
187
+
188
+ # For SEO; 'canonical' is a personal override ;-)
189
+ site_url = (@site.config['canonical'] || @site.config['url']) + @site.config['baseurl']
190
+ site_url.gsub!(/\/$/, '')
191
+
192
+ # For the permalink
193
+ base = item.url
194
+
195
+ user_props = @config[:user_props]
196
+
197
+ first_page_path = ''
198
+ total_pages = 0
199
+ single_page = ''
200
+ id = ("%10.9f" % Time.now.to_f).to_s
201
+
202
+ num = 1
203
+ max = pages.length
204
+
205
+ # Find the anchors/targets
206
+ a_locations = {}
207
+ i = 1
208
+ pages.each do |page|
209
+ # TODO: Optimize this regex
210
+ page.scan(/<a\s+name=['"](\S+)['"]>[^<]*<\/a>|<[^>]*id=['"](\S+)['"][^>]*>|{:.*id=['"](\S+)['"][^}]*}/i).each do |a|
211
+ anchor = a[0] || a[1] || a[2]
212
+ a_locations[anchor] = i
213
+ end
214
+ i += 1
215
+ end
216
+
217
+ ######################################## Main processing
218
+
219
+ pages.each do |page|
220
+ # Unescape special characters inside code blocks, for pages
221
+ page.gsub!(/~\|(.)\|/, '\1')
222
+
223
+ plink_all = nil
224
+ plink_next = nil
225
+ plink_prev = nil
226
+
227
+ paginator = {}
228
+
229
+ first = num == 1
230
+ last = num == max
231
+
232
+ if m = base.match(/(.*\/[^\.]*)(\.[^\.]+)$/)
233
+ # /.../filename.ext
234
+ plink = _permalink(m[1], num, max)
235
+ plink_all = m[1] + @config[:single_page]
236
+ plink_prev = _permalink(m[1], num-1, max) if !first
237
+ plink_next = _permalink(m[1],num+1, max) if !last
238
+ else
239
+ # /.../folder/
240
+ plink = _permalink(base, num, max)
241
+ plink_all = base + @config[:single_page]
242
+ plink_prev = _permalink(base, num-1, max) if !first
243
+ plink_next = _permalink(base, num+1, max) if !last
244
+ end
245
+
246
+ plink_all.gsub!(/\/\//,'/')
247
+
248
+ # TODO: Put these in classes
249
+
250
+ if @collection == "pages"
251
+ if first
252
+ # Keep the info of the original page to avoid warnings
253
+ # while creating the new virtual pages
254
+ dirname = File.dirname(plink)
255
+ filename = item.name
256
+ page_data = item.data
257
+ end
258
+
259
+ paginator.merge!(page_data)
260
+ new_part = Page.new(item, @site, dirname, filename)
261
+ else
262
+ new_part = Document.new(item, @site, @collection)
263
+ end
264
+
265
+ # Find the section names from the first h1 etc.
266
+ # TODO: Simplify/merge regex
267
+ candidates = {}
268
+ if m = /(.*\r?\n|)#+\s+(.*)\s*#*/.match(page)
269
+ candidates[m[2]] = m[1].length
270
+ end
271
+
272
+ if m = /(.*\r?\n|)([^\r\n]+)\r?\n(=+|\-{4,})\s*\r?\n/.match(page)
273
+ candidates[m[2]] = m[1].length
274
+ end
275
+
276
+ if m = /<h([1-6])[^>]*>\s*([^\r\n<]+)(\s*<\/h\1)/mi.match(page)
277
+ candidates[m[2]] = m[1].length
278
+ end
279
+
280
+ if candidates.empty?
281
+ section = "Untitled"
282
+ else
283
+ section = candidates.sort_by { |k,v| v }.first.flatten[0]
284
+ end
285
+
286
+ paginator['section'] = section
287
+
288
+ paginator['paginated'] = true
289
+ paginator['page_num'] = num
290
+ paginator['page_path'] = @config[:base_url] + _permalink(base, num, max)
291
+
292
+ paginator['first_page'] = 1
293
+ paginator['first_page_path'] = @config[:base_url] + base
294
+
295
+ paginator['last_page'] = pages.length
296
+ paginator['last_page_path'] = @config[:base_url] + _permalink(base, max, max)
297
+
298
+ paginator['total_pages'] = max
299
+
300
+ paginator['single_page'] = @config[:base_url] + plink_all
301
+
302
+ if first
303
+ paginator['is_first'] = true
304
+ first_page_path = @config[:base_url] + base
305
+ total_pages = max
306
+ single_page = plink_all
307
+ else
308
+ paginator['previous_page'] = num - 1
309
+ paginator['previous_page_path'] = @config[:base_url] + plink_prev
310
+ end
311
+
312
+ if last
313
+ paginator['is_last'] = true
314
+ else
315
+ paginator['next_page'] = num + 1
316
+ paginator['next_page_path'] = @config[:base_url] + plink_next
317
+ end
318
+
319
+ paginator['previous_is_first'] = (num == 2)
320
+ paginator['next_is_last'] = (num == max - 1)
321
+
322
+ paginator['has_previous'] = (num >= 2)
323
+ paginator['has_next'] = (num < max)
324
+
325
+ seo = {}
326
+ seo['canonical'] = _seo('canonical', site_url + plink_all) if @config[:seo_canonical];
327
+ seo['prev'] = _seo('prev', site_url + plink_prev) if plink_prev
328
+ seo['next'] = _seo('next', site_url + plink_next) if plink_next
329
+ seo['links'] = seo.map {|k,v| v }.join($/)
330
+
331
+ paginator['seo'] = seo
332
+
333
+ # Set the paginator
334
+ new_part.pager = Pager.new(paginator)
335
+
336
+ # Set up the frontmatter properties
337
+ _set_properties(item, new_part, 'all', user_props)
338
+ _set_properties(item, new_part, 'first', user_props) if first
339
+ _set_properties(item, new_part, 'last', user_props) if last
340
+ _set_properties(item, new_part, 'part', user_props) if !first && !last
341
+
342
+ # Don't allow these to be overriden,
343
+ # i.e. set/reset layout, date, title, permalink
344
+
345
+ new_part.data['layout'] = item.data['layout']
346
+ new_part.data['date'] = item.data['date']
347
+ new_part.data['permalink'] = plink
348
+
349
+ # title is set together with trail below as it may rely on section name
350
+
351
+ new_part.data['pagination_info'] =
352
+ {
353
+ 'curr_page' => num,
354
+ 'total_pages' => max,
355
+ 'type' => first ? 'first' : ( last ? 'last' : 'part'),
356
+ 'id' => id
357
+ }
358
+
359
+ new_part.content = header + page + footer
360
+
361
+ new_items << new_part
362
+
363
+ num += 1
364
+ end
365
+
366
+ t_config = @config[:trail]
367
+ t_config[:title] = @config[:title]
368
+
369
+ # Replace #target with page_path#target
370
+ i = 0
371
+ new_items.each do |item|
372
+ content = item.content
373
+
374
+ _adjust_links(new_items, item.content, a_locations, i+1)
375
+
376
+ # Adjust the TOC relative to this page
377
+ if @toc
378
+ toc = @toc.dup
379
+ _adjust_links(new_items, toc, a_locations, i+1)
380
+ else
381
+ toc = nil
382
+ end
383
+
384
+ item.pager.toc = { 'simple' => toc }
385
+
386
+ item.pager.page_trail = _page_trail(@config[:base_url] + base, new_items, i+1,
387
+ new_items.length, t_config)
388
+
389
+ # Previous/next section name assignments
390
+ item.pager.previous_section = new_items[i-1].pager.section if i > 0
391
+ item.pager.next_section = new_items[i+1].pager.section if i < new_items.length - 1
392
+
393
+ i += 1
394
+ end
395
+
396
+ # This is in another loop to avoid messing with the titles
397
+ # during page trail generation
398
+ i = 1
399
+ new_items.each do |item|
400
+ item.data['title'] =
401
+ _title(@config[:title], new_items, i, new_items.length,
402
+ @config[:retitle_first])
403
+ i += 1
404
+ end
405
+
406
+ # Setup single-page view
407
+
408
+ if !@config[:single_page].empty?
409
+ if @collection == "pages"
410
+ single = Page.new(item, @site, dirname, item.name)
411
+ else
412
+ single = Document.new(item, @site, @collection)
413
+ end
414
+
415
+ _set_properties(item, single, 'all', user_props)
416
+ _set_properties(item, single, 'single', user_props)
417
+
418
+ single.data['pagination_info'] = {
419
+ 'type' => 'single',
420
+ 'id' => id
421
+ }
422
+
423
+ # Restore original properties for these
424
+ single.data['permalink'] = single_page
425
+ single.data['layout'] = item.data['layout']
426
+ single.data['date'] = item.data['date']
427
+ single.data['title'] = item.data['title']
428
+
429
+ # Just some limited data for the single page
430
+ seo = @config[:seo_canonical] ?
431
+ _seo('canonical', site_url + single_page) : ""
432
+
433
+ single_paginator = {
434
+ 'first_page_path' => first_page_path,
435
+ 'total_pages' => total_pages,
436
+ 'toc' => {
437
+ 'simple' => @toc
438
+ },
439
+ 'seo' => {
440
+ 'links' => seo,
441
+ 'canonical' => seo
442
+ }
443
+ }
444
+
445
+ single.pager = Pager.new(single_paginator)
446
+ single.content = item.content
447
+
448
+ new_items << single
449
+ end
450
+
451
+ @items = new_items
452
+ end
453
+
454
+ private
455
+ def _page_trail(base, items, page, max, config)
456
+ page_trail = []
457
+
458
+ before = config["before"] || 0
459
+ after = config["after"] || 0
460
+
461
+ (before <= 0 || before >= max) ? 0 : before
462
+ (after <= 0 || after >= max) ? 0 : after
463
+
464
+ if before.zero? && after.zero?
465
+ start_page = 1
466
+ end_page = max
467
+ else
468
+ start_page = page - before
469
+ start_page = 1 if start_page <= 0
470
+
471
+ end_page = start_page + before + after
472
+ if end_page > max
473
+ end_page = max
474
+ start_page = max - before - after
475
+ start_page = 1 if start_page <= 0
476
+ end
477
+ end
478
+
479
+ i = start_page
480
+ while i <= end_page do
481
+ title = _title(config[:title], items, i, max)
482
+ page_trail <<
483
+ {
484
+ 'num' => i,
485
+ 'path' => _permalink(base, i, max),
486
+ 'title' => title
487
+ }
488
+ i += 1
489
+ end
490
+
491
+ page_trail
492
+ end
493
+
494
+ def _seo(type, url)
495
+ " <link rel=\"#{type}\" href=\"#{url}\" />"
496
+ end
497
+
498
+ def _permalink(base, page, max)
499
+ return base if page == 1
500
+
501
+ (base + @config[:permalink]).
502
+ gsub(/:num/, page.to_s).
503
+ gsub(/:max/, max.to_s).
504
+ gsub(/\/\//, '/')
505
+ end
506
+
507
+ def _title(format, items, page, max, retitle_first = false)
508
+ orig = items[page-1].data['title']
509
+ return orig if !format || (page == 1 && !retitle_first)
510
+
511
+ section = items[page-1].pager.section
512
+
513
+ format.gsub(/:title/, orig || '').
514
+ gsub(/:section/, section).
515
+ gsub(/:num/, page.to_s).
516
+ gsub(/:max/, max.to_s)
517
+ end
518
+
519
+ def _set_properties(original, item, stage, user_props = nil)
520
+ stage_props = {}
521
+ stage_props.merge!(@config[:properties][stage])
522
+
523
+ if user_props && user_props.has_key?(stage)
524
+ stage_props.merge!(user_props[stage])
525
+ end
526
+
527
+ return if stage_props.empty?
528
+
529
+ # Handle special values
530
+ stage_props.delete_if do |k,v|
531
+ if k == "pagination_info"
532
+ false
533
+ elsif v == "/"
534
+ true
535
+ else
536
+ if v.is_a?(String) && m = /\$\.?(.*)$/.match(v)
537
+ stage_props[k] = m[1].empty? ?
538
+ original.data[k] : original.data[m[1]]
539
+ end
540
+ false
541
+ end
542
+ end
543
+
544
+ if item.respond_to?('merge_data')
545
+ item.merge_data!(stage_props)
546
+ else
547
+ item.data.merge!(stage_props)
548
+ end
549
+
550
+ end
551
+
552
+ def _adjust_links(new_items, content, a_locations, num)
553
+ # TODO: Try to merge these
554
+
555
+ # [Something](#target)
556
+ content.scan(/\[[^\]]+\]\(#(.*)\)/i).flatten.each do |a|
557
+ if (page_num = a_locations[a]) && (page_num != num)
558
+ content.gsub!(/(\[[^\]]+\]\()##{a}(\))/i,
559
+ '\1' + @site.config['baseurl'] + new_items[page_num-1].data['permalink']+'#'+a+'\2')
560
+ end
561
+ end
562
+
563
+ # [Something]: #target
564
+ content.scan(/\[[^\]]+\]:\s*#(\S+)/i).flatten.each do |a|
565
+ if (page_num = a_locations[a]) && (page_num != num)
566
+ content.gsub!(/(\[[^\]]+\]:\s*)##{a}/i,
567
+ '\1' + @site.config['baseurl'] + new_items[page_num-1].data['permalink']+'#'+a)
568
+ end
569
+ end
570
+
571
+ end
572
+ end
573
+
574
+ end
575
+ end