sutty-liquid 0.8.1 → 0.10.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/jekyll/filters/arrays.rb +149 -0
- data/lib/jekyll/filters/assertion.rb +1 -1
- data/lib/jekyll/filters/content.rb +129 -0
- data/lib/jekyll/filters/strings.rb +14 -0
- data/lib/sutty-liquid.rb +2 -2
- metadata +33 -5
- data/lib/jekyll/filters/infinite.rb +0 -20
- data/lib/jekyll/filters/sample.rb +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f89b4f4a0b3dc57f4720491bd1245b63e48a018eb059f1e1c065178e8d0ab185
|
4
|
+
data.tar.gz: 797a226386270f608022b0c9ff89402a17b0806fba9e409e0fb99eff2bdad475
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 924ba6d9c6d01f1f3b313782911de7ce751e7dab63fbfd99cb18ccbec9f34ee2fe30ff9a65a5cc7e5b203ac3a90a2b094d89606a0247905322d9d611dd175eda
|
7
|
+
data.tar.gz: d2b3c2c91a51311313cff91b82ca752d680eb54b12145187bbeaa0771e0473fe561e3995c583bcbdb78e5297a67b42fae58bdeb427ef30dfaa8e5dc8c8aa6c5b
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module Filters
|
5
|
+
module Arrays
|
6
|
+
# Returns one or several random items from an Array.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# {{ site.posts | sample }}
|
10
|
+
# {{ site.posts | sample: 3 }}
|
11
|
+
# @param input [Array]
|
12
|
+
# @param amount [Integer]
|
13
|
+
# @return [Any]
|
14
|
+
def sample(input, amount = 1)
|
15
|
+
input = [] unless array? input
|
16
|
+
|
17
|
+
input.sample(amount)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Join arrays or append item to array
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
# {% assign things = site.posts | where: "layout", "thing" %}
|
24
|
+
# {% assign being = site.posts | find: "layout", "being" %}
|
25
|
+
# {% assign dread = things | concat: being %}
|
26
|
+
#
|
27
|
+
# @param input [Array]
|
28
|
+
# @param concatenable [Array,any]
|
29
|
+
def join(input, concatenable)
|
30
|
+
input = [] unless array? input
|
31
|
+
|
32
|
+
if concatenable.is_a? Array
|
33
|
+
input + concatenable
|
34
|
+
else
|
35
|
+
input.dup << concatenable
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Finds the next posts in a collection, starting from current
|
40
|
+
# post and restarts from the beginning to always return posts.
|
41
|
+
#
|
42
|
+
# @example
|
43
|
+
# {{ page | infinite_next: site.posts }}
|
44
|
+
# @param input [Jekyll::Document,Drop] The current post (page)
|
45
|
+
# @param posts [Array] An array of posts (ie. results from where filter)
|
46
|
+
# @param amount [Integer] Amount of posts next to current, max is posts size
|
47
|
+
# @return [Array<Jekyll::Document,Drop>] Array of posts
|
48
|
+
def infinite_next(input, posts, amount = 1)
|
49
|
+
posts = [] unless array? posts
|
50
|
+
|
51
|
+
liquid_input = input.to_liquid
|
52
|
+
liquid_posts = posts.map(&:to_liquid)
|
53
|
+
index = find_in_stack(liquid_input, liquid_posts)
|
54
|
+
liquid_posts.rotate(index).slice(1, amount) if index
|
55
|
+
end
|
56
|
+
|
57
|
+
# Finds the previous posts in a collection, starting from current
|
58
|
+
# post and restarts from the beginning to always return posts.
|
59
|
+
#
|
60
|
+
# @example
|
61
|
+
# {{ page | infinite_next: site.posts }}
|
62
|
+
# @param input [Jekyll::Document,Drop] The current post (page)
|
63
|
+
# @param posts [Array<Jekyll::Document,Drop>] An array of posts (ie. results from where filter)
|
64
|
+
# @param amount [Integer] Amount of posts previous to current, max is posts size
|
65
|
+
# @return [Array<Jekyll::Document,Drop>] Array of posts
|
66
|
+
def infinite_prev(input, posts, amount = 1)
|
67
|
+
posts = [] unless array? posts
|
68
|
+
|
69
|
+
liquid_input = input.to_liquid
|
70
|
+
liquid_posts = posts.map(&:to_liquid)
|
71
|
+
index = find_in_stack(liquid_input, liquid_posts)
|
72
|
+
liquid_posts.rotate(index).reverse.slice(0, amount).reverse if index
|
73
|
+
end
|
74
|
+
|
75
|
+
# Return next post from an array or nothing if post is last.
|
76
|
+
#
|
77
|
+
# @example
|
78
|
+
# {{ page | next: site.posts }}
|
79
|
+
# @param input [Jekyll::Document,Drop]
|
80
|
+
# @param posts [Array<Jekyll::Document,Drop>]
|
81
|
+
# @return [Drop,nil]
|
82
|
+
def next(input, posts)
|
83
|
+
posts = [] unless array? posts
|
84
|
+
|
85
|
+
liquid_input = input.to_liquid
|
86
|
+
liquid_posts = posts.map(&:to_liquid)
|
87
|
+
index = find_in_stack(liquid_input, liquid_posts)
|
88
|
+
liquid_posts[index + 1] if index
|
89
|
+
end
|
90
|
+
|
91
|
+
# Return previous post from an array, or nothing if post is the
|
92
|
+
# first item.
|
93
|
+
#
|
94
|
+
# @example
|
95
|
+
# {{ page | prev: site.posts }}
|
96
|
+
# {{ page | previous: site.posts }}
|
97
|
+
# @param input [Jekyll::Document,Drop]
|
98
|
+
# @param array [Array]
|
99
|
+
# @return [Drop,nil]
|
100
|
+
def prev(input, posts)
|
101
|
+
posts = [] unless array? posts
|
102
|
+
|
103
|
+
liquid_input = input.to_liquid
|
104
|
+
liquid_posts = posts.map(&:to_liquid)
|
105
|
+
index = find_in_stack(liquid_input, liquid_posts)
|
106
|
+
liquid_posts[index - 1] if index && index > 0
|
107
|
+
end
|
108
|
+
|
109
|
+
alias_method :previous, :prev
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
# Detects if param is an array or raise an error if strict filters
|
114
|
+
# is enabled
|
115
|
+
#
|
116
|
+
# @param posts [Array]
|
117
|
+
# @return [Boolean]
|
118
|
+
def array?(posts)
|
119
|
+
posts.is_a?(Array).tap do |a|
|
120
|
+
next if a
|
121
|
+
next unless @context.strict_filters
|
122
|
+
|
123
|
+
raise Liquid::ArgumentError.new('needs an array argument')
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Find post in posts, raise an error if strict_filters is enabled
|
128
|
+
#
|
129
|
+
# @param input [Drop]
|
130
|
+
# @param posts [Array] array of drops
|
131
|
+
# @return [Integer]
|
132
|
+
def find_in_stack(input, posts)
|
133
|
+
posts.index(input).tap do |n|
|
134
|
+
next if n
|
135
|
+
next unless @context.strict_filters
|
136
|
+
|
137
|
+
title = input['title'] || input['id'] || 'no title'
|
138
|
+
titles = posts.map do |p|
|
139
|
+
p['title'] || p['id'] || 'no title'
|
140
|
+
end
|
141
|
+
|
142
|
+
raise Liquid::ArgumentError.new("can't find #{title} in #{titles.join(', ')}")
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
Liquid::Template.register_filter(Jekyll::Filters::Arrays)
|
@@ -123,7 +123,7 @@ module Jekyll
|
|
123
123
|
input.blank?
|
124
124
|
when Array then input.compact.empty?
|
125
125
|
when Hash then input.compact.empty?
|
126
|
-
else input.respond_to?(:empty?) ? input.empty? :
|
126
|
+
else input.respond_to?(:empty?) ? input.empty? : !!!input
|
127
127
|
end
|
128
128
|
end
|
129
129
|
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module Filters
|
5
|
+
module Content
|
6
|
+
HEADINGS = 'h1,h2,h3,h4,h5,h6'
|
7
|
+
|
8
|
+
# Add id attribute to all headings with an optional prefix. It
|
9
|
+
# also creates a table of contents with unique IDs.
|
10
|
+
#
|
11
|
+
# It doesn't change pre-existing IDs.
|
12
|
+
#
|
13
|
+
# @example Render content with unique IDs
|
14
|
+
# {{ content | canonicalize_headings }}
|
15
|
+
# @param input [String] HTML string
|
16
|
+
# @param prefix [nil,String] Prefix IDs with this
|
17
|
+
# @return [String]
|
18
|
+
def canonicalize_headings(input, prefix = nil)
|
19
|
+
@@canonicalize_headings ||= {}
|
20
|
+
@@canonicalize_headings[input.hash] ||=
|
21
|
+
begin
|
22
|
+
require 'nokogiri'
|
23
|
+
|
24
|
+
toc = toc(input)
|
25
|
+
|
26
|
+
html_fragment(input).tap do |html|
|
27
|
+
html.css(HEADINGS).each do |h|
|
28
|
+
id = h['id']
|
29
|
+
|
30
|
+
unless id
|
31
|
+
slug = ::Jekyll::Utils.slugify(h.text, mode: 'pretty')
|
32
|
+
id = unique_id(slug, prefix, toc)
|
33
|
+
h['id'] = id
|
34
|
+
end
|
35
|
+
|
36
|
+
toc[id] = {
|
37
|
+
'level' => h.name[1].to_i,
|
38
|
+
'title' => h.text,
|
39
|
+
'id' => id
|
40
|
+
}
|
41
|
+
end
|
42
|
+
end.to_s
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Extracts a table of contents from HTML up to a certain headings
|
47
|
+
# level.
|
48
|
+
#
|
49
|
+
# It returns an array of hashes with title, level and id.
|
50
|
+
#
|
51
|
+
# @example Create a table of contents
|
52
|
+
# {% assign toc = content | table_of_contents: 2 %}
|
53
|
+
#
|
54
|
+
# {% unless toc == empty %}
|
55
|
+
# {% for item in toc %}
|
56
|
+
# {% assign heading = "h" | append: item.level %}
|
57
|
+
# <{{ heading }}>
|
58
|
+
# <a href="#{{ item.id }}">
|
59
|
+
# {{ item.title }}
|
60
|
+
# </a>
|
61
|
+
# </{{ heading }}>
|
62
|
+
# {% endfor %}
|
63
|
+
# {% endunless %}
|
64
|
+
# @param input [String]
|
65
|
+
# @param max_level [Integer] All headings up to this level
|
66
|
+
# @param prefix [String,nil] Prefix
|
67
|
+
# @return [Hash]
|
68
|
+
def table_of_contents(input, max_level = 2, prefix = nil)
|
69
|
+
canonicalize_headings(input, prefix)
|
70
|
+
|
71
|
+
toc(input).select do |id, item|
|
72
|
+
item['level'] <= max_level
|
73
|
+
end.values
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
# Parses and caches an HTML5 fragment
|
79
|
+
#
|
80
|
+
# @param input [String]
|
81
|
+
# @return [Nokogiri::HTML5::Fragment]
|
82
|
+
def html_fragment(input)
|
83
|
+
@@html_fragment ||= {}
|
84
|
+
@@html_fragment[input.hash] ||= Nokogiri::HTML5.fragment(input.to_s)
|
85
|
+
end
|
86
|
+
|
87
|
+
# @param input [String]
|
88
|
+
# @return [Hash]
|
89
|
+
def toc(input)
|
90
|
+
@@toc ||= {}
|
91
|
+
@@toc[input.hash] ||= {}
|
92
|
+
end
|
93
|
+
|
94
|
+
# Apply a prefix to an ID unless it's already applied
|
95
|
+
#
|
96
|
+
# @param id [String]
|
97
|
+
# @param prefix [nil,String]
|
98
|
+
# @return [String]
|
99
|
+
def prefix_id(id, prefix)
|
100
|
+
return id if prefix.nil?
|
101
|
+
return id if id.start_with? "#{prefix}-"
|
102
|
+
|
103
|
+
"#{prefix}-#{id}"
|
104
|
+
end
|
105
|
+
|
106
|
+
# Obtains a unique ID for TOC
|
107
|
+
#
|
108
|
+
# @param id [String]
|
109
|
+
# @param prefix [String,nil]
|
110
|
+
# @param toc [Hash]
|
111
|
+
# @return [String]
|
112
|
+
def unique_id(id, prefix, toc)
|
113
|
+
prefixed_id = prefix_id id, prefix
|
114
|
+
|
115
|
+
return prefixed_id unless toc.key? prefixed_id
|
116
|
+
|
117
|
+
require 'securerandom'
|
118
|
+
|
119
|
+
loop do
|
120
|
+
unique = "#{prefixed_id}-#{SecureRandom.hex(3)}"
|
121
|
+
|
122
|
+
break unique unless toc.key? unique
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
Liquid::Template.register_filter(Jekyll::Filters::Content)
|
@@ -61,6 +61,20 @@ module Jekyll
|
|
61
61
|
.gsub(star_delimiter, '*')
|
62
62
|
.gsub(escaped_delimiter, '\*')
|
63
63
|
end
|
64
|
+
|
65
|
+
def unescape(input)
|
66
|
+
CGI.unescapeHTML input.to_s
|
67
|
+
end
|
68
|
+
|
69
|
+
# Escapes a string by percent encoding all reserved characters
|
70
|
+
#
|
71
|
+
# @param :input [Any]
|
72
|
+
# @return [String]
|
73
|
+
def component_escape(input)
|
74
|
+
require 'addressable'
|
75
|
+
|
76
|
+
Addressable::URI.encode_component input.to_s, Addressable::URI::CharacterClasses::UNRESERVED
|
77
|
+
end
|
64
78
|
end
|
65
79
|
end
|
66
80
|
end
|
data/lib/sutty-liquid.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'jekyll/filters/arrays'
|
3
4
|
require_relative 'jekyll/filters/assertion'
|
4
5
|
require_relative 'jekyll/filters/compact'
|
6
|
+
require_relative 'jekyll/filters/content'
|
5
7
|
require_relative 'jekyll/filters/date_local'
|
6
|
-
require_relative 'jekyll/filters/infinite'
|
7
8
|
require_relative 'jekyll/filters/file'
|
8
9
|
require_relative 'jekyll/filters/json'
|
9
10
|
require_relative 'jekyll/filters/menu'
|
10
11
|
require_relative 'jekyll/filters/number'
|
11
|
-
require_relative 'jekyll/filters/sample'
|
12
12
|
require_relative 'jekyll/filters/strings'
|
13
13
|
require_relative 'jekyll/filters/social_network'
|
14
14
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sutty-liquid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- f
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-08-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jekyll
|
@@ -80,6 +80,34 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0.13'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: nokogiri
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: yard
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
83
111
|
description: An assorment of Liquid filters and tags for Jekyll used in Sutty
|
84
112
|
email:
|
85
113
|
- f@sutty.nl
|
@@ -92,16 +120,16 @@ files:
|
|
92
120
|
- LICENSE.txt
|
93
121
|
- README.md
|
94
122
|
- lib/jekyll/drops/url_drop_decorator.rb
|
123
|
+
- lib/jekyll/filters/arrays.rb
|
95
124
|
- lib/jekyll/filters/assertion.rb
|
96
125
|
- lib/jekyll/filters/compact.rb
|
126
|
+
- lib/jekyll/filters/content.rb
|
97
127
|
- lib/jekyll/filters/date_local.rb
|
98
128
|
- lib/jekyll/filters/file.rb
|
99
|
-
- lib/jekyll/filters/infinite.rb
|
100
129
|
- lib/jekyll/filters/json.rb
|
101
130
|
- lib/jekyll/filters/menu.rb
|
102
131
|
- lib/jekyll/filters/number.rb
|
103
132
|
- lib/jekyll/filters/pry.rb
|
104
|
-
- lib/jekyll/filters/sample.rb
|
105
133
|
- lib/jekyll/filters/social_network.rb
|
106
134
|
- lib/jekyll/filters/strings.rb
|
107
135
|
- lib/jekyll/tags/pry.rb
|
@@ -137,7 +165,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
137
165
|
- !ruby/object:Gem::Version
|
138
166
|
version: '0'
|
139
167
|
requirements: []
|
140
|
-
rubygems_version: 3.3.
|
168
|
+
rubygems_version: 3.3.15
|
141
169
|
signing_key:
|
142
170
|
specification_version: 4
|
143
171
|
summary: Liquid filters
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Jekyll
|
4
|
-
module Filters
|
5
|
-
module Infinite
|
6
|
-
#
|
7
|
-
def infinite_next(input, posts, amount)
|
8
|
-
liquid = posts.map(&:to_liquid)
|
9
|
-
liquid.rotate(liquid.index(input)).slice(1, amount)
|
10
|
-
end
|
11
|
-
|
12
|
-
def infinite_prev(input, posts, amount)
|
13
|
-
liquid = posts.map(&:to_liquid)
|
14
|
-
liquid.rotate(liquid.index(input)).reverse.slice(0, amount).reverse
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
Liquid::Template.register_filter(Jekyll::Filters::Infinite)
|
@@ -1,24 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Jekyll
|
4
|
-
module Filters
|
5
|
-
module Sample
|
6
|
-
# Returns a random item from an Array.
|
7
|
-
#
|
8
|
-
# Example usage:
|
9
|
-
#
|
10
|
-
# {{ site.posts | sample }}
|
11
|
-
# {{ site.posts | sample: 3 }}
|
12
|
-
#
|
13
|
-
# @input [Array]
|
14
|
-
# @return [Any]
|
15
|
-
def sample(input, amount = 1)
|
16
|
-
return unless input.respond_to? :sample
|
17
|
-
|
18
|
-
input.sample(amount)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
Liquid::Template.register_filter(Jekyll::Filters::Sample)
|