locomotivecms_steam 1.5.0.rc0 → 1.5.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -1
  3. data/Gemfile +3 -6
  4. data/Gemfile.lock +39 -39
  5. data/README.md +2 -2
  6. data/lib/locomotive/steam/adapters/filesystem/sanitizers/section.rb +62 -16
  7. data/lib/locomotive/steam/adapters/filesystem/sanitizers/site.rb +15 -1
  8. data/lib/locomotive/steam/adapters/filesystem/yaml_loader.rb +30 -9
  9. data/lib/locomotive/steam/adapters/filesystem/yaml_loaders/content_entry.rb +1 -1
  10. data/lib/locomotive/steam/adapters/filesystem/yaml_loaders/page.rb +1 -1
  11. data/lib/locomotive/steam/adapters/filesystem/yaml_loaders/section.rb +14 -2
  12. data/lib/locomotive/steam/adapters/filesystem/yaml_loaders/site.rb +1 -1
  13. data/lib/locomotive/steam/adapters/filesystem/yaml_loaders/translation.rb +1 -1
  14. data/lib/locomotive/steam/adapters/mongodb.rb +1 -1
  15. data/lib/locomotive/steam/entities/content_entry.rb +0 -1
  16. data/lib/locomotive/steam/entities/site.rb +4 -0
  17. data/lib/locomotive/steam/errors.rb +54 -18
  18. data/lib/locomotive/steam/liquid/drops/content_entry.rb +1 -1
  19. data/lib/locomotive/steam/liquid/drops/content_entry_collection.rb +1 -1
  20. data/lib/locomotive/steam/liquid/drops/content_types.rb +1 -1
  21. data/lib/locomotive/steam/liquid/drops/inherited_block.rb +28 -0
  22. data/lib/locomotive/steam/liquid/drops/metafields.rb +2 -2
  23. data/lib/locomotive/steam/liquid/drops/params.rb +1 -1
  24. data/lib/locomotive/steam/liquid/drops/section.rb +10 -2
  25. data/lib/locomotive/steam/liquid/drops/section_content_proxy.rb +13 -2
  26. data/lib/locomotive/steam/liquid/drops/section_editor_setting_data.rb +1 -1
  27. data/lib/locomotive/steam/liquid/drops/session_proxy.rb +1 -1
  28. data/lib/locomotive/steam/liquid/file_system.rb +46 -0
  29. data/lib/locomotive/steam/liquid/filters/array.rb +61 -0
  30. data/lib/locomotive/steam/liquid/filters/misc.rb +12 -2
  31. data/lib/locomotive/steam/liquid/filters/number.rb +13 -12
  32. data/lib/locomotive/steam/liquid/filters/text.rb +4 -0
  33. data/lib/locomotive/steam/liquid/patches.rb +58 -19
  34. data/lib/locomotive/steam/liquid/tags/alt_page_links.rb +9 -5
  35. data/lib/locomotive/steam/liquid/tags/concerns/attributes.rb +47 -0
  36. data/lib/locomotive/steam/liquid/tags/concerns/path.rb +18 -31
  37. data/lib/locomotive/steam/liquid/tags/concerns/section.rb +22 -11
  38. data/lib/locomotive/steam/liquid/tags/consume.rb +26 -33
  39. data/lib/locomotive/steam/liquid/tags/csrf.rb +2 -2
  40. data/lib/locomotive/steam/liquid/tags/editable/base.rb +30 -20
  41. data/lib/locomotive/steam/liquid/tags/editable/control.rb +2 -2
  42. data/lib/locomotive/steam/liquid/tags/editable/file.rb +11 -11
  43. data/lib/locomotive/steam/liquid/tags/editable/text.rb +5 -5
  44. data/lib/locomotive/steam/liquid/tags/extends.rb +56 -8
  45. data/lib/locomotive/steam/liquid/tags/global_section.rb +6 -6
  46. data/lib/locomotive/steam/liquid/tags/google_analytics.rb +16 -6
  47. data/lib/locomotive/steam/liquid/tags/hybrid.rb +8 -4
  48. data/lib/locomotive/steam/liquid/tags/inherited_block.rb +90 -13
  49. data/lib/locomotive/steam/liquid/tags/inline_editor.rb +4 -4
  50. data/lib/locomotive/steam/liquid/tags/link_to.rb +2 -1
  51. data/lib/locomotive/steam/liquid/tags/locale_switcher.rb +25 -21
  52. data/lib/locomotive/steam/liquid/tags/model_form.rb +38 -17
  53. data/lib/locomotive/steam/liquid/tags/nav.rb +4 -4
  54. data/lib/locomotive/steam/liquid/tags/page_not_found.rb +19 -0
  55. data/lib/locomotive/steam/liquid/tags/paginate.rb +13 -7
  56. data/lib/locomotive/steam/liquid/tags/path_to.rb +1 -0
  57. data/lib/locomotive/steam/liquid/tags/redirect_to.rb +34 -0
  58. data/lib/locomotive/steam/liquid/tags/section.rb +34 -33
  59. data/lib/locomotive/steam/liquid/tags/sections_dropzone.rb +1 -1
  60. data/lib/locomotive/steam/liquid/tags/seo.rb +2 -4
  61. data/lib/locomotive/steam/liquid/tags/session_assign.rb +1 -0
  62. data/lib/locomotive/steam/liquid/tags/snippet.rb +21 -29
  63. data/lib/locomotive/steam/liquid/tags/with_scope.rb +61 -27
  64. data/lib/locomotive/steam/liquid.rb +3 -1
  65. data/lib/locomotive/steam/middlewares/cache.rb +117 -0
  66. data/lib/locomotive/steam/middlewares/concerns/helpers.rb +22 -8
  67. data/lib/locomotive/steam/middlewares/concerns/liquid_context.rb +5 -1
  68. data/lib/locomotive/steam/middlewares/concerns/rendering.rb +53 -0
  69. data/lib/locomotive/steam/middlewares/impersonated_entry.rb +4 -0
  70. data/lib/locomotive/steam/middlewares/locale.rb +2 -2
  71. data/lib/locomotive/steam/middlewares/locale_redirection.rb +1 -1
  72. data/lib/locomotive/steam/middlewares/logging.rb +1 -0
  73. data/lib/locomotive/steam/middlewares/page_not_found.rb +37 -0
  74. data/lib/locomotive/steam/middlewares/redirection.rb +1 -1
  75. data/lib/locomotive/steam/middlewares/renderer.rb +4 -26
  76. data/lib/locomotive/steam/middlewares/thread_safe.rb +0 -4
  77. data/lib/locomotive/steam/models/pager.rb +1 -0
  78. data/lib/locomotive/steam/server.rb +3 -1
  79. data/lib/locomotive/steam/services/action_service.rb +5 -0
  80. data/lib/locomotive/steam/services/auth_service.rb +9 -9
  81. data/lib/locomotive/steam/services/cookie_service.rb +1 -0
  82. data/lib/locomotive/steam/services/external_api_service.rb +5 -0
  83. data/lib/locomotive/steam/services/liquid_parser_service.rb +4 -2
  84. data/lib/locomotive/steam/services/page_finder_service.rb +1 -1
  85. data/lib/locomotive/steam/services/recaptcha_service.rb +4 -2
  86. data/lib/locomotive/steam/version.rb +1 -1
  87. data/lib/locomotive/steam.rb +5 -1
  88. data/locomotivecms_steam.gemspec +4 -4
  89. data/spec/fixtures/default/app/views/pages/basic.liquid.haml +1 -0
  90. data/spec/fixtures/default/app/views/pages/music.liquid.haml +6 -0
  91. data/spec/fixtures/default/app/views/sections/carousel.liquid +15 -16
  92. data/spec/fixtures/default/app/views/sections/footer.liquid +37 -3
  93. data/spec/fixtures/default/app/views/sections/header.liquid +47 -10
  94. data/spec/fixtures/default/app/views/sections/misc/hero.liquid +28 -0
  95. data/spec/fixtures/default/config/metafields_schema.yml +3 -0
  96. data/spec/integration/liquid/tags/section_spec.rb +82 -0
  97. data/spec/integration/repositories/content_entry_repository_spec.rb +9 -0
  98. data/spec/integration/server/basic_spec.rb +2 -2
  99. data/spec/integration/server/metafields_spec.rb +1 -0
  100. data/spec/integration/services/content_entry_service_spec.rb +12 -0
  101. data/spec/support/helpers.rb +1 -0
  102. data/spec/support/liquid.rb +32 -2
  103. data/spec/support/mongo.rb +1 -0
  104. data/spec/unit/adapters/filesystem/sanitizers/section_spec.rb +66 -40
  105. data/spec/unit/adapters/filesystem/yaml_loaders/section_spec.rb +25 -0
  106. data/spec/unit/errors_spec.rb +1 -1
  107. data/spec/unit/liquid/drops/content_entry_collection_spec.rb +3 -3
  108. data/spec/unit/liquid/drops/content_entry_spec.rb +4 -4
  109. data/spec/unit/liquid/drops/content_types_spec.rb +2 -2
  110. data/spec/unit/liquid/drops/metafields_spec.rb +8 -8
  111. data/spec/unit/liquid/drops/params_spec.rb +5 -5
  112. data/spec/unit/liquid/drops/section_content_proxy_spec.rb +69 -18
  113. data/spec/unit/liquid/drops/section_spec.rb +1 -1
  114. data/spec/unit/liquid/file_system_spec.rb +25 -0
  115. data/spec/unit/liquid/filters/array_spec.rb +140 -0
  116. data/spec/unit/liquid/filters/misc_spec.rb +21 -3
  117. data/spec/unit/liquid/filters/number_spec.rb +4 -4
  118. data/spec/unit/liquid/filters/text_spec.rb +4 -0
  119. data/spec/unit/liquid/tags/alt_page_links_spec.rb +19 -2
  120. data/spec/unit/liquid/tags/authorize_spec.rb +1 -1
  121. data/spec/unit/liquid/tags/editable/text_spec.rb +32 -4
  122. data/spec/unit/liquid/tags/extends_spec.rb +115 -28
  123. data/spec/unit/liquid/tags/global_section_spec.rb +4 -3
  124. data/spec/unit/liquid/tags/google_analytics_spec.rb +21 -2
  125. data/spec/unit/liquid/tags/inherited_block_spec.rb +18 -4
  126. data/spec/unit/liquid/tags/inline_editor_spec.rb +11 -0
  127. data/spec/unit/liquid/tags/link_to_spec.rb +1 -1
  128. data/spec/unit/liquid/tags/model_form_spec.rb +7 -0
  129. data/spec/unit/liquid/tags/page_not_found_spec.rb +14 -0
  130. data/spec/unit/liquid/tags/redirect_to_spec.rb +171 -0
  131. data/spec/unit/liquid/tags/section_spec.rb +43 -3
  132. data/spec/unit/liquid/tags/sections_dropzone_spec.rb +0 -1
  133. data/spec/unit/liquid/tags/snippet_spec.rb +9 -8
  134. data/spec/unit/liquid/tags/with_scope_spec.rb +80 -60
  135. data/spec/unit/middlewares/cache_spec.rb +186 -0
  136. data/spec/unit/middlewares/impersonated_entry_spec.rb +7 -0
  137. data/spec/unit/middlewares/locale_redirection_spec.rb +7 -0
  138. data/spec/unit/middlewares/locale_spec.rb +8 -1
  139. data/spec/unit/middlewares/page_not_found_spec.rb +46 -0
  140. data/spec/unit/middlewares/redirection_spec.rb +8 -0
  141. data/spec/unit/middlewares/renderer_spec.rb +64 -6
  142. data/spec/unit/middlewares/section_spec.rb +1 -0
  143. data/spec/unit/models/pager_spec.rb +11 -1
  144. data/spec/unit/repositories/section_repository_spec.rb +1 -1
  145. data/spec/unit/services/action_service_spec.rb +23 -3
  146. data/spec/unit/services/page_redirection_service_spec.rb +2 -2
  147. data/spec/unit/services/recaptcha_service_spec.rb +1 -1
  148. metadata +50 -24
