/
view_extensions.rb
132 lines (115 loc) · 3.26 KB
/
view_extensions.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# frozen_string_literal: true
require_relative 'breadcrumb'
require_relative 'crumb'
require_relative 'options_validator'
require_relative 'translation'
module Loaf
# A mixin to define view extensions
module ViewExtensions
include Loaf::OptionsValidator
def initialize(*)
@_breadcrumbs ||= []
super
end
# Checks to see if any breadcrumbs have been added
#
# @return [Boolean]
#
# @api public
def breadcrumbs?
_breadcrumbs.present?
end
# Adds breadcrumbs inside view.
#
# @param [String] name
# the breadcrumb name
# @param [Object] url
# the breadcrumb url
# @param [Hash] options
# the breadcrumb options
#
# @api public
def breadcrumb(name, url, options = {})
_breadcrumbs << Loaf::Crumb.new(name, url, options)
end
alias add_breadcrumb breadcrumb
# Renders breadcrumbs inside view.
#
# @param [Hash] options
#
# @api public
def breadcrumb_trail(options = {})
return enum_for(:breadcrumb_trail) unless block_given?
valid?(options)
options = Loaf.configuration.to_hash.merge(options)
_breadcrumbs.each do |crumb|
name = title_for(crumb.name)
path = url_for(_expand_url(crumb.url))
current = current_crumb?(path, crumb.match)
yield(Loaf::Breadcrumb[name, path, current])
end
end
# Check if breadcrumb is current based on the pattern
#
# @param [String] path
# @param [Object] pattern
# the pattern to match on
#
# @api public
def current_crumb?(path, pattern = :inclusive)
return false unless request.get? || request.head?
origin_path = URI.parser.unescape(path).force_encoding(Encoding::BINARY)
request_uri = request.fullpath
request_uri = URI.parser.unescape(request_uri)
request_uri.force_encoding(Encoding::BINARY)
# strip away trailing slash
if origin_path.start_with?('/') && origin_path != '/'
origin_path.chomp!('/')
request_uri.chomp!('/')
end
if %r{^\w+://} =~ origin_path
origin_path.chomp!('/')
request_uri.insert(0, "#{request.protocol}#{request.host_with_port}")
end
case pattern
when :inclusive
!request_uri.match(/^#{Regexp.escape(origin_path)}(\/.*|\?.*)?$/).nil?
when :exclusive
!request_uri.match(/^#{Regexp.escape(origin_path)}\/?(\?.*)?$/).nil?
when :exact
request_uri == origin_path
when :force
true
when Regexp
!request_uri.match(pattern).nil?
when Hash
query_params = URI.encode_www_form(pattern)
!request_uri.match(/^#{Regexp.escape(origin_path)}\/?(\?.*)?.*?#{query_params}.*$/).nil?
else
raise ArgumentError, "Unknown `:#{pattern}` match option!"
end
end
private
# Find title translation for a crumb name
#
# @return [String]
#
# @api private
def title_for(name)
Translation.find_title(name)
end
# Expand url in the current context of the view
#
# @api private
def _expand_url(url)
case url
when String, Symbol
respond_to?(url) ? send(url) : url
when Proc
url.call(self)
else
url
end
end
end # ViewExtensions
end # Loaf