shoperb_liquid 0.0.1

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.
Files changed (102) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.rubocop.yml +131 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +143 -0
  7. data/Rakefile +4 -0
  8. data/lib/shoperb_liquid/configuration.rb +169 -0
  9. data/lib/shoperb_liquid/drops/account_drop.rb +9 -0
  10. data/lib/shoperb_liquid/drops/address_drop.rb +121 -0
  11. data/lib/shoperb_liquid/drops/array_drop.rb +18 -0
  12. data/lib/shoperb_liquid/drops/attribute_drop.rb +21 -0
  13. data/lib/shoperb_liquid/drops/base.rb +65 -0
  14. data/lib/shoperb_liquid/drops/blog_category_drop.rb +56 -0
  15. data/lib/shoperb_liquid/drops/blog_post_drop.rb +46 -0
  16. data/lib/shoperb_liquid/drops/cart_drop.rb +42 -0
  17. data/lib/shoperb_liquid/drops/cart_item_drop.rb +111 -0
  18. data/lib/shoperb_liquid/drops/categories_drop.rb +13 -0
  19. data/lib/shoperb_liquid/drops/category_drop.rb +110 -0
  20. data/lib/shoperb_liquid/drops/collection_drop.rb +117 -0
  21. data/lib/shoperb_liquid/drops/country_drop.rb +37 -0
  22. data/lib/shoperb_liquid/drops/currency_drop.rb +17 -0
  23. data/lib/shoperb_liquid/drops/customer_credit_drop.rb +23 -0
  24. data/lib/shoperb_liquid/drops/customer_credits_drop.rb +18 -0
  25. data/lib/shoperb_liquid/drops/customer_drop.rb +108 -0
  26. data/lib/shoperb_liquid/drops/customer_group_drop.rb +17 -0
  27. data/lib/shoperb_liquid/drops/gift_card_drop.rb +34 -0
  28. data/lib/shoperb_liquid/drops/image_drop.rb +27 -0
  29. data/lib/shoperb_liquid/drops/integration_drop.rb +25 -0
  30. data/lib/shoperb_liquid/drops/integrations_drop.rb +17 -0
  31. data/lib/shoperb_liquid/drops/language_drop.rb +17 -0
  32. data/lib/shoperb_liquid/drops/link_drop.rb +53 -0
  33. data/lib/shoperb_liquid/drops/media_file_drop.rb +29 -0
  34. data/lib/shoperb_liquid/drops/menu_drop.rb +25 -0
  35. data/lib/shoperb_liquid/drops/menus_drop.rb +16 -0
  36. data/lib/shoperb_liquid/drops/meta_drop.rb +21 -0
  37. data/lib/shoperb_liquid/drops/order_drop.rb +148 -0
  38. data/lib/shoperb_liquid/drops/order_item_attribute_drop.rb +8 -0
  39. data/lib/shoperb_liquid/drops/order_item_attributes_drop.rb +19 -0
  40. data/lib/shoperb_liquid/drops/order_item_drop.rb +159 -0
  41. data/lib/shoperb_liquid/drops/order_return_drop.rb +43 -0
  42. data/lib/shoperb_liquid/drops/order_return_item_drop.rb +30 -0
  43. data/lib/shoperb_liquid/drops/order_return_item_entity_drop.rb +13 -0
  44. data/lib/shoperb_liquid/drops/order_return_parcel_drop.rb +29 -0
  45. data/lib/shoperb_liquid/drops/order_returns_drop.rb +13 -0
  46. data/lib/shoperb_liquid/drops/orders_drop.rb +14 -0
  47. data/lib/shoperb_liquid/drops/page_drop.rb +26 -0
  48. data/lib/shoperb_liquid/drops/pages_drop.rb +12 -0
  49. data/lib/shoperb_liquid/drops/payment_card_drop.rb +29 -0
  50. data/lib/shoperb_liquid/drops/payment_method_drop.rb +41 -0
  51. data/lib/shoperb_liquid/drops/payment_provider_drop.rb +23 -0
  52. data/lib/shoperb_liquid/drops/product_attribute_drop.rb +14 -0
  53. data/lib/shoperb_liquid/drops/product_collection_drop.rb +41 -0
  54. data/lib/shoperb_liquid/drops/product_collections_drop.rb +12 -0
  55. data/lib/shoperb_liquid/drops/product_drop.rb +195 -0
  56. data/lib/shoperb_liquid/drops/product_type_drop.rb +25 -0
  57. data/lib/shoperb_liquid/drops/product_types_drop.rb +15 -0
  58. data/lib/shoperb_liquid/drops/products_drop.rb +44 -0
  59. data/lib/shoperb_liquid/drops/refund_drop.rb +22 -0
  60. data/lib/shoperb_liquid/drops/refund_item_drop.rb +18 -0
  61. data/lib/shoperb_liquid/drops/review_drop.rb +37 -0
  62. data/lib/shoperb_liquid/drops/search_drop.rb +45 -0
  63. data/lib/shoperb_liquid/drops/shipping_item_drop.rb +29 -0
  64. data/lib/shoperb_liquid/drops/shipping_method_drop.rb +25 -0
  65. data/lib/shoperb_liquid/drops/shipping_parcel_drop.rb +25 -0
  66. data/lib/shoperb_liquid/drops/shop_drop.rb +81 -0
  67. data/lib/shoperb_liquid/drops/subscription_drop.rb +51 -0
  68. data/lib/shoperb_liquid/drops/subscription_plan_drop.rb +63 -0
  69. data/lib/shoperb_liquid/drops/theme_section_blocks_drop.rb +19 -0
  70. data/lib/shoperb_liquid/drops/theme_section_drop.rb +30 -0
  71. data/lib/shoperb_liquid/drops/theme_section_image_drop.rb +11 -0
  72. data/lib/shoperb_liquid/drops/theme_section_settings_drop.rb +40 -0
  73. data/lib/shoperb_liquid/drops/theme_settings_drop.rb +60 -0
  74. data/lib/shoperb_liquid/drops/url_drop.rb +218 -0
  75. data/lib/shoperb_liquid/drops/variant_attribute_drop.rb +8 -0
  76. data/lib/shoperb_liquid/drops/variant_drop.rb +206 -0
  77. data/lib/shoperb_liquid/drops/variants_drop.rb +13 -0
  78. data/lib/shoperb_liquid/drops/vendor_drop.rb +77 -0
  79. data/lib/shoperb_liquid/drops/vendors_drop.rb +13 -0
  80. data/lib/shoperb_liquid/errors.rb +6 -0
  81. data/lib/shoperb_liquid/ext/array.rb +7 -0
  82. data/lib/shoperb_liquid/ext/context.rb +12 -0
  83. data/lib/shoperb_liquid/ext/models.rb +55 -0
  84. data/lib/shoperb_liquid/ext/template.rb +13 -0
  85. data/lib/shoperb_liquid/filters/asset_filters.rb +57 -0
  86. data/lib/shoperb_liquid/filters/collection_filters.rb +26 -0
  87. data/lib/shoperb_liquid/filters/datum_filters.rb +150 -0
  88. data/lib/shoperb_liquid/filters/extension_filters.rb +35 -0
  89. data/lib/shoperb_liquid/filters/html_filters.rb +46 -0
  90. data/lib/shoperb_liquid/filters/theme_filters.rb +22 -0
  91. data/lib/shoperb_liquid/filters/translate_filters.rb +16 -0
  92. data/lib/shoperb_liquid/filters/url_filters.rb +60 -0
  93. data/lib/shoperb_liquid/registers.rb +76 -0
  94. data/lib/shoperb_liquid/tags/cache_tag.rb +45 -0
  95. data/lib/shoperb_liquid/tags/form_tag.rb +47 -0
  96. data/lib/shoperb_liquid/tags/layout_tag.rb +21 -0
  97. data/lib/shoperb_liquid/tags/paginate_tag.rb +134 -0
  98. data/lib/shoperb_liquid/tags/products_filter_tag.rb +106 -0
  99. data/lib/shoperb_liquid/tags/section_tag.rb +113 -0
  100. data/lib/shoperb_liquid.rb +46 -0
  101. data/shoperb_liquid.gemspec +24 -0
  102. metadata +223 -0