@@ -5,34 +5,41 @@ module Locomotive::Steam
5
5
 
6
6
  class RedirectionException < ::Exception
7
7
 
8
- attr_reader :url
8
+ attr_reader :url, :permanent
9
9
 
10
- def initialize(url)
11
- @url = url
12
- super("Redirect to #{url}")
10
+ def initialize(url, permanent: false)
11
+ @url = url
12
+ @permanent = permanent
13
+ super("Redirect to #{url} (#{permanent ? '301': '302'})")
13
14
  end
14
15
 
15
16
  end
16
17
 
17
- class ParsingRenderingError < ::StandardError
18
+ class PageNotFoundException < ::Exception
19
+ end
20
+
21
+ class TemplateError < ::Liquid::Error
18
22
 
19
23
  LINES_RANGE = 10
20
24
 
21
- attr_accessor :file, :line, :source, :original_backtrace
25
+ attr_accessor :source, :original_backtrace
22
26
 
23
- def initialize(message, file, source, line, original_backtrace)
24
- @file, @source, @line, @original_backtrace = file, source, line, original_backtrace
27
+ def initialize(message, template_name, source, line_number, original_backtrace)
25
28
  super(message)
29
+ self.template_name = template_name
30
+ self.line_number = line_number
31
+ self.source = source
32
+ self.original_backtrace = original_backtrace
26
33
  end
