jekyll-uj-powertools 1.6.3 → 1.6.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0bb2525b4822d44d79b90f95dd50e2f4231fc1696825edeaafd13273e42834c4
4
- data.tar.gz: eb8b0c45df97fd704a7cda6d2d532606ebf260b10d32edc14588728b3de23684
3
+ metadata.gz: e74f6d968d196904d9306b2b3c15479dafb8adbec2ce42dd1b9e4d2b42660646
4
+ data.tar.gz: ac464d3b6a8df83604094e1c5b817af659c32bc58ce76adc3e9b315aa85c85e8
5
5
  SHA512:
6
- metadata.gz: e08a2ff66c6ba2f03ff2b4e694401c65b09b07a57015b2852e55cae268ab50dd68b2714d7cb5c5b29f755d3a8ab2bca089c63d938587dbdeb94904a3abe2421a
7
- data.tar.gz: c2248351129af1c9494262f9ec1d99746f495cc3f124d6b875ab0c1bb765b845d38bf3e16ac35e9e9db119f1f7bc5b22ff407f08b2b8c52ce79103274d49fcfa
6
+ metadata.gz: 0dd1feb9617342c7a21f15c7f313f11be4d2c2956a592b5ea20289687267514390c0141133eeaaaa4c42b8f959c405ae31d2819613beecd7d6d1eeefc30337cd
7
+ data.tar.gz: 81a12879162cc3616076ab55ddf642fef351098986967e1ae55f0efaf79da1aaa7878243fdf263ddff13acb85e41205459d2b2b574c42e8cb82880fac039d06b
@@ -5,7 +5,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
  Gem::Specification.new do |spec|
6
6
  # Gem info
7
7
  spec.name = "jekyll-uj-powertools"
8
- spec.version = "1.6.3"
8
+ spec.version = "1.6.4"
9
9
 
10
10
  # Author info
11
11
  spec.authors = ["ITW Creative Works"]