@@ -0,0 +1,26 @@
1
+ module ShoperbLiquid
2
+ module CollectionFilters
3
+
4
+ def with_custom_field(input, name, value, leave_blank=true)
5
+ ary = Liquid::StandardFilters::InputIterator.new(input, context)
6
+
7
+ ary.select do |el|
8
+ hash_value = el.custom_fields[name]
9
+ if hash_value
10
+ if hash_value["set_values"] == []
11
+ leave_blank
12
+ elsif !value || value == ""
13
+ false
14
+ else
15
+ hash_value["set_values"].include?(value)
16
+ end
17
+ else
18
+ # if true and not present, then leacing in collection
19
+ leave_blank
20
+ end
21
+ end
22
+ # filter_array(input, property, target_value) { |ary, &block| ary.select(&block) }
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShoperbLiquid
4
+ #
5
+ # Helpers for working with strings,
6
+ # numbers, money, dates, weight units
7
+ #
8
+ module DatumFilters
9
+ include ActionView::Helpers::NumberHelper
10
+ include ActionView::Helpers::OutputSafetyHelper
11
+
12
+ # either with symbol or code
13
+ def money(money)
14
+ _money(money, precision: money_precision(money))
15
+ end
16
+
17
+ def money_with_cents(money)
18
+ _money(money, precision: 2)
19
+ end
20
+
21
+ # with both symbol and code
22
+ def money_with_currency(money)
23
+ "#{_money(money, precision: 2)} #{shop.currency.code}"
24
+ end
25
+
26
+ def money_precision(money)
27
+ fmt = "%05.2f" % money.to_f
28
+ _, cost_cents = fmt.split "."
29
+
30
+ cost_cents.to_i == 0 ? 0 : 2
31
+ end
32
+
33
+ # just numbers
34
+ def money_without_currency(money)
35
+ number_to_currency(money, unit: "", delimiter: " ")
36
+ end
37
+
38
+ def without_cents(money)
39
+ money.to_i
40
+ end
41
+
42
+ def num_with_2_meaning_nums(money)
43
+ "%05.2f" % money
44
+ end
45
+
46
+ def weight_with_unit(weight, precision=nil)
47
+ return if weight.nil?
48
+
49
+ weight = "%.#{precision}f" % weight if precision
50
+
51
+ "#{weight} #{shop.metric? ? "kg" : "lbs"}" # TODO
52
+ end
53
+
54
+ def dimension_with_unit(size)
55
+ "#{size} #{shop.metric? ? "cm" : "inch"}" # TODO
56
+ end
57
+
58
+ def upcase(value)
59
+ value.to_s.upcase
60
+ end
61
+
62
+ def downcase(value)
63
+ value.to_s.downcase
64
+ end
65
+
66
+ def titleize(value)
67
+ value.to_s.titlecase
68
+ end
69
+
70
+ def size(value)
71
+ value.size rescue value.to_s.size
72
+ end
73
+
74
+ def date(value, formatting)
75
+ return unless value
76
+
77
+ value = Time.at(value) if value.is_a?(Integer)
78
+ value = Time.now if value.eql?("now")
79
+ date = value.kind_of?(String) ? Date.parse(value) : value
80
+ I18n.l(date, format: formatting)
81
+ end
82
+
83
+ def pluck(value, key)
84
+ value.pluck(key)
85
+ end
86
+
87
+ def json(value)
88
+ value.to_json if value.is_a?(CollectionDrop)
89
+ end
90
+
91
+ def debug(object)
92
+ safe_join(["<pre>".html_safe, object.inspect, "</pre>".html_safe], "\n")
93
+ end
94
+
95
+ def numeric(value)
96
+ value.to_i
97
+ end
98
+
99
+ def plus(value, add)
100
+ value.to_i + add
101
+ end
102
+
103
+ def minus(value, remove)
104
+ value.to_i - remove
105
+ end
106
+
107
+ def decimal_plus(value, add)
108
+ value.to_d + add.to_d
109
+ end
110
+
111
+ def decimal_minus(value, remove)
112
+ value.to_d - remove.to_d
113
+ end
114
+
115
+ # we use default times filter
116
+ # def times(value, times)
117
+ # value.to_i * times.to_i
118
+ # end
119
+
120
+ def decimal_times(value, times)
121
+ value.to_d * times.to_d
122
+ end
123
+
124
+ def random(value, limit=nil)
125
+ return value unless limit
126
+ value.to_a.sample limit
127
+ end
128
+ deprecate :random, deprecator: ::ActiveSupport::Deprecation
129
+
130
+ def sum(collection, field)
131
+ collection.pluck(field).sum
132
+ end
133
+
134
+ protected
135
+
136
+ def shop
137
+ @context["shop"]
138
+ end
139
+
140
+ private
141
+
142
+ def _money(money, **args)
143
+ if shop.currency.symbol
144
+ number_to_currency(money, unit: shop.currency.symbol, format: "%u%n", delimiter: " ", **args)
145
+ else
146
+ number_to_currency(money, unit: shop.currency.code, format: "%n %u", delimiter: " ", **args)
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShoperbLiquid
4
+ #
5
+ # Translating of strings in the theme
6
+ #
7
+ module ExtensionFilters
8
+ def sort(input, property = nil)
9
+ if input.is_a?(Hash)
10
+ # replacing values
11
+ property = 0 if property == "key"
12
+ property = 1 if property == "value"
13
+
14
+ ret = if property
15
+ input.sort{|a,b| nil_safe_compare(a[property],b[property])}.to_h
16
+ else
17
+ input.sort{|a,b| nil_safe_compare(a,b)}.to_h
18
+ end
19
+ return ret
20
+ end
21
+ super
22
+ end
23
+
24
+ def nil_safe_compare(a, b)
25
+ a = a.to_s if a.is_a?(Array)
26
+ b = b.inspect if b.is_a?(Array)
27
+ if !a.nil? && !b.nil?
28
+ a <=> b
29
+ else
30
+ a.nil? ? 1 : -1
31
+ end
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,46 @@
1
+ module ShoperbLiquid
2
+ module HtmlFilters
3
+ def modulo_word(word, index, modulo)
4
+ index.to_i % modulo == 0 ? word : ""
5
+ end
6
+
7
+ def default_pagination(paginate, *args)
8
+ return "" if paginate["parts"].empty?
9
+
10
+ previous_label = ShoperbLiquid.config.translator.translate("navigation.previous")
11
+ next_label = ShoperbLiquid.config.translator.translate("navigation.next")
12
+
13
+ previous_link = link("previous", previous_label, paginate)
14
+ next_link = link("next", next_label, paginate)
15
+
16
+ links = ""
17
+ paginate["parts"].each do |part|
18
+ links << (if part["is_link"]
19
+ "<a class=\"page\" href=\"#{part["url"]}\">#{part["title"]}</a>"
20
+ elsif part["current"]
21
+ "<span class=\"page current\">#{part["title"]}</span>"
22
+ else
23
+ "<span class=\"page gap\">#{part["title"]}</span>"
24
+ end)
25
+ end
26
+
27
+ %{
28
+ <div class="pagination">
29
+ #{previous_link}
30
+ #{links}
31
+ #{next_link}
32
+ </div>
33
+ }
34
+ end
35
+
36
+ private
37
+
38
+ def link(type, label, paginate)
39
+ if paginate[type].blank?
40
+ "<span class=\"disabled prev-page\">#{label}</span>"
41
+ else
42
+ "<a href=\"#{paginate[type]["url"]}\" class=\"prev-page\">#{label}</a>"
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShoperbLiquid
4
+ module ThemeFilters
5
+ #
6
+ # returns content with values
7
+ # taken from settins
8
+ #
9
+ def customize(asset_path, settings_drop)
10
+ Theme.current.assets.find_by(
11
+ file: asset_path
12
+ ).customize(
13
+ settings_drop,
14
+ host: ShoperbLiquid.config.assets_remote_host
15
+ )
16
+ end
17
+
18
+ def image_size(image, size)
19
+ (image[size].try(:url) if image) || image
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShoperbLiquid
4
+ #
5
+ # Translating of strings in the theme
6
+ #
7
+ module TranslateFilters
8
+ def translate(string, args = {})
9
+ args[:theme] = @context.registers[:theme]
10
+ translation = ShoperbLiquid.config.translator.translate(string, **args.symbolize_keys)
11
+ Liquid::Template.parse(translation || "").render(args.stringify_keys)
12
+ end
13
+
14
+ alias_method :t, :translate
15
+ end
16
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShoperbLiquid
4
+ module UrlFilters
5
+ include ActionView::Helpers::UrlHelper
6
+
7
+ def link_to_category(category)
8
+ link_to category.name, category.url, category.name
9
+ end
10
+
11
+ def link_to_product(product)
12
+ link_to product.name, product.url, product.name
13
+ end
14
+
15
+ def link_to_page(page)
16
+ link_to page.name, page.url, page.name
17
+ end
18
+
19
+ def link_to_collection(collection)
20
+ link_to collection.name, collection.url, collection.name
21
+ end
22
+
23
+ def link_to_order(obj)
24
+ link_to obj.name, obj.url, obj.name
25
+ end
26
+
27
+ def link_to_locale(text, locale)
28
+ link_to text, url_to_locale(locale)
29
+ end
30
+
31
+ def url_to_locale(locale)
32
+ pars = {locale: locale}
33
+ pars[:query] = @context["params"]["query"] if @context["params"]["query"].present? # need for search
34
+
35
+ controller = @context.registers[:controller]
36
+ if @context["params"]["id"] && (obj = @context["object"]) && obj.respond_to?(:permalink)
37
+ pars["id"] = in_locale(locale) {obj.record.to_param}
38
+ end
39
+ controller.url_for(pars)
40
+ end
41
+
42
+ def link_to_root(text)
43
+ link_to text, "/#{@context["params"]["locale"]}"
44
+ end
45
+
46
+ def link_to(text, url, title=nil)
47
+ super text, url, title: title
48
+ end
49
+
50
+ private
51
+ def in_locale(local_locale)
52
+ klass = ::Shoperb::Theme::Editor::Translations
53
+ old = klass.locale
54
+ klass.locale = local_locale
55
+ resp = yield
56
+ klass.locale = old
57
+ resp
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "request_store"
4
+
5
+ module ShoperbLiquid
6
+ module Registers
7
+ extend self
8
+
9
+ def register_filters
10
+ Liquid::Environment.default.register_filter ShoperbLiquid::UrlFilters
11
+ Liquid::Environment.default.register_filter ShoperbLiquid::DatumFilters
12
+ Liquid::Environment.default.register_filter ShoperbLiquid::AssetFilters
13
+ Liquid::Environment.default.register_filter ShoperbLiquid::CollectionFilters
14
+ Liquid::Environment.default.register_filter ShoperbLiquid::HtmlFilters
15
+ Liquid::Environment.default.register_filter ShoperbLiquid::TranslateFilters
16
+ Liquid::Environment.default.register_filter ShoperbLiquid::ExtensionFilters
17
+ Liquid::Environment.default.register_filter ShoperbLiquid::ThemeFilters
18
+ end
19
+
20
+ def register_tags
21
+ Liquid::Environment.default.register_tag "layout", ShoperbLiquid::LayoutTag
22
+ Liquid::Environment.default.register_tag "paginate", ShoperbLiquid::PaginateTag
23
+ Liquid::Environment.default.register_tag "form", ShoperbLiquid::FormTag
24
+ Liquid::Environment.default.register_tag "section", ShoperbLiquid::SectionTag
25
+ Liquid::Environment.default.register_tag "cache", ShoperbLiquid::CacheTag
26
+ Liquid::Environment.default.register_tag "products_filter", ShoperbLiquid::ProductsFilterTag
27
+ ''
28
+ end
29
+
30
+ def options(context, locals)
31
+ context.instance_eval do
32
+ params = self.params
33
+ params = params.to_unsafe_h if params.respond_to?(:to_unsafe_h)
34
+ params = params.to_h.with_indifferent_access
35
+
36
+ {
37
+ errors: CollectionDrop.new(flash[:errors]),
38
+ meta: MetaDrop.new(locals.delete(:meta)),
39
+ categories: CategoriesDrop.new,
40
+ cart: CartDrop.new(current_cart),
41
+ carts: CollectionDrop.new(current_carts.map{|cart| CartDrop.new(cart)}),
42
+ menus: MenusDrop.new,
43
+ pages: PagesDrop.new,
44
+ blog_posts: CollectionDrop.new(BlogPost.active),
45
+ blog_categories: CollectionDrop.new(BlogCategory.active),
46
+ countries: CollectionDrop.new(Country.all),
47
+ vendors: VendorsDrop.new,
48
+ brands: VendorsDrop.new,
49
+ media_files: CollectionDrop.new(MediaFile.includes(:file)),
50
+ search: SearchDrop.new(params[:query], params[:options]),
51
+ shop: ShopDrop.new(locals[:shop]),
52
+ current_page: (params[:page].to_i rescue 1),
53
+ path: request.path,
54
+ params: params,
55
+ flash: flash.to_hash.stringify_keys,
56
+ get_params: request.query_parameters,
57
+ template_name: locals[:template].to_s,
58
+ url: Url::GetDrop.new,
59
+ form_actions: Url::PostDrop.new,
60
+ paths: Url::PostDrop.new, # alias
61
+ geoip: RequestStore["country_code"],
62
+ collections: ProductCollectionsDrop.new,
63
+ products: ProductsDrop.new,
64
+ account: CustomerDrop.new(current_customer),
65
+ settings: ThemeSettingsDrop.new(current_settings),
66
+ preview: params[:theme_id].present?,
67
+ edit_preview: params[:iframe_uuid].present?,
68
+ integrations: IntegrationsDrop.new(locals[:shop].grouped_integrations),
69
+ preconnects: defined?(ResourceHints) ? ResourceHints.preconnects : [],
70
+ product_types: ProductTypesDrop.new,
71
+ plans: CollectionDrop.new(CustomerSubscriptionPlan.active),
72
+ }
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShoperbLiquid
4
+ # Example {% cache product, arg1, arg2 %}
5
+ class CacheTag < ::Liquid::Block
6
+ def initialize(tag_name, markup, tokens)
7
+ super
8
+ @attrs = markup.split(/[, ]/).select(&:present?).map(&:strip)
9
+ end
10
+
11
+ def render(context)
12
+ context.stack do
13
+ key_lookup = [
14
+ "liquid.cached",
15
+ cache_key(context.registers[:theme]),
16
+ @markup,
17
+ ::I18n.locale.to_s,
18
+ ]
19
+
20
+ @attrs.each do |attr|
21
+ key = cache_key(context[attr])
22
+ key_lookup << (key || attr)
23
+ end
24
+
25
+ ShoperbLiquid.config.cache.fetch(key_lookup) do
26
+ super(context)
27
+ end
28
+ end
29
+ end
30
+
31
+ # using activerecord cache key when possible
32
+ def cache_key(object)
33
+ instance = nil
34
+ instance = object if object.respond_to?(:updated_at)
35
+ instance = object.record if object.respond_to?(:record)
36
+ instance = object.collection if object.respond_to?(:collection)
37
+
38
+ if instance && instance.respond_to?(:cache_key)
39
+ instance.cache_key
40
+ else
41
+ object
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShoperbLiquid
4
+ # Generates feedback form
5
+ #
6
+ # Usage:
7
+ #
8
+ # {% form 'name' %}
9
+ # html
10
+ # {% endform %}
11
+ # <input name="subject"> - will be used for subject. Other ones will be used for body
12
+ #
13
+ class FormTag < ::Liquid::Block
14
+ SYNTAX = /(#{::Liquid::QuotedFragment})/
15
+
16
+ def initialize(tag_name, markup, tokens)
17
+ super
18
+
19
+ if markup =~ SYNTAX
20
+ @subject = $1.strip[1..-2]
21
+ else
22
+ raise ShoperbLiquid::SyntaxError, "Error in tag 'layout' - Valid syntax: form 'form_name'"
23
+ end
24
+ end
25
+
26
+ def render(context)
27
+ context.stack do
28
+ nodelist = []
29
+ nodelist << %(<form action='/submit-form' method="post">)
30
+ nodelist << %(<input type="text" name="contact_form_name" value="#{@subject}" style="color: black; display: none;" />)
31
+ nodelist << auth_token(context)
32
+ nodelist << super(context)
33
+ nodelist << %(</form>)
34
+
35
+ nodelist.join
36
+ end
37
+ end
38
+
39
+ # returns input with protection token and honeypot protection
40
+ def auth_token(context)
41
+ controller = context.registers[:controller]
42
+ value = controller.send(:form_authenticity_token)
43
+
44
+ %(<input type="hidden" name="authenticity_token" value="#{value}"> <input autocomplete="nope" type="search" tabindex="-1" name="shoperb_first_last_name_1" value="" style="color: black; display: none;" />)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShoperbLiquid
4
+ class LayoutTag < ::Liquid::Tag
5
+ SYNTAX = /(#{::Liquid::QuotedFragment}+)(\s+(#{::Liquid::QuotedFragment}+))?/
6
+
7
+ def initialize(tag_name, markup, tokens)
8
+ super
9
+
10
+ if markup =~ SYNTAX
11
+ @layout_name = $1
12
+ else
13
+ raise ShoperbLiquid::SyntaxError, "Error in tag 'layout' - Valid syntax: layout '[layout|none]'"
14
+ end
15
+ end
16
+
17
+ def render(context)
18
+ context.registers[:layouts] = @layout_name == "none" ? nil : @layout_name
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShoperbLiquid
4
+ # StrictQuotedFragment = /"[^"]+"|'[^']+'|[^\s|:,]+/
5
+ # FirstFilterArgument = /#{FilterArgumentSeparator}(?:#{StrictQuotedFragment})/o
6
+ # OtherFilterArgument = /#{ArgumentSeparator}(?:#{StrictQuotedFragment})/o
7
+ # SpacelessFilter = /^(?:'[^']+'|"[^"]+"|[^'"])*#{FilterSeparator}(?:#{StrictQuotedFragment})(?:#{FirstFilterArgument}(?:#{OtherFilterArgument})*)?/o
8
+ # Expression = /(?:#{QuotedFragment}(?:#{SpacelessFilter})*)/o
9
+ # Paginate a collection
10
+ #
11
+ # Usage:
12
+ #
13
+ # {% paginate contents.projects by 5 %}
14
+ # {% for project in paginate.collection %}
15
+ # {{ project.name }}
16
+ # {% endfor %}
17
+ # {% endpaginate %}
18
+ #
19
+ class PaginateTag < ::Liquid::Block
20
+ Syntax = /(#{::Liquid::QuotedFragment})\s*(by\s*(\w+))?/
21
+ DEFAULT_PER = 20
22
+ MAXIMUM_PER = 100
23
+
24
+ def initialize(tag_name, markup, tokens)
25
+ super
26
+
27
+ if markup =~ Syntax
28
+ @collection_name = $1
29
+ @page_size = $2 ? $3 : DEFAULT_PER # save number hardcoded or variable name
30
+
31
+ @attributes = { "window_size" => 3 }
32
+
33
+ markup.scan(Liquid::TagAttributes) do |key, value|
34
+ @attributes[key] = value
35
+ end
36
+ else
37
+ raise ShoperbLiquid::SyntaxError, "Syntax Error in 'paginate' - Valid syntax: paginate <collection> by <number>"
38
+ end
39
+
40
+ super
41
+ end
42
+
43
+ def get_page_number(per)
44
+ return @get_page_number if @get_page_number
45
+
46
+ @get_page_number = per.to_i
47
+ @get_page_number = (@context.scopes.last[per] || DEFAULT_PER).to_i if @get_page_number == 0
48
+ @get_page_number = MAXIMUM_PER if @get_page_number > MAXIMUM_PER
49
+
50
+ @get_page_number
51
+ end
52
+
53
+ # @page_size - is number or reference
54
+ def render(context)
55
+ @context = context
56
+
57
+ context.stack do
58
+ collection = context[@collection_name]
59
+ collection ||= CollectionDrop.new(Product.none)
60
+
61
+ current = context["current_page"].to_i == 0 ? 1 : context["current_page"].to_i
62
+ pagy,scope = collection.send(:paginate, current, get_page_number(@page_size))
63
+
64
+ paginator = {
65
+ total: pagy.count,
66
+ last: pagy.count - 1,
67
+ pages: pagy.pages,
68
+ size: pagy.limit,
69
+ offset: pagy.offset,
70
+ first: 1,
71
+ page: current,
72
+ previous: nil,
73
+ next: nil,
74
+ parts: [],
75
+ collection: scope,
76
+ }
77
+
78
+ path = context["path"]
79
+ other_params = context["get_params"]
80
+
81
+ has_prev_page = (paginator[:page] - 1) >= 1
82
+ has_next_page = (paginator[:page] + 1) <= pagy.pages
83
+
84
+ previous_text = ShoperbLiquid.config.translator.translate("navigation.previous", locale: context.registers[:locale])
85
+ next_text = ShoperbLiquid.config.translator.translate("navigation.next", locale: context.registers[:locale])
86
+
87
+ paginator[:previous] = link(previous_text, paginator[:page] - 1, path, other_params) if has_prev_page
88
+ paginator[:next] = link(next_text, paginator[:page] + 1, path, other_params) if has_next_page
89
+
90
+ hellip_break = false
91
+
92
+ if paginator[:pages] > 1
93
+ 1.upto(paginator[:pages]) do |page|
94
+ if paginator[:page] == page
95
+ paginator[:parts] << no_link(page)
96
+ elsif page == 1
97
+ paginator[:parts] << link(page, page, path, other_params)
98
+ elsif page == paginator[:pages]
99
+ paginator[:parts] << link(page, page, path, other_params)
100
+ elsif page <= paginator[:page] - window_size || page >= paginator[:page] + window_size
101
+ next if hellip_break
102
+ paginator[:parts] << no_link("&hellip;")
103
+ hellip_break = true
104
+ next
105
+ else
106
+ paginator[:parts] << link(page, page, path, other_params)
107
+ end
108
+
109
+ hellip_break = false
110
+ end
111
+ end
112
+
113
+ context["paginate"] = paginator.stringify_keys!
114
+
115
+ super
116
+ end
117
+ end
118
+
119
+ private
120
+
121
+ def window_size
122
+ @attributes["window_size"]
123
+ end
124
+
125
+ def no_link(title)
126
+ { "title" => title, "is_link" => false, "current" => title != "&hellip;" }
127
+ end
128
+
129
+ def link(title, page, path, other_params={})
130
+ params = other_params.merge("page" => page)
131
+ { "title" => title, "url" => path + "?#{params.to_query}", "is_link" => true }
132
+ end
133
+ end
134
+ end