27
34
 
28
35
  def code_lines
29
- return [] if source.blank? || line.nil?
36
+ return [] if source.blank? || line_number.nil?
30
37
 
31
38
  lines = source.split("\n")
32
39
 
33
- start = line - (LINES_RANGE / 2)
40
+ start = line_number - (LINES_RANGE / 2)
34
41
  start = 1 if start <= 0
35
- finish = line + (LINES_RANGE / 2)
42
+ finish = line_number + (LINES_RANGE / 2)
36
43
 
37
44
  (start..finish).map { |i| [i, lines[i - 1]] }
38
45
  end
@@ -41,21 +48,38 @@ module Locomotive::Steam
41
48
  original_backtrace
42
49
  end
43
50
 
51
+ private
52
+
53
+ def message_prefix
54
+ ""
55
+ # "Liquid parsing error - "
56
+ end
57
+
44
58
  end
45
59
 
46
- class RenderError < ParsingRenderingError
60
+ class LiquidError < TemplateError
47
61
 
48
62
  def initialize(error, file, source)
49
- message = error.message
50
- line = error.respond_to?(:line_number) ? error.line_number : error.line
51
- backtrace = error.backtrace
63
+ message = error.message
64
+ line_number = error.respond_to?(:line_number) ? error.line_number : error.line
65
+ backtrace = error.backtrace
52
66
 