@@ -0,0 +1,115 @@
1
+ # Helper module for resolving variables in Jekyll tags
2
+ module Jekyll
3
+ module UJPowertools
4
+ module VariableResolver
5
+ # Resolve a variable or string literal from context
6
+ # If prefer_literal is true, unquoted strings are treated as literals unless they're clearly variables
7
+ def resolve_input(context, input, prefer_literal = false)
8
+ return nil if input.nil? || input.empty?
9
+
10
+ # Check if the input is a quoted string literal
11
+ if input.match(/^["'](.*)["']$/)
12
+ # It's a string literal - extract the value between quotes
13
+ $1
14
+ elsif prefer_literal
15
+ # In prefer_literal mode, only treat as variable if it has dots or exists in context
16
+ if input.include?('.') || context[input]
17
+ resolve_variable(context, input)
18
+ else
19
+ # Treat as literal string
20
+ input
21
+ end
22
+ else
23
+ # Default behavior - try to resolve as variable, return nil if not found
24
+ resolve_variable(context, input)
25
+ end
26
+ end
27
+
28
+ # Resolve a variable path through Jekyll's context
29
+ def resolve_variable(context, variable_name)
30
+ return nil if variable_name.nil? || variable_name.empty?
31
+
32
+ # Handle nested variable access like page.resolved.post.id
33
+ parts = variable_name.split('.')
34
+
35
+ # Start with the first part
36
+ current = context[parts.first]
37
+
38
+ # Navigate through nested properties
39
+ parts[1..-1].each do |part|
40
+ break if current.nil?
41
+
42
+ # Handle different types of objects
43
+ if current.respond_to?(:[])
44
+ current = current[part]
45
+ elsif current.respond_to?(:data) && current.data.respond_to?(:[])
46
+ # Handle Jekyll Drop objects
47
+ current = current.data[part]
48
+ else
49
+ current = nil
50
+ end
51
+ end
52
+
53
+ current
54
+ end
55
+
56
+ # Parse comma-separated arguments (preserving quotes)
57
+ def parse_arguments(markup)
58
+ args = []
59
+ current_arg = ''
60
+ in_quotes = false
61
+ quote_char = nil
62
+
63
+ markup.each_char do |char|
64
+ if !in_quotes && (char == '"' || char == "'")
65
+ in_quotes = true
66
+ quote_char = char
67
+ current_arg += char
68
+ elsif in_quotes && char == quote_char
69
+ in_quotes = false
70
+ quote_char = nil
71
+ current_arg += char
72
+ elsif !in_quotes && char == ','
73
+ args << current_arg.strip
74
+ current_arg = ''
75
+ else
76
+ current_arg += char
77
+ end
78
+ end
79
+
80
+ args << current_arg.strip if current_arg.strip.length > 0
81
+ args
82
+ end
83
+
84
+ # Parse key=value options from arguments
85
+ def parse_options(args, context = nil)
86
+ options = {}
87
+
88
+ args.each do |arg|
89
+ if arg.include?('=')
90
+ key, value = arg.split('=', 2)
91
+ key = key.strip
92
+ value = value.strip
93
+
94
+ # If context provided, resolve variables in values
95
+ if context
96
+ value = resolve_input(context, value)
97
+ else
98
+ # Just strip quotes if no context
99
+ value = value.gsub(/^['"]|['"]$/, '')
100
+ end
101
+
102
+ options[key] = value
103
+ end
104
+ end
105
+
106
+ options
107
+ end
108
+
109
+ # Check if input was originally quoted
110
+ def is_quoted?(input)
111
+ !!(input && input.match(/^["']/))
112
+ end
113
+ end
114
+ end
115
+ end
@@ -13,6 +13,7 @@ module Jekyll
13
13
  require_relative "hooks/markdown-images"
14
14
 
15
15
  # Load Tags
16
+ require_relative "tags/external"
16
17
  require_relative "tags/fake_comments"
17
18
  require_relative "tags/icon"
18
19
  require_relative "tags/iffalsy"
@@ -0,0 +1,46 @@
1
+ # Libraries
2
+ require "jekyll"
3
+ require_relative '../helpers/variable_resolver'
4
+
5
+ module Jekyll
6
+ module UJPowertools
7
+ class ExternalTag < Liquid::Tag
8
+ include VariableResolver
9
+
10
+ def initialize(tag_name, markup, tokens)
11
+ super
12
+ @markup = markup.strip
13
+ end
14
+
15
+ def render(context)
16
+ # Resolve input path (handles both literals and variables)
17
+ path = resolve_input(context, @markup)
18
+ return '' if path.nil? || path.empty?
19
+
20
+ # Check if path already has a protocol (http:// or https://)
21
+ if path =~ /^https?:\/\//
22
+ # Already has protocol, return as-is
23
+ path
24
+ elsif path =~ /^\/\//
25
+ # Protocol-relative URL, return as-is
26
+ path
27
+ else
28
+ # Get site URL from context
29
+ site = context.registers[:site]
30
+ site_url = site.config['url'] || ''
31
+
32
+ # Remove trailing slash from site_url if present
33
+ site_url = site_url.chomp('/')
34
+
35
+ # Ensure path starts with /
36
+ path = "/#{path}" unless path.start_with?('/')
37
+
38
+ # Combine site URL with path
39
+ "#{site_url}#{path}"
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ Liquid::Template.register_tag('uj_external', Jekyll::UJPowertools::ExternalTag)
@@ -1,8 +1,10 @@
1
1
  # Libraries
2
2
  require "jekyll"
3
+ require_relative '../helpers/variable_resolver'
3
4
 
4
5
  module Jekyll
5
6
  class UJCommentsTag < Liquid::Tag
7
+ include UJPowertools::VariableResolver
6
8
  def initialize(tag_name, markup, tokens)
7
9
  super
8
10
  @markup = markup.strip
@@ -34,24 +36,12 @@ module Jekyll
34
36
  return nil unless page
35
37
  page['content']
36
38
  else
37
- # Resolve the variable name
38
- resolve_variable(context, @markup)
39
+ # Use the helper to resolve input (handles both literals and variables)
40
+ resolve_input(context, @markup)
39
41
  end
40
42
  end
41
43
 
42
- def resolve_variable(context, variable_name)
43
- # Handle nested variable access like page.content or include.content
44
- parts = variable_name.split('.')
45
- current = context
46
-
47
- parts.each do |part|
48
- return nil unless current.respond_to?(:[]) || current.is_a?(Hash)
49
- current = current[part]
50
- return nil if current.nil?
51
- end
52
-
53
- current
54
- end
44
+ # resolve_variable method is now provided by VariableResolver module
55
45
 
56
46
  def strip_html(content)
57
47
  # Remove HTML tags
data/lib/tags/icon.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  # Libraries
2
2
  require "jekyll"
3
+ require_relative '../helpers/variable_resolver'
3
4
 
4
5
  module Jekyll
5
6
  class UJIconTag < Liquid::Tag
7
+ include UJPowertools::VariableResolver
6
8
  # Default icon to show when requested icon is not found
7
9
  DEFAULT_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M320 64C334.7 64 348.2 72.1 355.2 85L571.2 485C577.9 497.4 577.6 512.4 570.4 524.5C563.2 536.6 550.1 544 536 544L104 544C89.9 544 76.9 536.6 69.6 524.5C62.3 512.4 62.1 497.4 68.8 485L284.8 85C291.8 72.1 305.3 64 320 64zM320 232C306.7 232 296 242.7 296 256L296 368C296 381.3 306.7 392 320 392C333.3 392 344 381.3 344 368L344 256C344 242.7 333.3 232 320 232zM346.7 448C347.3 438.1 342.4 428.7 333.9 423.5C325.4 418.4 314.7 418.4 306.2 423.5C297.7 428.7 292.8 438.1 293.4 448C292.8 457.9 297.7 467.3 306.2 472.5C314.7 477.6 325.4 477.6 333.9 472.5C342.4 467.3 347.3 457.9 346.7 448z"/></svg>'
8
10
 
@@ -69,28 +71,25 @@ module Jekyll
69
71
  end
70
72
 
71
73
  def render(context)
72
- # Parse arguments that can be quoted or unquoted
74
+ # Parse arguments using helper
73
75
  parts = parse_arguments(@markup)
74
- icon_name_input = parts[0]
75
- css_classes = parts[1]
76
-
77
- # Check if the input was originally quoted (literal string)
78
- is_quoted = @markup.strip.match(/^['"]/)
79
-
80
- # If quoted, use as literal. Otherwise, try to resolve as variable
81
- if is_quoted
82
- icon_name = icon_name_input
83
- else
84
- # Try to resolve as a variable
85
- icon_name = resolve_variable(context, icon_name_input)
86
- # If it didn't resolve to a string, use the input as literal
87
- icon_name = icon_name_input if icon_name.nil? || !icon_name.is_a?(String)
88
- end
89
-
90
- # Strip quotes from resolved icon name if present
91
- if icon_name.is_a?(String) && icon_name.match(/^['"].*['"]$/)
92
- icon_name = icon_name[1..-2]
76
+
77
+ # Resolve icon name - if it resolves to non-string, use the literal
78
+ icon_name = parts[0]
79
+ if icon_name
80
+ resolved = resolve_input(context, icon_name, true)
81
+ # If resolved value is not a string, treat the input as literal
82
+ if resolved.is_a?(String)
83
+ # Strip any quotes from the resolved string value
84
+ icon_name = resolved.gsub(/^['"]|['"]$/, '')
85
+ else
86
+ # Strip quotes if present and use as literal
87
+ icon_name = icon_name.gsub(/^['"]|['"]$/, '')
88
+ end
93
89
  end
90
+
91
+ # Resolve CSS classes (treat unquoted strings as literals)
92
+ css_classes = resolve_input(context, parts[1], true) if parts[1]
94
93
 
95
94
  # Get site from context
96
95
  site = context.registers[:site]
@@ -205,57 +204,7 @@ module Jekyll
205
204
  nil
206
205
  end
207
206
 
208
- def parse_arguments(markup)
209
- # Parse arguments that can be quoted or unquoted
210
- # Examples: award, fa-md OR 'award', 'fa-md' OR myVar, "2em"
211
- args = []
212
- current_arg = ''
213
- in_quotes = false
214
- quote_char = nil
215
-
216
- markup.each_char.with_index do |char, i|
217
- if !in_quotes && (char == '"' || char == "'")
218
- # Start of quoted string
219
- in_quotes = true
220
- quote_char = char
221
- elsif in_quotes && char == quote_char
222
- # End of quoted string
223
- in_quotes = false
224
- quote_char = nil
225
- elsif !in_quotes && char == ','
226
- # Argument separator
227
- args << current_arg.strip
228
- current_arg = ''
229
- else
230
- # Regular character
231
- current_arg += char
232
- end
233
- end
234
-
235
- # Add the last argument
236
- args << current_arg.strip if current_arg.strip.length > 0
237
-
238
- args
239
- end
240
-
241
- def resolve_variable(context, variable_name)
242
- # Handle nested variable access like page.icon
243
- parts = variable_name.split('.')
244
- current = context
245
-
246
- parts.each do |part|
247
- if current.respond_to?(:[])
248
- current = current[part]
249
- elsif current.respond_to?(:key?) && current.key?(part)
250
- current = current[part]
251
- else
252
- return nil
253
- end
254
- return nil if current.nil?
255
- end
256
-
257
- current
258
- end
207
+ # parse_arguments and resolve_variable methods are now provided by VariableResolver module
259
208
  end
260
209
  end
261
210
 
data/lib/tags/iffalsy.rb CHANGED
@@ -1,28 +1,20 @@
1
1
  # Libraries
2
- # ...
2
+ require_relative '../helpers/variable_resolver'
3
3
 
4
4
  # Tag
5
5
  module Jekyll
6
6
  module UJPowertools
7
7
  class IfFalsyTag < Liquid::Block
8
+ include VariableResolver
9
+
8
10
  def initialize(tag_name, markup, tokens)
9
11
  super
10
12
  @variable = markup.strip
11
13
  end
12
14
 
13
15
  def render(context)
14
- # Use Liquid's variable lookup to handle nested properties
15
- value = context.scopes.last[@variable] || context[@variable]
16
-
17
- # For nested properties like page.my.variable
18
- if @variable.include?('.')
19
- parts = @variable.split('.')
20
- value = context[parts.first]
21
- parts[1..-1].each do |part|
22
- value = value.is_a?(Hash) ? value[part] : nil
23
- break if value.nil?
24
- end
25
- end
16
+ # Use the helper to resolve input (handles both literals and variables)
17
+ value = resolve_input(context, @variable)
26
18
 
27
19
  # Check if the value is falsy (nil, false, empty string, or 0)
28
20
  if value.nil? || value == false || value == "" || value == 0
data/lib/tags/iffile.rb CHANGED
@@ -1,10 +1,12 @@
1
1
  # Libraries
2
- # ...
2
+ require_relative '../helpers/variable_resolver'
3
3
 
4
4
  # Tag
5
5
  module Jekyll
6
6
  module UJPowertools
7
7
  class IfFileTag < Liquid::Block
8
+ include VariableResolver
9
+
8
10
  def initialize(tag_name, markup, tokens)
9
11
  super
10
12
  @path = markup.strip
@@ -14,18 +16,11 @@ module Jekyll
14
16
  # Get the site object
15
17
  site = context.registers[:site]
16
18
 
17
- # Resolve the path variable if it's a variable name
18
- path = context[@path] || @path
19
-
20
- # Handle nested variables like page.css_path
21
- if @path.include?('.')
22
- parts = @path.split('.')
23
- path = context[parts.first]
24
- parts[1..-1].each do |part|
25
- path = path.is_a?(Hash) ? path[part] : nil
26
- break if path.nil?
27
- end
28
- end
19
+ # Use the helper to resolve input (handles both literals and variables)
20
+ path = resolve_input(context, @path)
21
+
22
+ # Return empty if path couldn't be resolved
23
+ return "" unless path
29
24
 
30
25
  # Ensure path starts with /
31
26
  path = "/#{path}" unless path.to_s.start_with?('/')
data/lib/tags/iftruthy.rb CHANGED
@@ -1,28 +1,20 @@
1
1
  # Libraries
2
- # ...
2
+ require_relative '../helpers/variable_resolver'
3
3
 
4
4
  # Tag
5
5
  module Jekyll
6
6
  module UJPowertools
7
7
  class IfTruthyTag < Liquid::Block
8
+ include VariableResolver
8
9
  def initialize(tag_name, markup, tokens)
9
10
  super
10
11
  @variable = markup.strip
11
12
  end
12
13
 
13
14
  def render(context)
14
- # Use Liquid's variable lookup to handle nested properties
15
- value = context.scopes.last[@variable] || context[@variable]
16
-
17
- # For nested properties like page.my.variable
18
- if @variable.include?('.')
19
- parts = @variable.split('.')
20
- value = context[parts.first]
21
- parts[1..-1].each do |part|
22
- value = value.is_a?(Hash) ? value[part] : nil
23
- break if value.nil?
24
- end
25
- end
15
+ # Use the helper to resolve input (handles both literals and variables)
16
+ # Don't use prefer_literal for iftruthy - we want to check variables
17
+ value = resolve_input(context, @variable, false)
26
18
 
27
19
  # Check if the value is truthy (not nil, not false, not empty string, not 0)
28
20
  if value && value != false && value != "" && value != 0
data/lib/tags/image.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  # Libraries
2
2
  require "jekyll"
3
+ require_relative '../helpers/variable_resolver'
3
4
 
4
5
  module Jekyll
5
6
  class UJImageTag < Liquid::Tag
7
+ include UJPowertools::VariableResolver
6
8
  def initialize(tag_name, markup, tokens)
7
9
  super
8
10
  @markup = markup.strip
@@ -12,10 +14,12 @@ module Jekyll
12
14
  # Parse arguments
13
15
  args = parse_arguments(@markup)
14
16
  src_input = args[0]
15
- options = parse_options(args[1..-1])
16
17
 
17
- # Resolve source path
18
- src = resolve_variable(context, src_input)
18
+ # Parse options and resolve their values
19
+ options = parse_options(args[1..-1], context)
20
+
21
+ # Resolve source path (treat unquoted strings as literals)
22
+ src = resolve_input(context, src_input, true)
19
23
  return '' unless src
20
24
 
21
25
  # Check if this is an external URL
@@ -40,66 +44,7 @@ module Jekyll
40
44
 
41
45
  private
42
46
 
43
- def parse_arguments(markup)
44
- args = []
45
- current_arg = ''
46
- in_quotes = false
47
- quote_char = nil
48
-
49
- markup.each_char do |char|
50
- if !in_quotes && (char == '"' || char == "'")
51
- in_quotes = true
52
- quote_char = char
53
- current_arg += char
54
- elsif in_quotes && char == quote_char
55
- in_quotes = false
56
- quote_char = nil
57
- current_arg += char
58
- elsif !in_quotes && char == ','
59
- args << current_arg.strip
60
- current_arg = ''
61
- else
62
- current_arg += char
63
- end
64
- end
65
-
66
- args << current_arg.strip if current_arg.strip.length > 0
67
- args
68
- end
69
-
70
- def parse_options(option_args)
71
- options = {}
72
-
73
- option_args.each do |arg|
74
- if arg.include?('=')
75
- key, value = arg.split('=', 2)
76
- key = key.strip.gsub(/^['"]|['"]$/, '')
77
- value = value.strip.gsub(/^['"]|['"]$/, '')
78
- options[key] = value
79
- end
80
- end
81
-
82
- options
83
- end
84
-
85
- def resolve_variable(context, variable_input)
86
- # Strip quotes if present
87
- if variable_input.match(/^['"]/)
88
- variable_input.gsub(/^['"]|['"]$/, '')
89
- else
90
- # Resolve as variable
91
- parts = variable_input.split('.')
92
- current = context
93
-
94
- parts.each do |part|
95
- return nil unless current.respond_to?(:[]) || current.is_a?(Hash)
96
- current = current[part]
97
- return nil if current.nil?
98
- end
99
-
100
- current
101
- end
102
- end
47
+ # parse_arguments and parse_options methods are now provided by VariableResolver module
103
48
 
104
49
  def build_picture_element(src, src_path, extension, max_width, options)
105
50
  html = "<picture>\n"
@@ -194,10 +139,10 @@ module Jekyll
194
139
  html += " data-lazy=\"@src #{src}\""
195
140
  html += " class=\"#{css_class}\"" unless css_class.empty?
196
141
  html += " alt=\"#{alt}\""
142
+ html += " loading=\"#{loading}\""
197
143
  html += " style=\"#{style}\"" unless style.empty?
198
144
  html += " width=\"#{width}\"" unless width.empty?
199
145
  html += " height=\"#{height}\"" unless height.empty?
200
- html += " loading=\"#{loading}\""
201
146
  html += ">"
202
147
 
203
148
  html
data/lib/tags/language.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  # Libraries
2
2
  require "jekyll"
3
+ require_relative '../helpers/variable_resolver'
3
4
 
4
5
  module Jekyll
5
6
  class UJLanguageTag < Liquid::Tag
7
+ include UJPowertools::VariableResolver
6
8
  # Language mappings: ISO code => [English name, Native name]
7
9
  LANGUAGE_MAPPINGS = {
8
10
  'aa' => ['Afar', 'Afaraf'],
@@ -197,34 +199,25 @@ module Jekyll
197
199
  end
198
200
 
199
201
  def render(context)
200
- # Parse arguments that can be quoted or unquoted
202
+ # Parse arguments using helper
201
203
  parts = parse_arguments(@markup)
202
- iso_code_input = parts[0]
203
- output_type = parts[1] || 'english' # default to english
204
-
205
- # Check if the input was originally quoted (literal string)
206
- is_quoted = @markup.strip.match(/^['"]/)
207
-
208
- # If quoted, use as literal. Otherwise, try to resolve as variable
209
- if is_quoted
210
- iso_code = iso_code_input
211
- else
212
- # Try to resolve as a variable
213
- iso_code = resolve_variable(context, iso_code_input)
214
- # If it didn't resolve to a string, use the input as literal
215
- iso_code = iso_code_input if iso_code.nil? || !iso_code.is_a?(String)
216
- end
217
-
218
- # Strip quotes from resolved iso code if present
219
- if iso_code.is_a?(String) && iso_code.match(/^['"].*['"]$/)
220
- iso_code = iso_code[1..-2]
221
- end
222
-
223
- # Strip quotes from output type if present
224
- if output_type.is_a?(String) && output_type.match(/^['"].*['"]$/)
225
- output_type = output_type[1..-2]
204
+
205
+ # Resolve first argument - if it resolves to non-string, use the literal
206
+ iso_code = parts[0]
207
+ if iso_code
208
+ resolved = resolve_input(context, iso_code, true)
209
+ # If resolved value is not a string, treat the input as literal
210
+ if resolved.is_a?(String)
211
+ # Strip any quotes from the resolved string value
212
+ iso_code = resolved.gsub(/^['"]|['"]$/, '')
213
+ else
214
+ # Strip quotes if present and use as literal
215
+ iso_code = iso_code.gsub(/^['"]|['"]$/, '')
216
+ end
226
217
  end
227
-
218
+
219
+ output_type = resolve_input(context, parts[1], true) || 'english' # default to english
220
+
228
221
  # Convert to lowercase for lookup
229
222
  iso_code = iso_code.to_s.downcase
230
223
  output_type = output_type.to_s.downcase
@@ -241,60 +234,6 @@ module Jekyll
241
234
  language_data[0] # English name (default)
242
235
  end
243
236
  end
244
-
245
- private
246
-
247
- def parse_arguments(markup)
248
- # Parse arguments that can be quoted or unquoted
249
- # Examples: de, english OR 'de', 'english' OR myVar, "native"
250
- args = []
251
- current_arg = ''
252
- in_quotes = false
253
- quote_char = nil
254
-
255
- markup.each_char.with_index do |char, i|
256
- if !in_quotes && (char == '"' || char == "'")
257
- # Start of quoted string
258
- in_quotes = true
259
- quote_char = char
260
- elsif in_quotes && char == quote_char
261
- # End of quoted string
262
- in_quotes = false
263
- quote_char = nil
264
- elsif !in_quotes && char == ','
265
- # Argument separator
266
- args << current_arg.strip
267
- current_arg = ''
268
- else
269
- # Regular character
270
- current_arg += char
271
- end
272
- end
273
-
274
- # Add the last argument
275
- args << current_arg.strip if current_arg.strip.length > 0
276
-
277
- args
278
- end
279
-
280
- def resolve_variable(context, variable_name)
281
- # Handle nested variable access like page.language
282
- parts = variable_name.split('.')
283
- current = context
284
-
285
- parts.each do |part|
286
- if current.respond_to?(:[])
287
- current = current[part]
288
- elsif current.respond_to?(:key?) && current.key?(part)
289
- current = current[part]
290
- else
291
- return nil
292
- end
293
- return nil if current.nil?
294
- end
295
-
296
- current
297
- end
298
237
  end
299
238
  end
300
239
 
data/lib/tags/member.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  # Libraries
2
2
  require "jekyll"
3
+ require_relative '../helpers/variable_resolver'
3
4
 
4
5
  module Jekyll
5
6
  class UJMemberTag < Liquid::Tag
7
+ include UJPowertools::VariableResolver
6
8
  def initialize(tag_name, markup, tokens)
7
9
  super
8
10
  @markup = markup.strip
@@ -17,17 +19,10 @@ module Jekyll
17
19
  # Strip quotes from property if present
18
20
  property = property_input.gsub(/^['"]|['"]$/, '')
19
21
 
20
- # Check if the member input was originally quoted
21
- is_quoted = member_input && member_input.match(/^['"]/)
22
-
23
22
  # Resolve member ID
24
- if is_quoted
25
- # If quoted, strip quotes and use as literal
26
- member_id = member_input.gsub(/^['"]|['"]$/, '')
27
- else
28
- # Otherwise resolve as variable
29
- member_id = resolve_member_id(context, member_input)
30
- end
23
+ member_id = is_quoted?(member_input) ?
24
+ member_input.gsub(/^['"]|['"]$/, '') :
25
+ resolve_member_id(context, member_input)
31
26
  return '' unless member_id
32
27
 
33
28
  # Find member in site.team collection
data/lib/tags/post.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  # Libraries
2
2
  require "jekyll"
3
+ require_relative '../helpers/variable_resolver'
3
4
 
4
5
  module Jekyll
5
6
  class UJPostTag < Liquid::Tag
7
+ include UJPowertools::VariableResolver
6
8
  def initialize(tag_name, markup, tokens)
7
9
  super
8
10
  @markup = markup.strip
@@ -17,17 +19,10 @@ module Jekyll
17
19
  # Strip quotes from property if present
18
20
  property = property_input.gsub(/^['"]|['"]$/, '')
19
21
 
20
- # Check if the post input was originally quoted
21
- is_quoted = post_input && post_input.match(/^['"]/)
22
-
23
22
  # Resolve post ID
24
- if is_quoted
25
- # If quoted, strip quotes and use as literal
26
- post_id = post_input.gsub(/^['"]|['"]$/, '')
27
- else
28
- # Otherwise resolve as variable
29
- post_id = resolve_post_id(context, post_input)
30
- end
23
+ post_id = is_quoted?(post_input) ?
24
+ post_input.gsub(/^['"]|['"]$/, '') :
25
+ resolve_post_id(context, post_input)
31
26
  return '' unless post_id
32
27
 
33
28
  # Find post in site collections
@@ -46,13 +41,6 @@ module Jekyll
46
41
  site_url + post.url
47
42
  when 'path'
48
43
  post.url
49
- when 'image'
50
- # Use the custom post.post.id if available, otherwise fall back to extracting from post.id
51
- custom_id = (post.data['post'] && post.data['post']['id']) || post.id.gsub(/^\/(\w+)\//, '')
52
- # Extract the slug from the Jekyll post ID
53
- post_id_clean = post.id.gsub(/^\/(\w+)\//, '')
54
- slug = post_id_clean.gsub(/^\d{4}-\d{2}-\d{2}-/, '')
55
- "/assets/images/blog/post-#{custom_id}/#{slug}.jpg"
56
44
  when 'date'
57
45
  post.data['date'] ? post.data['date'].strftime('%Y-%m-%d') : ''
58
46
  when 'author'
@@ -65,6 +53,13 @@ module Jekyll
65
53
  Array(post.data['tags']).join(', ')
66
54
  when 'id'
67
55
  post.id
56
+ when 'image'
57
+ # Use the custom post.post.id if available, otherwise fall back to extracting from post.id
58
+ custom_id = (post.data['post'] && post.data['post']['id']) || post.id.gsub(/^\/(\w+)\//, '')
59
+ # Extract the slug from the Jekyll post ID
60
+ post_id_clean = post.id.gsub(/^\/(\w+)\//, '')
61
+ slug = post_id_clean.gsub(/^\d{4}-\d{2}-\d{2}-/, '')
62
+ "/assets/images/blog/post-#{custom_id}/#{slug}.jpg"
68
63
  when 'image-tag'
69
64
  # Generate image path
70
65
  # Use the custom post.post.id if available, otherwise fall back to extracting from post.id
@@ -73,20 +68,20 @@ module Jekyll
73
68
  post_id_clean = post.id.gsub(/^\/(\w+)\//, '')
74
69
  slug = post_id_clean.gsub(/^\d{4}-\d{2}-\d{2}-/, '')
75
70
  image_path = "/assets/images/blog/post-#{custom_id}/#{slug}.jpg"
76
-
71
+
77
72
  # Parse additional options for the image tag
78
73
  image_options = parse_image_options(args[2..-1], context)
79
-
74
+
80
75
  # Set default alt text if not provided
81
76
  if !image_options['alt']
82
77
  # Try to get the title from post.post.title first, then fall back to post.title
83
78
  default_alt = (post.data['post'] && post.data['post']['title']) || post.data['title']
84
79
  image_options['alt'] = default_alt if default_alt
85
80
  end
86
-
81
+
87
82
  # Build the markup string for uj_image tag
88
83
  image_markup = build_image_markup(image_path, image_options)
89
-
84
+
90
85
  # Parse and render the uj_image tag using Liquid template
91
86
  template_content = "{% uj_image #{image_markup} %}"
92
87
  template = Liquid::Template.parse(template_content)
@@ -105,7 +100,7 @@ module Jekyll
105
100
  current_arg = ''
106
101
  in_quotes = false
107
102
  quote_char = nil
108
-
103
+
109
104
  markup.each_char.with_index do |char, i|
110
105
  if !in_quotes && (char == '"' || char == "'")
111
106
  in_quotes = true
@@ -122,11 +117,11 @@ module Jekyll
122
117
  current_arg += char
123
118
  end
124
119
  end
125
-
120
+
126
121
  args << current_arg.strip if current_arg.strip.length > 0
127
122
  args
128
123
  end
129
-
124
+
130
125
  def parse_arguments(markup)
131
126
  # Parse arguments that can be quoted or unquoted
132
127
  args = []
@@ -171,28 +166,16 @@ module Jekyll
171
166
  end
172
167
  end
173
168
 
174
- def resolve_variable(context, variable_name)
175
- # Handle nested variable access
176
- parts = variable_name.split('.')
177
- current = context
178
-
179
- parts.each do |part|
180
- return nil unless current.respond_to?(:[]) || current.is_a?(Hash)
181
- current = current[part]
182
- return nil if current.nil?
183
- end
184
-
185
- current
186
- end
169
+ # resolve_variable method is now provided by VariableResolver module
187
170
 
188
171
  def find_post(site, post_id)
189
172
  post_id_clean = post_id.to_s.strip
190
-
173
+
191
174
  # Search in posts collection first
192
175
  if site.collections['posts']
193
176
  post = site.collections['posts'].docs.find do |doc|
194
177
  # Check standard ID match
195
- doc.id == post_id_clean ||
178
+ doc.id == post_id_clean ||
196
179
  doc.id.include?(post_id_clean) ||
197
180
  # Also check if the post has a custom post.id field that matches
198
181
  (doc.data['post'] && doc.data['post']['id'] == post_id_clean)
@@ -200,15 +183,15 @@ module Jekyll
200
183
  return post if post
201
184
  end
202
185
 
203
- # Search in other collections that might contain posts
186
+ # Search in other collections that might contain posts
204
187
  site.collections.each do |name, collection|
205
188
  next if name == 'posts' # Already checked
206
189
 
207
190
  post = collection.docs.find do |doc|
208
- (doc.id == post_id_clean ||
191
+ (doc.id == post_id_clean ||
209
192
  doc.id.include?(post_id_clean) ||
210
193
  # Check custom post.id field
211
- (doc.data['post'] && doc.data['post']['id'] == post_id_clean)) &&
194
+ (doc.data['post'] && doc.data['post']['id'] == post_id_clean)) &&
212
195
  doc.data['post']
213
196
  end
214
197
  return post if post
@@ -216,15 +199,15 @@ module Jekyll
216
199
 
217
200
  nil
218
201
  end
219
-
202
+
220
203
  def parse_image_options(option_args, context)
221
204
  options = {}
222
-
205
+
223
206
  option_args.each do |arg|
224
207
  if arg.include?('=')
225
208
  key, value = arg.split('=', 2)
226
209
  key = key.strip
227
-
210
+
228
211
  # Check if the value is quoted (literal) or unquoted (variable)
229
212
  if value.strip.match(/^['"].*['"]$/)
230
213
  # It's a literal string, strip quotes
@@ -234,22 +217,22 @@ module Jekyll
234
217
  resolved_value = resolve_variable(context, value.strip)
235
218
  value = resolved_value || value.strip
236
219
  end
237
-
220
+
238
221
  options[key] = value
239
222
  end
240
223
  end
241
-
224
+
242
225
  options
243
226
  end
244
-
227
+
245
228
  def build_image_markup(image_path, options)
246
229
  # Build markup string in the format expected by uj_image tag
247
230
  markup_parts = ["\"#{image_path}\""]
248
-
231
+
249
232
  options.each do |key, value|
250
233
  markup_parts << "#{key}=\"#{value}\""
251
234
  end
252
-
235
+
253
236
  markup_parts.join(', ')
254
237
  end
255
238
  end
data/lib/tags/readtime.rb CHANGED
@@ -1,8 +1,11 @@
1
1
  # Libraries
2
2
  require "jekyll"
3
+ require_relative '../helpers/variable_resolver'
3
4
 
4
5
  module Jekyll
5
6
  class UJReadtimeTag < Liquid::Tag
7
+ include UJPowertools::VariableResolver
8
+
6
9
  def initialize(tag_name, markup, tokens)
7
10
  super
8
11
  @markup = markup.strip
@@ -35,23 +38,9 @@ module Jekyll
35
38
  return nil unless page
36
39
  page['content']
37
40
  else
38
- # Resolve the variable name
39
- resolve_variable(context, @markup)
40
- end
41
- end
42
-
43
- def resolve_variable(context, variable_name)
44
- # Handle nested variable access like page.content or include.content
45
- parts = variable_name.split('.')
46
- current = context
47
-
48
- parts.each do |part|
49
- return nil unless current.respond_to?(:[]) || current.is_a?(Hash)
50
- current = current[part]
51
- return nil if current.nil?
41
+ # Use the helper to resolve input (handles both literals and variables)
42
+ resolve_input(context, @markup)
52
43
  end
53
-
54
- current
55
44
  end
56
45
 
57
46
  def strip_html(content)
data/lib/tags/social.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  # Libraries
2
2
  require "jekyll"
3
+ require_relative '../helpers/variable_resolver'
3
4
 
4
5
  module Jekyll
5
6
  class UJSocialTag < Liquid::Tag
7
+ include UJPowertools::VariableResolver
6
8
  # Social platform URL patterns
7
9
  SOCIAL_URLS = {
8
10
  'facebook' => 'https://facebook.com/%s',
@@ -28,14 +30,8 @@ module Jekyll
28
30
  end
29
31
 
30
32
  def render(context)
31
- # Parse the platform name (can be quoted or unquoted)
32
- platform_input = parse_argument(@markup)
33
-
34
- # Resolve the platform name (could be a variable or literal string)
35
- platform = resolve_variable(context, platform_input)
36
-
37
- # If it didn't resolve to anything, use the input as a literal string
38
- platform = platform_input if platform.nil? || platform.empty?
33
+ # Resolve the platform name (handles both literals and variables)
34
+ platform = resolve_input(context, @markup) || @markup
39
35
 
40
36
  # Get the social handle from page.resolved.socials.{platform}
41
37
  page = context['page']
@@ -54,30 +50,7 @@ module Jekyll
54
50
 
55
51
  private
56
52
 
57
- def parse_argument(markup)
58
- # Remove quotes if present
59
- cleaned = markup.strip
60
- if (cleaned.start_with?('"') && cleaned.end_with?('"')) ||
61
- (cleaned.start_with?("'") && cleaned.end_with?("'"))
62
- cleaned[1..-2]
63
- else
64
- cleaned
65
- end
66
- end
67
-
68
- def resolve_variable(context, variable_name)
69
- # Handle nested variable access like page.social
70
- parts = variable_name.split('.')
71
- current = context
72
-
73
- parts.each do |part|
74
- return nil unless current.respond_to?(:[]) || current.is_a?(Hash)
75
- current = current[part]
76
- return nil if current.nil?
77
- end
78
-
79
- current
80
- end
53
+ # parse_argument and resolve_variable methods are now provided by VariableResolver module
81
54
  end
82
55
  end
83
56
 
@@ -1,27 +1,25 @@
1
1
  # Libraries
2
2
  require "jekyll"
3
+ require_relative '../helpers/variable_resolver'
3
4
 
4
5
  module Jekyll
5
6
  class UJTranslationUrlTag < Liquid::Tag
7
+ include UJPowertools::VariableResolver
6
8
  def initialize(tag_name, markup, tokens)
7
9
  super
8
10
  @markup = markup.strip
9
11
  end
10
12
 
11
13
  def render(context)
12
- # Parse arguments that can be quoted or unquoted
14
+ # Parse arguments using helper
13
15
  parts = parse_arguments(@markup)
14
16
 
15
17
  # Return root if no arguments
16
18
  return '/' if parts.empty? || parts[0].nil?
17
19
 
18
- language_code_input = parts[0]
19
- url_path_input = parts[1] || '/'
20
-
21
- # Resolve language code (literal or variable)
22
- language_code = resolve_argument_value(context, language_code_input)
23
- # Resolve URL path (literal or variable)
24
- url_path = resolve_argument_value(context, url_path_input)
20
+ # Resolve both arguments using helper (handles literals and variables)
21
+ language_code = resolve_input(context, parts[0])
22
+ url_path = resolve_input(context, parts[1]) || '/'
25
23
 
26
24
  # Get site and translation config from context
27
25
  site = context.registers[:site]
@@ -46,80 +44,7 @@ module Jekyll
46
44
 
47
45
  private
48
46
 
49
- def parse_arguments(markup)
50
- # Parse arguments that can be quoted or unquoted
51
- # Examples: 'es', '/pricing' OR language, page.canonical.path OR 'es', page.url
52
- args = []
53
- current_arg = ''
54
- in_quotes = false
55
- quote_char = nil
56
-
57
- markup.each_char.with_index do |char, i|
58
- if !in_quotes && (char == '"' || char == "'")
59
- # Start of quoted string - include the quote in the arg
60
- in_quotes = true
61
- quote_char = char
62
- current_arg += char
63
- elsif in_quotes && char == quote_char
64
- # End of quoted string - include the quote in the arg
65
- current_arg += char
66
- in_quotes = false
67
- quote_char = nil
68
- elsif !in_quotes && char == ','
69
- # Argument separator
70
- args << current_arg.strip
71
- current_arg = ''
72
- else
73
- # Regular character
74
- current_arg += char
75
- end
76
- end
77
-
78
- # Add the last argument
79
- args << current_arg.strip if current_arg.strip.length > 0
80
-
81
- args
82
- end
83
-
84
- def resolve_argument_value(context, argument_input)
85
- return '' if argument_input.nil? || argument_input.empty?
86
-
87
- # Check if the argument was originally quoted (literal string)
88
- is_quoted = argument_input.match(/^['"].*['"]$/)
89
-
90
- # If quoted, remove quotes and use as literal. Otherwise, try to resolve as variable
91
- if is_quoted
92
- # Remove quotes from literal string
93
- resolved_value = argument_input[1..-2]
94
- else
95
- # Try to resolve as a variable
96
- resolved_value = resolve_variable(context, argument_input)
97
- # If variable resolved to nil, return empty string
98
- return '' if resolved_value.nil?
99
- # If it didn't resolve to a string, use the resolved value
100
- resolved_value = resolved_value.to_s if resolved_value
101
- end
102
-
103
- resolved_value.to_s
104
- end
105
-
106
- def resolve_variable(context, variable_name)
107
- parts = variable_name.split('.')
108
- current = context
109
-
110
- parts.each do |part|
111
- if current.respond_to?(:[])
112
- current = current[part]
113
- elsif current.respond_to?(:key?) && current.key?(part)
114
- current = current[part]
115
- else
116
- return nil
117
- end
118
- return nil if current.nil?
119
- end
120
-
121
- current
122
- end
47
+ # parse_arguments and resolve_variable methods are now provided by VariableResolver module
123
48
 
124
49
  def normalize_path(path)
125
50
  return '' if path.nil? || path.empty?
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-uj-powertools
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.3
4
+ version: 1.6.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - ITW Creative Works
@@ -115,9 +115,11 @@ files:
115
115
  - jekyll-uj-powertools.gemspec
116
116
  - lib/filters/main.rb
117
117
  - lib/generators/inject-properties.rb
118
+ - lib/helpers/variable_resolver.rb
118
119
  - lib/hooks/inject-properties.rb
119
120
  - lib/hooks/markdown-images.rb
120
121
  - lib/jekyll-uj-powertools.rb
122
+ - lib/tags/external.rb
121
123
  - lib/tags/fake_comments.rb
122
124
  - lib/tags/icon.rb
123
125
  - lib/tags/iffalsy.rb