53
- super(message, file, source, line, backtrace)
67
+ super(message, file, source, line_number, backtrace)
54
68
  end
55
69
 
56
70
  end
57
71
 
58
- class JsonParsingError < ParsingRenderingError
72
+ class RenderError < LiquidError
73
+
74
+ private
75
+
76
+ def message_prefix
77
+ "Render - "
78
+ end
79
+
80
+ end
81
+
82
+ class JsonParsingError < TemplateError
59
83
 
60
84
  def initialize(error, file, source)
61
85
  line = if error.message =~ /at line ([0-9]+)/
@@ -67,9 +91,15 @@ module Locomotive::Steam
67
91
  super(error.message, file, source, line, error.backtrace)
68
92
  end
69
93
 
94
+ private
95
+
96
+ def message_prefix
97
+ "JSON parsing error - "
98
+ end
99
+
70
100
  end
71
101
 
72
- class ActionError < ParsingRenderingError
102
+ class ActionError < TemplateError
73
103
 
74
104
  attr_accessor :action
75
105
 
@@ -77,6 +107,12 @@ module Locomotive::Steam
77
107
  super(error.message, nil, script, 0, error.backtrace)
78
108
  end
79
109
 
110
+ private
111
+
112
+ def message_prefix
113
+ "Action error - "
114
+ end
115
+
80
116
  end
81
117
 
82
118
  end
@@ -50,7 +50,7 @@ module Locomotive
50
50
  end
51
51
  end
52
52
 
53
- def before_method(meth)
53
+ def liquid_method_missing(meth)
54
54
  return '' if @_source.nil?
55
55
 
56
56
  if not @@forbidden_attributes.include?(meth.to_s)
@@ -38,7 +38,7 @@ module Locomotive
38
38
  { 'create' => public_submission_url }
39
39
  end
40
40
 
41
- def before_method(meth)
41
+ def liquid_method_missing(meth)
42
42
  if (meth.to_s =~ /^group_by_(.+)$/) == 0
43
43
  repository.group_by_select_option($1)
44
44
  elsif (meth.to_s =~ /^(.+)_options$/) == 0
@@ -4,7 +4,7 @@ module Locomotive
4
4
  module Drops
5
5
  class ContentTypes < ::Liquid::Drop
6
6
 
7
- def before_method(meth)
7
+ def liquid_method_missing(meth)
8
8
  if content_type = fetch_content_type(meth.to_s)
9
9
  ContentEntryCollection.new(content_type)
10
10
  else
@@ -0,0 +1,28 @@
1
+ module Locomotive
2
+ module Steam
3
+ module Liquid
4
+ module Drops
5
+
6
+ # Used to render the content of the parent block.
7
+ #
8
+ # {% extends home %}
9
+ # {% block content }{{ block.super }}{% endblock %}
10
+ #
11
+ class InheritedBlock < ::Liquid::Drop
12
+ def initialize(block)
13
+ @block = block
14
+ end
15
+
16
+ def name
17
+ @block.name
18
+ end
19
+
20
+ def super
21
+ @block.call_super(@context)
22
+ end
23
+ end
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -10,7 +10,7 @@ module Locomotive
10
10
  alias :count :size
11
11
  alias :length :size
12
12
 
13
- def before_method(meth)
13
+ def liquid_method_missing(meth)
14
14
  find_value(meth.to_s)
15
15
  end
16
16
 
@@ -79,7 +79,7 @@ module Locomotive
79
79
 
80
80
  class Metafields < Base
81
81
 
82
- def before_method(meth)
82
+ def liquid_method_missing(meth)
83
83
  find_namespace(meth.to_s)
84
84
  end
85
85
 
@@ -9,7 +9,7 @@ module Locomotive
9
9
  @_params = params.stringify_keys
10
10
  end
11
11
 
12
- def before_method(meth)
12
+ def liquid_method_missing(meth)
13
13
  Param.new(@_params[meth.to_s])
14
14
  end
15
15
 
@@ -38,8 +38,16 @@ module Locomotive
38
38
  @section.definition['class']
39
39
  end
40
40
 
41
- def anchor
42
- @content['anchor'] || id
41
+ def anchor_id
42
+ "#{@content['anchor'] || id}-section"
43
+ end
44
+
45
+ def locomotive_attributes
46
+ %(data-locomotive-section-id="#{id}" data-locomotive-section-type="#{type}").tap do
47
+ # let Steam know that we won't need to wrap the section HTML
48
+ # into an extra DIV layer.
49
+ @context['is_section_locomotive_attributes_displayed'] = true
50
+ end
43
51
  end
44
52
 
45
53
  def blocks
@@ -12,12 +12,15 @@ module Locomotive
12
12
  @content, @settings = content, settings
13
13
  end
14
14
 
15
- def before_method(name)
15
+ def liquid_method_missing(name)
16
16
  value = @content[name.to_s]
17
17
 
18
+ return nil if value.blank?
19
+
18
20
  case type_of(name)
19
21
  when 'url' then SectionUrlField.new(*url_finder.url_for(value))
20
22
  when 'image_picker' then SectionImagePickerField.new(value)
23
+ when 'integer' then value.to_i
21
24
  when 'text' then url_finder.decode_urls_for(value)
22
25
  else value
23
26
  end
@@ -68,6 +71,10 @@ module Locomotive
68
71
  @attributes[:cropped]
69
72
  end
70
73
 
74
+ def present?
75
+ self.source.present?
76
+ end
77
+
71
78
  def to_s
72
79
  self.cropped || self.source || ''
73
80
  end
@@ -78,7 +85,7 @@ module Locomotive
78
85
  class SectionUrlField < ::Liquid::Drop
79
86
 
80
87
  def initialize(url, new_window = false)
81
- @url, @new_window = url || '#', new_window
88
+ @url, @new_window = url, new_window
82
89
  end
83
90
 
84
91
  def new_window
@@ -89,6 +96,10 @@ module Locomotive
89
96
  !!@new_window ? 'target="_blank"' : ''
90
97
  end
91
98
 
99
+ def present?
100
+ @url.present?
101
+ end
102
+
92
103
  def to_s
93
104
  @url
94
105
  end
@@ -11,7 +11,7 @@ module Locomotive
11
11
  @section = section
12
12
  end
13
13
 
14
- def before_method(meth)
14
+ def liquid_method_missing(meth)
15
15
  block = nil
16
16
  prefix = "section-#{@context['section'].id}"
17
17
  matches = (@context['forloop.name'] || '').match(SECTIONS_BLOCK_FORLOOP_REGEXP)
@@ -5,7 +5,7 @@ module Locomotive
5
5
 
6
6
  class SessionProxy < ::Liquid::Drop
7
7
 
8
- def before_method(meth)
8
+ def liquid_method_missing(meth)
9
9
  request = @context.registers[:request]
10
10
  request.session[meth.to_sym]
11
11
  end
@@ -0,0 +1,46 @@
1
+ module Locomotive
2
+ module Steam
3
+ module Liquid
4
+
5
+ # A Liquid file system is a way to let your templates retrieve other templates for use with the include and sections tags.
6
+ #
7
+ # Example:
8
+ #
9
+ # Liquid::Template.file_system = Liquid::LocalFileSystem.new(template_path)
10
+ # liquid = Liquid::Template.parse(template)
11
+ #
12
+ # This will parse the template from both the DB or the Filesystem.
13
+ #
14
+ class FileSystem
15
+
16
+ attr_reader :section_finder, :snippet_finder
17
+
18
+ def initialize(section_finder: nil, snippet_finder: nil)
19
+ @section_finder, @snippet_finder = section_finder, snippet_finder
20
+ end
21
+
22
+ # Called by Liquid to retrieve a template file
23
+ def read_template_file(template_path)
24
+ type, name = template_path.split('--')
25
+
26
+ entity = (
27
+ case type
28
+ when 'sections'
29
+ section_finder.find(name)
30
+ when 'snippets'
31
+ snippet_finder.find(name)
32
+ else
33
+ raise ::Liquid::FileSystemError, "This liquid context does not allow #{type}."
34
+ end
35
+ )
36
+
37
+ raise ::Liquid::FileSystemError, "Unable to find #{name} in the #{type} folder" if entity.nil?
38
+
39
+ entity.liquid_source
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,61 @@
1
+ module Locomotive
2
+ module Steam
3
+ module Liquid
4
+ module Filters
5
+
6
+ module Array
7
+
8
+ def pop(array, input = 1)
9
+ return array unless array.is_a?(::Array)
10
+ new_ary = array.dup
11
+ new_ary.pop(input.to_i || 1)
12
+ new_ary
13
+ end
14
+
15
+ def push(array, input)
16
+ return array unless array.is_a?(::Array)
17
+ new_ary = array.dup
18
+ new_ary.push(input)
19
+ new_ary
20
+ end
21
+
22
+ def shift(array, input = 1)
23
+ return array unless array.is_a?(::Array)
24
+ new_ary = array.dup
25
+ new_ary.shift(input.to_i || 1)
26
+ new_ary
27
+ end
28
+
29
+ def unshift(array, input)
30
+ return array unless array.is_a?(::Array)
31
+ new_ary = array.dup
32
+ new_ary.unshift(*input)
33
+ new_ary
34
+ end
35
+
36
+ def in_groups_of(array, number, fill_with = nil)
37
+ return array unless array.respond_to?(:all) || array.respond_to?(:each_slice)
38
+
39
+ number = number.to_i
40
+ grouped_array = array.respond_to?(:all) ? array.all : array
41
+
42
+ if fill_with != false
43
+ # size % number gives how many extra we have;
44
+ # subtracting from number gives how many to add;
45
+ # modulo number ensures we don't add group of just fill.
46
+ padding = (number - grouped_array.size % number) % number
47
+ grouped_array = grouped_array + ::Array.new(padding, fill_with)
48
+ end
49
+
50
+ grouped_array.each_slice(number).to_a
51
+ end
52
+
53
+ end
54
+
55
+ ::Liquid::Template.register_filter(Array)
56
+
57
+ end
58
+
59
+ end
60
+ end
61
+ end
@@ -4,6 +4,14 @@ module Locomotive
4
4
  module Filters
5
5
  module Misc
6
6
 
7
+ def blank?(input)
8
+ input.blank?
9
+ end
10
+
11
+ def present?(input)
12
+ input.present?
13
+ end
14
+
7
15
  # was called modulo at first
8
16
  def str_modulo(word, index, modulo)
9
17
  (index.to_i + 1) % modulo == 0 ? word : ''
@@ -38,10 +46,12 @@ module Locomotive
38
46
  elsif property == 'to_i'.freeze
39
47
  e.to_i
40
48
  elsif e.respond_to?(:[])
41
- e[property]
49
+ r = e[property]
50
+ r.is_a?(Proc) ? r.call : r
42
51
  end
43
52
  end
44
-
53
+ rescue TypeError
54
+ raise_property_error(property)
45
55
  end
46
56
 
47
57
  def hexdigest(input, key, digest = nil)
@@ -4,15 +4,15 @@ module Locomotive
4
4
  module Filters
5
5
  module Number
6
6
 
7
- def money(input, *options)
7
+ def money(input, options = nil)
8
8
  NumberProxyHelper.new(:currency, @context).invoke(input, options)
9
9
  end
10
10
 
11
- def percentage(input, *options)
11
+ def percentage(input, options = nil)
12
12
  NumberProxyHelper.new(:percentage, @context).invoke(input, options)
13
13
  end
14
14
 
15
- def human_size(input, *options)
15
+ def human_size(input, options = nil)
16
16
  NumberProxyHelper.new(:human_size, @context).invoke(input, options)
17
17
  end
18
18
 
@@ -30,17 +30,18 @@ module Locomotive
30
30
  end
31
31
 
32
32
  def invoke(input, options)
33
- _options = parse_and_interpolate_options(options)
34
- send :"number_to_#{@name}", input, _options
33
+ send :"number_to_#{@name}", input, interpolate_options(options)
35
34
  end
36
35
 
37
- def parse_and_interpolate_options(string_or_array)
38
- return {} if string_or_array.empty?
39
-
40
- string = [*string_or_array].flatten.join(', ')
41
- arguments = Solid::Arguments.parse(string)
42
-
43
- (arguments.interpolate(@context).first || {})
36
+ def interpolate_options(options)
37
+ (options || {}).transform_values do |option|
38
+ if option.is_a?(String)
39
+ _option = ::Liquid::Expression.parse(option)
40
+ @context.evaluate(_option) || option
41
+ else
42
+ option
43
+ end
44
+ end
44
45
  end
45
46
 
46
47
  end
@@ -16,6 +16,10 @@ module Locomotive
16
16
  Rack::Utils.escape(input)
17
17
  end
18
18
 
19
+ def parameterize(input)
20
+ input.parameterize
21
+ end
22
+
19
23
  # alias newline_to_br
20
24
  def multi_line(input)
21
25
  input.to_s.gsub("\n", '<br/>')
@@ -1,9 +1,48 @@
1
+ # Enhance the IF condition to write the following statement:
2
+ #
3
+ # {% if value is present %}Value is not blank{% endif %}
4
+ #
5
+ Liquid::Condition.operators['is'.freeze] = lambda { |cond, left, right| cond.send(:equal_variables, left, right) }
6
+
1
7
  module Liquid
8
+
9
+ class Expression
10
+
11
+ class << self
12
+ alias_method :parse_without_extra_literals, :parse
13
+ end
14
+
15
+ EXTRA_LITERALS = {
16
+ 'present' => MethodLiteral.new(:present?, '').freeze
17
+ }.freeze
18
+
19
+ def self.parse(markup)
20
+ if EXTRA_LITERALS.key?(markup)
21
+ EXTRA_LITERALS[markup]
22
+ else
23
+ parse_without_extra_literals(markup)
24
+ end
25
+ end
26
+
27
+ end
28
+
29
+ class ParseContext
30
+
31
+ def []=(option_key, value)
32
+ @options[option_key] = value
33
+ end
34
+
35
+ def merge(options)
36
+ @template_options.merge(options)
37
+ end
38
+
39
+ end
40
+
2
41
  module StandardFilters
3
42
 
4
43
  private
5
44
 
6
- # Fixme: Handle DateTime, Date and Time objects, convert them
45
+ # FIXME: Handle DateTime, Date and Time objects, convert them
7
46
  # into seconds (integer)
8
47
  def to_number(obj)
9
48
  case obj
@@ -19,32 +58,32 @@ module Liquid
19
58
  end
20
59
 
21
60
  end
22
- end
23
61
 
24
- module Liquid
25
- module OptionsBuilder
26
-
27
- private
62
+ class PartialCache
28
63
 
29
- def parse_options_from_string(string)
30
- string.try(:strip!)
64
+ def self.load(template_name, context:, parse_context:)
65
+ begin
66
+ cached_partials = (context.registers[:cached_partials] ||= {})
67
+ cached = cached_partials[template_name]
68
+ return cached if cached
31
69
 
32
- return nil if string.blank?
70
+ file_system = (context.registers[:file_system] ||= ::Liquid::Template.file_system)
71
+ source = file_system.read_template_file(template_name)
72
+ parse_context.partial = true
33
73
 
34
- string = string.gsub(/^(\s*,)/, '')
74
+ partial = ::Liquid::Template.parse(source, parse_context)
75
+ cached_partials[template_name] = partial
35
76
 
36
- Solid::Arguments.parse(string)
37
- end
38
77
 
39
- def interpolate_options(options, context)
40
- if options
41
- options.interpolate(context).first
42
- else
43
- {}
78
+ rescue ::Liquid::SyntaxError => e
79
+ # FIXME: we had to reload the template one more time. Not ideal.
80
+ file_system = (context.registers[:file_system] ||= ::Liquid::Template.file_system)
81
+ source = file_system.read_template_file(template_name)
82
+ raise Locomotive::Steam::LiquidError.new(e, template_name, source)
44
83
  end
84
+ ensure
85
+ parse_context.partial = false
45
86
  end
46
87
 
47
88
  end
48
89
  end
49
-
50
- Liquid::Tag.send(:include, Liquid::OptionsBuilder)
@@ -13,10 +13,12 @@ module Locomotive
13
13
  if @site.locales.size == 1
14
14
  ''
15
15
  else
16
+ ending_path = context['alt_page_links_ending_path'] || ''
17
+
16
18
  (
17
- [%(<link rel="alternate" hreflang="x-default" href="#{url_for(@site.default_locale, true)}" />)] +
19
+ [%(<link rel="alternate" hreflang="x-default" href="#{url_for(@site.default_locale, ending_path, true)}" />)] +
18
20
  @site.locales.map do |locale|
19
- %(<link rel="alternate" hreflang="#{locale}" href="#{url_for(locale)}" />)
21
+ %(<link rel="alternate" hreflang="#{locale}" href="#{url_for(locale, ending_path)}" />)
20
22
  end
21
23
  ).join("\n")
22
24
  end
@@ -30,15 +32,17 @@ module Locomotive
30
32
  #
31
33
  # Note: the index page has a different behaviour because rendering "/" depends
32
34
  # on the language returned by the browser (so might be different based on the user session).
33
- def url_for(locale, default = false)
35
+ def url_for(locale, ending_path = '', default = false)
34
36
  change_page_locale(locale, @page) do
35
- fullpath = services.url_builder.url_for(@page.send(:_source), locale, @page.index? && !default ? true : nil)
37
+ fullpath = services.url_builder.url_for(@page.send(:_source), locale, @site.prefix_default_locale) #@page.index? && !default ? true : nil)
36
38
 
37
39
  if @page.index? && default
38
40
  fullpath.gsub!(/\/#{locale}$/, '/')
39
41
  end
40
42
 
41
- @base_url + fullpath
43
+ fullpath.gsub!(/\/$/, '') if ending_path.present?
44
+
45
+ @base_url + fullpath + ending_path
42
46
  end
43
47
  end
44
48
 
@@ -0,0 +1,47 @@
1
+ module Locomotive
2
+ module Steam
3
+ module Liquid
4
+ module Tags
5
+ module Concerns
6
+
7
+ # Many of Liquid tags have attributes (like options)
8
+ # This module makes sure we use the same reliable way to
9
+ # extract and evaluate them.
10
+
11
+ module Attributes
12
+
13
+ attr_reader :attributes, :raw_attributes
14
+
15
+ private
16
+
17
+ def parse_attributes(markup, default = {})
18
+ @attributes = default || {}
19
+ @raw_attributes = {}
20
+
21
+ return if markup.blank?
22
+
23
+ markup.scan(tag_attributes_regexp) do |key, value|
24
+ _key = key.to_sym
25
+
26
+ @attributes[_key] = block_given? ? yield(value) : ::Liquid::Expression.parse(value)
27
+ @raw_attributes[_key] = value
28
+ end
29
+ end
30
+
31
+ def evaluate_attributes(context)
32
+ @attributes = @attributes.transform_values do |attribute|
33
+ context.evaluate(attribute)
34
+ end
35
+ end
36
+
37
+ def tag_attributes_regexp
38
+ ::Liquid::TagAttributes
39
+ end
40
+
41
+ end
42
+
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end