tabnav 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/LICENSE +24 -0
- data/README.rdoc +136 -0
- data/Rakefile +46 -0
- data/VERSION +1 -0
- data/lib/tabnav/helper.rb +17 -0
- data/lib/tabnav/navbar.rb +36 -0
- data/lib/tabnav/tab.rb +69 -0
- data/lib/tabnav.rb +8 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/tabnav/helper_spec.rb +38 -0
- data/spec/tabnav/integration_spec.rb +184 -0
- data/spec/tabnav/navbar_spec.rb +119 -0
- data/spec/tabnav/tab_spec.rb +166 -0
- metadata +133 -0
data/.document
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
LICENSE
|
2
|
+
|
3
|
+
The MIT License
|
4
|
+
|
5
|
+
Copyright (c) 2010 Alex Tomlins and Unboxed Consulting
|
6
|
+
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
8
|
+
a copy of this software and associated documentation files (the
|
9
|
+
"Software"), to deal in the Software without restriction, including
|
10
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
11
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
12
|
+
permit persons to whom the Software is furnished to do so, subject to
|
13
|
+
the following conditions:
|
14
|
+
|
15
|
+
The above copyright notice and this permission notice shall be
|
16
|
+
included in all copies or substantial portions of the Software.
|
17
|
+
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
20
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
22
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
23
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
24
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
= Tabnav
|
2
|
+
|
3
|
+
Tabnav is a helper for generating navigation bars. It allows you to simply specify highlighting rules for each tab.
|
4
|
+
|
5
|
+
* Homepage: http://github.com/unboxed/tabnav
|
6
|
+
* Issues: http://github.com/unboxed/tabnav/issues
|
7
|
+
|
8
|
+
== Some Examples
|
9
|
+
|
10
|
+
=== Simple Example
|
11
|
+
|
12
|
+
In your view:
|
13
|
+
|
14
|
+
<%
|
15
|
+
render_tabnav do |n|
|
16
|
+
n.add_tab do |t|
|
17
|
+
t.named "Home"
|
18
|
+
t.links_to root_path
|
19
|
+
t.highlights_on :controller => :home, :action => :index
|
20
|
+
end
|
21
|
+
n.add_tab do |t|
|
22
|
+
t.named "Froobles"
|
23
|
+
t.links_to froobles_path
|
24
|
+
t.highlights_on :controller => :froobles
|
25
|
+
end
|
26
|
+
end
|
27
|
+
%>
|
28
|
+
|
29
|
+
On home/index will output:
|
30
|
+
|
31
|
+
<ul>
|
32
|
+
<li class="active"><a href="/">Home</a></li>
|
33
|
+
<li><a href="/froobles">Froobles</a></li>
|
34
|
+
</ul>
|
35
|
+
|
36
|
+
On any action in FrooblesController will output:
|
37
|
+
|
38
|
+
<ul>
|
39
|
+
<li><a href="/">Home</a></li>
|
40
|
+
<li class="active"><a href="/froobles">Froobles</a></li>
|
41
|
+
</ul>
|
42
|
+
|
43
|
+
See the highlights_on method of Tabnav::Tab for full details of the highlighting logic.
|
44
|
+
|
45
|
+
=== Options for controlling markup
|
46
|
+
|
47
|
+
View:
|
48
|
+
|
49
|
+
<%
|
50
|
+
render_tabnav :id => "main_navigation", :class => "clearfix" do |n|
|
51
|
+
n.add_tab :class => "home_tab" do |t|
|
52
|
+
t.named "Home"
|
53
|
+
t.links_to root_path
|
54
|
+
t.highlights_on :controller => :home, :action => :index
|
55
|
+
end
|
56
|
+
n.add_tab :class => "heading" do |t|
|
57
|
+
t.named "Froobles Heading"
|
58
|
+
t.highlights_on :controller => :froobles
|
59
|
+
end
|
60
|
+
n.add_tab do |t|
|
61
|
+
t.named "Froobles"
|
62
|
+
t.links_to froobles_path, :target => "_blank", :rel => "http://foo.bar/"
|
63
|
+
t.highlights_on :controller => :froobles, :action => :index
|
64
|
+
end
|
65
|
+
end
|
66
|
+
%>
|
67
|
+
|
68
|
+
On froobles/index will output:
|
69
|
+
|
70
|
+
<ul id="main_navigation" class="clearfix">
|
71
|
+
<li class="home_tab"><a href="/">Home</a></li>
|
72
|
+
<li class="heading active"><span>Froobles Heading</span></li>
|
73
|
+
<li class="active"><a href="/froobles" target="_blank" rel="http://foo.bar/">Froobles</a></li>
|
74
|
+
</ul>
|
75
|
+
|
76
|
+
=== Custom tab partial
|
77
|
+
|
78
|
+
It is also possible to specify a partial to be used to generate the tab contents. e.g.:
|
79
|
+
|
80
|
+
View:
|
81
|
+
|
82
|
+
<%
|
83
|
+
render_tabnav :html => {:id => "main_navigation", :class => "clearfix"} do |n|
|
84
|
+
n.tab_partial "/shared/my_custom_tab"
|
85
|
+
n.add_tab :html => {:class => "home_tab"} do |t|
|
86
|
+
t.named "Home"
|
87
|
+
t.links_to root_path
|
88
|
+
t.highlights_on :controller => :home, :action => :index
|
89
|
+
end
|
90
|
+
n.add_tab :html => {:class => "heading"} do |t|
|
91
|
+
t.named "Froobles Heading"
|
92
|
+
t.highlights_on :controller => :froobles
|
93
|
+
end
|
94
|
+
n.add_tab do |t|
|
95
|
+
t.named "Froobles"
|
96
|
+
t.links_to froobles_path, :target => "_blank", :rel => "http://foo.bar/"
|
97
|
+
t.highlights_on :controller => :froobles, :action => :index
|
98
|
+
end
|
99
|
+
end
|
100
|
+
%>
|
101
|
+
|
102
|
+
In the partial, +tab+ will be the Tab instance to be rendered.
|
103
|
+
|
104
|
+
in /app/views/shared/_my_custom_tab.html.erb:
|
105
|
+
|
106
|
+
<div class="my_custom_class">
|
107
|
+
<%- if tab.has_link? -%>
|
108
|
+
<%= link_to tab.name, tab.url %>
|
109
|
+
<%- else -%>
|
110
|
+
<span><%= tab.name %></span>
|
111
|
+
<%- end -%>
|
112
|
+
</div>
|
113
|
+
|
114
|
+
On froobles/index the output will be:
|
115
|
+
|
116
|
+
<ul id="main_navigation" class="clearfix">
|
117
|
+
<li class="home_tab"><div class="my_custom_class"><a href="/">Home</a></div></li>
|
118
|
+
<li class="heading active"><div class="my_custom_class"><span>Froobles Heading</span></div></li>
|
119
|
+
<li class="active"><div class="my_custom_class"><a href="/froobles">Froobles</a></div></li>
|
120
|
+
</ul>
|
121
|
+
|
122
|
+
-----
|
123
|
+
|
124
|
+
== Note on Patches/Pull Requests
|
125
|
+
|
126
|
+
* Fork the project.
|
127
|
+
* Make your feature addition or bug fix.
|
128
|
+
* Add tests for it. This is important so I don't break it in a
|
129
|
+
future version unintentionally.
|
130
|
+
* Commit, do not mess with Rakefile, gemspec, version, or history.
|
131
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
132
|
+
* Send me a pull request. Bonus points for topic branches.
|
133
|
+
|
134
|
+
== Copyright
|
135
|
+
|
136
|
+
Copyright (c) 2010 Unboxed. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "tabnav"
|
8
|
+
gem.summary = %Q{Rails helper for generating navbars}
|
9
|
+
gem.description = %Q{Rails helper for generating navbars in a declarative manner}
|
10
|
+
gem.email = "github@unboxedconsulting.com"
|
11
|
+
gem.homepage = "http://github.com/unboxed/tabnav"
|
12
|
+
gem.authors = ["Unboxed"]
|
13
|
+
gem.add_dependency "actionpack", ">= 2.3.2"
|
14
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
15
|
+
gem.add_development_dependency "rspec-rails", ">= 1.2.9"
|
16
|
+
gem.files.exclude "*.gemspec", '.gitignore', 'doc/*'
|
17
|
+
end
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'spec/rake/spectask'
|
23
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
24
|
+
spec.libs << 'lib' << 'spec'
|
25
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
26
|
+
end
|
27
|
+
|
28
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
29
|
+
spec.libs << 'lib' << 'spec'
|
30
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
31
|
+
spec.rcov = true
|
32
|
+
end
|
33
|
+
|
34
|
+
task :spec => :check_dependencies
|
35
|
+
|
36
|
+
task :default => :spec
|
37
|
+
|
38
|
+
require 'rake/rdoctask'
|
39
|
+
Rake::RDocTask.new do |rdoc|
|
40
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
41
|
+
|
42
|
+
rdoc.rdoc_dir = 'rdoc'
|
43
|
+
rdoc.title = "tabnav #{version}"
|
44
|
+
rdoc.rdoc_files.include('README*')
|
45
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
46
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Tabnav
|
2
|
+
module Helper
|
3
|
+
|
4
|
+
# This is the main method to be used in your views.
|
5
|
+
# It creates and yields a new instance of Navbar.
|
6
|
+
#
|
7
|
+
# +options+ is an optional hash of options that are passed to the navbar, and
|
8
|
+
# and used to create the +ul+.
|
9
|
+
#
|
10
|
+
# Finally, this renders the navbar, and concats the result into the view.
|
11
|
+
def render_tabnav(options = {})
|
12
|
+
n = Navbar.new(self, params, options)
|
13
|
+
yield(n)
|
14
|
+
concat( n.render )
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Tabnav
|
2
|
+
class Navbar
|
3
|
+
def initialize(template, params, options = {}) # :nodoc:
|
4
|
+
@template = template
|
5
|
+
@params = params
|
6
|
+
@html_options = options
|
7
|
+
@tabs = []
|
8
|
+
end
|
9
|
+
|
10
|
+
# Optionally specifies a partial to be used to render the tab content.
|
11
|
+
attr_writer :tab_content_partial
|
12
|
+
|
13
|
+
# Creates a Tab and adds it to the navbar.
|
14
|
+
#
|
15
|
+
# +options+ is an optional hash of options which will be used to create the +li+ for the tab.
|
16
|
+
#
|
17
|
+
# yields the created Tab
|
18
|
+
def add_tab(options = {})
|
19
|
+
options[:tab_content_partial] = @tab_content_partial if @tab_content_partial
|
20
|
+
t = Tab.new(@template, @params, options)
|
21
|
+
yield t
|
22
|
+
@tabs << t
|
23
|
+
end
|
24
|
+
|
25
|
+
def render # :nodoc:
|
26
|
+
return '' if @tabs.empty?
|
27
|
+
@template.content_tag :ul, @html_options do
|
28
|
+
contents = ''
|
29
|
+
@tabs.each do |tab|
|
30
|
+
contents += tab.render
|
31
|
+
end
|
32
|
+
contents
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/tabnav/tab.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
module Tabnav
|
2
|
+
class Tab
|
3
|
+
|
4
|
+
def initialize(template, params, html_options = {}) # :nodoc:
|
5
|
+
@html_options = html_options
|
6
|
+
@params = params
|
7
|
+
@template = template
|
8
|
+
@name = ''
|
9
|
+
@active = false
|
10
|
+
end
|
11
|
+
|
12
|
+
# The name of this tab
|
13
|
+
attr_accessor :name
|
14
|
+
|
15
|
+
# The link destination
|
16
|
+
attr_accessor :link_url
|
17
|
+
|
18
|
+
# The link options (if any)
|
19
|
+
attr_accessor :link_options
|
20
|
+
|
21
|
+
# Sets the name of this tab. This will be used as the contents of the link or span
|
22
|
+
def named(text)
|
23
|
+
@name = text
|
24
|
+
end
|
25
|
+
|
26
|
+
# Sets the link destination.
|
27
|
+
#
|
28
|
+
# +link_options+ is an option hash of options that will be
|
29
|
+
# passed through to the link_to call.
|
30
|
+
def links_to(url, link_options = {})
|
31
|
+
@link_url = url
|
32
|
+
@link_options = link_options
|
33
|
+
end
|
34
|
+
|
35
|
+
# Adds a highlight condition to this tab. +rule+ can be one of the following:
|
36
|
+
#
|
37
|
+
# * A Hash: The tab will be highlighted if all the values in the given hash match the
|
38
|
+
# params hash (strings and symbols are treated as equivelent).
|
39
|
+
# * A Proc: The proc will be called, and the tab will be highlighted if it returns true.
|
40
|
+
#
|
41
|
+
# If multiple highlight conditions are given, the tab will be highlighted if any of them match.
|
42
|
+
def highlights_on(rule)
|
43
|
+
if rule.is_a?(Hash)
|
44
|
+
@active |= rule.with_indifferent_access.all? {|k, v| @params[k] == v.to_s}
|
45
|
+
elsif rule.is_a?(Proc)
|
46
|
+
@active |= rule.call
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns +true+ of this tab is highlighted.
|
51
|
+
def active?
|
52
|
+
@active
|
53
|
+
end
|
54
|
+
|
55
|
+
def render # :nodoc:
|
56
|
+
@html_options[:class] = "#{@html_options[:class]} active".strip if self.active?
|
57
|
+
partial = @html_options.delete(:tab_content_partial)
|
58
|
+
@template.content_tag(:li, @html_options) do
|
59
|
+
if partial
|
60
|
+
@template.render :partial => partial, :locals => {:tab => self}
|
61
|
+
elsif @link_url
|
62
|
+
@template.link_to @name, @link_url, @link_options
|
63
|
+
else
|
64
|
+
@template.content_tag :span, @name
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/tabnav.rb
ADDED
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
require 'rubygems'
|
4
|
+
require 'action_controller'
|
5
|
+
require 'tabnav'
|
6
|
+
|
7
|
+
require 'spec'
|
8
|
+
require 'spec/autorun'
|
9
|
+
|
10
|
+
# The parts of rspec-rails necessary to use helper example groups
|
11
|
+
class ApplicationController < ActionController::Base
|
12
|
+
end
|
13
|
+
require 'active_support/test_case'
|
14
|
+
require 'spec/test/unit'
|
15
|
+
require 'spec/rails/example'
|
16
|
+
require 'spec/rails/interop/testcase'
|
17
|
+
|
18
|
+
Spec::Runner.configure do |config|
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Tabnav::Helper, :type => :helper do
|
4
|
+
|
5
|
+
describe "render_tabnav" do
|
6
|
+
before :each do
|
7
|
+
# helper is an instance of a subclass of ActionView::Base
|
8
|
+
@template = helper
|
9
|
+
@navbar = Tabnav::Navbar.new(@template, {})
|
10
|
+
Tabnav::Navbar.stub!(:new).and_return(@navbar)
|
11
|
+
helper.output_buffer = ''
|
12
|
+
end
|
13
|
+
it "should create a new navbar with the template and params and yield it to the block" do
|
14
|
+
params[:foo] = "bar"
|
15
|
+
Tabnav::Navbar.should_receive(:new).with(@template, {"foo" => "bar"}, {}).and_return(@navbar)
|
16
|
+
helper.render_tabnav do |n|
|
17
|
+
n.should == @navbar
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should create a new navbar with any passed options" do
|
22
|
+
Tabnav::Navbar.should_receive(:new).with(@template, {}, {:class => "my_class", :id => "my_id"}).and_return(@navbar)
|
23
|
+
helper.render_tabnav :class => "my_class", :id => "my_id" do |n|
|
24
|
+
n.should == @navbar
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should concat the results of calling render on the navbar" do
|
29
|
+
@navbar.should_receive(:render).and_return("Some Navbar Markup")
|
30
|
+
helper.render_tabnav {|n| }
|
31
|
+
helper.output_buffer.should == "Some Navbar Markup"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should be included in ActionController::Base's helpers" do
|
36
|
+
ActionController::Base.helpers.should be_a(Tabnav::Helper)
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Tabnav::Helper, :type => :helper do
|
4
|
+
before :each do
|
5
|
+
helper.output_buffer = ''
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "basic flat navbar" do
|
9
|
+
it "should output a basic 2 tab navbar" do
|
10
|
+
helper.render_tabnav do |n|
|
11
|
+
n.add_tab do |t|
|
12
|
+
t.named "Home"
|
13
|
+
t.links_to "/"
|
14
|
+
end
|
15
|
+
n.add_tab do |t|
|
16
|
+
t.named "Froobles"
|
17
|
+
t.links_to "/froobles"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
helper.output_buffer.should == '<ul><li><a href="/">Home</a></li><li><a href="/froobles">Froobles</a></li></ul>'
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should output a basic 2 tab navbar with extra markup options" do
|
24
|
+
helper.render_tabnav :id => "main_navigation", :class => "clearfix" do |n|
|
25
|
+
n.add_tab :class => "home_tab" do |t|
|
26
|
+
t.named "Home"
|
27
|
+
t.links_to "/"
|
28
|
+
end
|
29
|
+
n.add_tab :class => "heading" do |t|
|
30
|
+
t.named "Froobles Heading"
|
31
|
+
end
|
32
|
+
n.add_tab do |t|
|
33
|
+
t.named "Froobles"
|
34
|
+
t.links_to "/froobles", :target => "_blank", :rel => "http://foo.bar/"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
helper.output_buffer.should == '<ul class="clearfix" id="main_navigation"><li class="home_tab"><a href="/">Home</a></li>' +
|
38
|
+
'<li class="heading"><span>Froobles Heading</span></li>' +
|
39
|
+
'<li><a href="/froobles" rel="http://foo.bar/" target="_blank">Froobles</a></li></ul>'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "highlighting logic" do
|
44
|
+
context "params based rules" do
|
45
|
+
it "should highlight the tab if the rules match the params hash" do
|
46
|
+
params[:controller] = 'home'
|
47
|
+
params[:action] = 'index'
|
48
|
+
params[:foo] = 'bar'
|
49
|
+
helper.render_tabnav :id => "main_navigation", :class => "clearfix" do |n|
|
50
|
+
n.add_tab :class => "home_tab" do |t|
|
51
|
+
t.named "Home"
|
52
|
+
t.links_to '/'
|
53
|
+
t.highlights_on :controller => :home, :action => :index
|
54
|
+
end
|
55
|
+
n.add_tab :class => "heading" do |t|
|
56
|
+
t.named "Froobles Heading"
|
57
|
+
t.highlights_on :controller => :froobles
|
58
|
+
end
|
59
|
+
n.add_tab do |t|
|
60
|
+
t.named "Froobles"
|
61
|
+
t.links_to '/froobles', :target => "_blank", :rel => "http://foo.bar/"
|
62
|
+
t.highlights_on :controller => :froobles, :action => :index
|
63
|
+
end
|
64
|
+
end
|
65
|
+
helper.output_buffer.should == '<ul class="clearfix" id="main_navigation"><li class="home_tab active"><a href="/">Home</a></li>' +
|
66
|
+
'<li class="heading"><span>Froobles Heading</span></li>' +
|
67
|
+
'<li><a href="/froobles" rel="http://foo.bar/" target="_blank">Froobles</a></li></ul>'
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should allow multiple tabs to be active at once" do
|
71
|
+
params[:controller] = 'froobles'
|
72
|
+
params[:action] = 'index'
|
73
|
+
params[:foo] = 'bar'
|
74
|
+
helper.render_tabnav do |n|
|
75
|
+
n.add_tab :class => "home_tab" do |t|
|
76
|
+
t.named "Home"
|
77
|
+
t.links_to '/'
|
78
|
+
t.highlights_on :controller => :home, :action => :index
|
79
|
+
end
|
80
|
+
n.add_tab :class => "heading" do |t|
|
81
|
+
t.named "Froobles Heading"
|
82
|
+
t.highlights_on :controller => :froobles
|
83
|
+
end
|
84
|
+
n.add_tab do |t|
|
85
|
+
t.named "Froobles"
|
86
|
+
t.links_to '/froobles', :target => "_blank", :rel => "http://foo.bar/"
|
87
|
+
t.highlights_on :controller => :froobles, :action => :index
|
88
|
+
end
|
89
|
+
end
|
90
|
+
helper.output_buffer.should == '<ul><li class="home_tab"><a href="/">Home</a></li>' +
|
91
|
+
'<li class="heading active"><span>Froobles Heading</span></li>' +
|
92
|
+
'<li class="active"><a href="/froobles" rel="http://foo.bar/" target="_blank">Froobles</a></li></ul>'
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should highlight tabs where any of the highlighting rules match" do
|
96
|
+
params[:controller] = 'home'
|
97
|
+
params[:action] = 'froobles'
|
98
|
+
params[:foo] = 'bar'
|
99
|
+
helper.render_tabnav do |n|
|
100
|
+
n.add_tab do |t|
|
101
|
+
t.named "Home"
|
102
|
+
t.links_to "/"
|
103
|
+
t.highlights_on :controller => :home, :action => :index
|
104
|
+
end
|
105
|
+
n.add_tab do |t|
|
106
|
+
t.named "Froobles"
|
107
|
+
t.links_to "/froobles"
|
108
|
+
t.highlights_on :controller => :home, :action => :froobles
|
109
|
+
t.highlights_on :controller => :froobles
|
110
|
+
end
|
111
|
+
end
|
112
|
+
helper.output_buffer.should == '<ul><li><a href="/">Home</a></li><li class="active"><a href="/froobles">Froobles</a></li></ul>'
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context "proc based rules" do
|
117
|
+
it "should highlight the tab if the give proc evaluates to true" do
|
118
|
+
helper.render_tabnav do |n|
|
119
|
+
n.add_tab do |t|
|
120
|
+
t.named "Home"
|
121
|
+
t.links_to "/"
|
122
|
+
t.highlights_on Proc.new { true }
|
123
|
+
end
|
124
|
+
n.add_tab do |t|
|
125
|
+
t.named "Froobles"
|
126
|
+
t.links_to "/froobles"
|
127
|
+
t.highlights_on Proc.new { false }
|
128
|
+
end
|
129
|
+
end
|
130
|
+
helper.output_buffer.should == '<ul><li class="active"><a href="/">Home</a></li><li><a href="/froobles">Froobles</a></li></ul>'
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should allow a mixture of rule types" do
|
135
|
+
params[:controller] = 'home'
|
136
|
+
params[:action] = 'index'
|
137
|
+
params[:foo] = 'bar'
|
138
|
+
helper.render_tabnav do |n|
|
139
|
+
n.add_tab :class => "home_tab" do |t|
|
140
|
+
t.named "Home"
|
141
|
+
t.links_to '/'
|
142
|
+
t.highlights_on :controller => :home, :action => :index
|
143
|
+
end
|
144
|
+
n.add_tab :class => "heading" do |t|
|
145
|
+
t.named "Froobles Heading"
|
146
|
+
t.highlights_on :controller => :froobles
|
147
|
+
t.highlights_on Proc.new { true }
|
148
|
+
end
|
149
|
+
n.add_tab do |t|
|
150
|
+
t.named "Froobles"
|
151
|
+
t.links_to '/froobles', :target => "_blank", :rel => "http://foo.bar/"
|
152
|
+
t.highlights_on :controller => :froobles, :action => :index
|
153
|
+
end
|
154
|
+
end
|
155
|
+
helper.output_buffer.should == '<ul><li class="home_tab active"><a href="/">Home</a></li>' +
|
156
|
+
'<li class="heading active"><span>Froobles Heading</span></li>' +
|
157
|
+
'<li><a href="/froobles" rel="http://foo.bar/" target="_blank">Froobles</a></li></ul>'
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe "custom tab partials" do
|
162
|
+
it "should allow sppecifying a custom partial for rendering the tabs" do
|
163
|
+
helper.should_receive(:render).twice do |args|
|
164
|
+
args[:partial].should == '/tab_content'
|
165
|
+
args[:locals][:tab].should be_a(Tabnav::Tab)
|
166
|
+
"Custom markup for #{args[:locals][:tab].name}"
|
167
|
+
end
|
168
|
+
helper.render_tabnav do |n|
|
169
|
+
n.tab_content_partial = '/tab_content'
|
170
|
+
n.add_tab do |t|
|
171
|
+
t.named "Home"
|
172
|
+
t.links_to "/"
|
173
|
+
end
|
174
|
+
n.add_tab do |t|
|
175
|
+
t.named "Froobles"
|
176
|
+
t.links_to "/froobles"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
helper.output_buffer.should ==
|
180
|
+
'<ul><li>Custom markup for Home</li>' +
|
181
|
+
'<li>Custom markup for Froobles</li></ul>'
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Tabnav::Navbar do
|
4
|
+
|
5
|
+
describe "add_tab" do
|
6
|
+
before :each do
|
7
|
+
@template = ActionView::Base.new()
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should create a new tab with the passed template and params and yield it to the block" do
|
11
|
+
n = Tabnav::Navbar.new(@template, {"foo" => "bar"})
|
12
|
+
t = Tabnav::Tab.new(@template, {})
|
13
|
+
Tabnav::Tab.should_receive(:new).with(@template, {"foo" => "bar"}, {}).and_return(t)
|
14
|
+
n.add_tab do |t|
|
15
|
+
t.should == t
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should create the tab with any passed options" do
|
20
|
+
n = Tabnav::Navbar.new(@template, {})
|
21
|
+
t = Tabnav::Tab.new(@template, {})
|
22
|
+
Tabnav::Tab.should_receive(:new).with(@template, {}, {:class => "my_class", :id => "my_id"}).and_return(t)
|
23
|
+
n.add_tab :class => "my_class", :id => "my_id" do |t|
|
24
|
+
t.should == t
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should add the custom partial to the options if set" do
|
29
|
+
n = Tabnav::Navbar.new(@template, {})
|
30
|
+
n.tab_content_partial = 'my_partial'
|
31
|
+
t = Tabnav::Tab.new(@template, {})
|
32
|
+
Tabnav::Tab.should_receive(:new).with(@template, {}, {:id => "my_id", :tab_content_partial => 'my_partial'}).and_return(t)
|
33
|
+
n.add_tab :id => "my_id" do |t|
|
34
|
+
t.should == t
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "render" do
|
40
|
+
before :each do
|
41
|
+
@template = ActionView::Base.new()
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should output nothing if no tabs have been added" do
|
45
|
+
n = Tabnav::Navbar.new(@template, {})
|
46
|
+
n.render.should == ''
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should output a ul containing the results of rendering each of it's tabs" do
|
50
|
+
n = Tabnav::Navbar.new(@template, {})
|
51
|
+
t1 = t2 = nil
|
52
|
+
n.add_tab do |t|
|
53
|
+
t1 = t
|
54
|
+
end
|
55
|
+
n.add_tab do |t|
|
56
|
+
t2 = t
|
57
|
+
end
|
58
|
+
t1.should_receive(:render).and_return("Tab 1 markup")
|
59
|
+
t2.should_receive(:render).and_return("Tab 2 markup")
|
60
|
+
n.render.should == '<ul>Tab 1 markupTab 2 markup</ul>'
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should pass the options given on creation to the ul" do
|
64
|
+
n = Tabnav::Navbar.new(@template, {}, :id => "my_id", :class => "my_class")
|
65
|
+
t1 = nil
|
66
|
+
n.add_tab do |t|
|
67
|
+
t1 = t
|
68
|
+
end
|
69
|
+
@template.should_receive(:content_tag).with(:ul, {:id => "my_id", :class => "my_class"}).and_return(:some_markup)
|
70
|
+
n.render.should == :some_markup
|
71
|
+
end
|
72
|
+
|
73
|
+
# it "should output a li containing a span with the name if no link given" do
|
74
|
+
# t = Tabnav::Tab.new(@template)
|
75
|
+
# t.named "A Tab"
|
76
|
+
# html = t.render
|
77
|
+
# html.should == "<li><span>A Tab</span></li>"
|
78
|
+
# end
|
79
|
+
#
|
80
|
+
# it "should output a li containing a link with the name" do
|
81
|
+
# t = Tabnav::Tab.new(@template)
|
82
|
+
# t.named "A Tab"
|
83
|
+
# t.links_to "/wibble"
|
84
|
+
# html = t.render
|
85
|
+
# html.should == "<li><a href=\"/wibble\">A Tab</a></li>"
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
# context "with no name given" do
|
89
|
+
# it "should output a blank tab if no link given" do
|
90
|
+
# t = Tabnav::Tab.new(@template)
|
91
|
+
# html = t.render
|
92
|
+
# html.should == "<li><span></span></li>"
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
# it "should output an empty link" do
|
96
|
+
# t = Tabnav::Tab.new(@template)
|
97
|
+
# t.links_to "/wibble"
|
98
|
+
# html = t.render
|
99
|
+
# html.should == "<li><a href=\"/wibble\"></a></li>"
|
100
|
+
# end
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
# it "should pass the options given on creation to the li" do
|
104
|
+
# @template.should_receive(:content_tag).with(:li, {:id => "my_id", :class => "my_class"}).and_return(:some_markup)
|
105
|
+
# t = Tabnav::Tab.new(@template, :id => "my_id", :class => "my_class")
|
106
|
+
# t.named "A Tab"
|
107
|
+
# t.render.should == :some_markup
|
108
|
+
# end
|
109
|
+
#
|
110
|
+
# it "should pass the options given to the link to link_to" do
|
111
|
+
# @template.should_receive(:link_to).with("A Tab", "/wibble", {:class => "link_class", :target => "_blank"}).and_return("A Link")
|
112
|
+
# t = Tabnav::Tab.new(@template)
|
113
|
+
# t.named "A Tab"
|
114
|
+
# t.links_to "/wibble", :class => "link_class", :target => "_blank"
|
115
|
+
# html = t.render
|
116
|
+
# html.should == "<li>A Link</li>"
|
117
|
+
# end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Tabnav::Tab do
|
4
|
+
|
5
|
+
describe "accessors" do
|
6
|
+
before :each do
|
7
|
+
@tab = Tabnav::Tab.new(nil, {})
|
8
|
+
@tab.named "A Tab"
|
9
|
+
@tab.links_to "/somewhere", :target => "_blank"
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should have a name accessor" do
|
13
|
+
@tab.name.should == "A Tab"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should have a link_url accessor" do
|
17
|
+
@tab.link_url.should == "/somewhere"
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should have a link_options accessor" do
|
21
|
+
@tab.link_options.should == {:target => "_blank"}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "render" do
|
26
|
+
before :each do
|
27
|
+
@template = ActionView::Base.new()
|
28
|
+
end
|
29
|
+
it "should output a li containing a span with the name if no link given" do
|
30
|
+
t = Tabnav::Tab.new(@template, {})
|
31
|
+
t.named "A Tab"
|
32
|
+
html = t.render
|
33
|
+
html.should == "<li><span>A Tab</span></li>"
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should output a li containing a link with the name" do
|
37
|
+
t = Tabnav::Tab.new(@template, {})
|
38
|
+
t.named "A Tab"
|
39
|
+
t.links_to "/wibble"
|
40
|
+
html = t.render
|
41
|
+
html.should == "<li><a href=\"/wibble\">A Tab</a></li>"
|
42
|
+
end
|
43
|
+
|
44
|
+
context "with no name given" do
|
45
|
+
it "should output a blank tab if no link given" do
|
46
|
+
t = Tabnav::Tab.new(@template, {})
|
47
|
+
html = t.render
|
48
|
+
html.should == "<li><span></span></li>"
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should output an empty link" do
|
52
|
+
t = Tabnav::Tab.new(@template, {})
|
53
|
+
t.links_to "/wibble"
|
54
|
+
html = t.render
|
55
|
+
html.should == "<li><a href=\"/wibble\"></a></li>"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should pass the options given on creation to the li" do
|
60
|
+
@template.should_receive(:content_tag).with(:li, {:id => "my_id", :class => "my_class"}).and_return(:some_markup)
|
61
|
+
t = Tabnav::Tab.new(@template, {}, :id => "my_id", :class => "my_class")
|
62
|
+
t.named "A Tab"
|
63
|
+
t.render.should == :some_markup
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should pass the options given to the link to link_to" do
|
67
|
+
@template.should_receive(:link_to).with("A Tab", "/wibble", {:class => "link_class", :target => "_blank"}).and_return("A Link")
|
68
|
+
t = Tabnav::Tab.new(@template, {})
|
69
|
+
t.named "A Tab"
|
70
|
+
t.links_to "/wibble", :class => "link_class", :target => "_blank"
|
71
|
+
html = t.render
|
72
|
+
html.should == "<li>A Link</li>"
|
73
|
+
end
|
74
|
+
|
75
|
+
context "with a custom partial" do
|
76
|
+
it "should render the partial, assigning the tab" do
|
77
|
+
t = Tabnav::Tab.new(@template, {}, :tab_content_partial => 'my_partial')
|
78
|
+
t.named "A Tab"
|
79
|
+
@template.should_receive(:render).with(:partial => 'my_partial', :locals => {:tab => t}).and_return("Custom tab markup")
|
80
|
+
t.render.should == "<li>Custom tab markup</li>"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "highlighting rules" do
|
86
|
+
describe "active logic" do
|
87
|
+
describe "params based rules" do
|
88
|
+
it "should be active if all the optons in the rule match the params" do
|
89
|
+
params = {"key1" => "a_value", "key2" => "another_value", "key3" => "something else"}
|
90
|
+
t = Tabnav::Tab.new(@template, params)
|
91
|
+
t.highlights_on "key1" => "a_value", "key2" => "another_value"
|
92
|
+
t.should be_active
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should not be active if only some of the values match" do
|
96
|
+
params = {"key1" => "a_value", "key2" => "another_value", "key3" => "something else"}
|
97
|
+
t = Tabnav::Tab.new(@template, params)
|
98
|
+
t.highlights_on "key1" => "a_value", "key2" => "a different value"
|
99
|
+
t.should_not be_active
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should not be active if some of the values are missing" do
|
103
|
+
params = {"key1" => "a_value", "key3" => "something else"}
|
104
|
+
t = Tabnav::Tab.new(@template, params)
|
105
|
+
t.highlights_on "key1" => "a_value", "key2" => "another_value"
|
106
|
+
t.should_not be_active
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should be active if any of the rules match" do
|
110
|
+
params = {"key1" => "a_value", "key2" => "another_value", "key3" => "something else"}
|
111
|
+
t = Tabnav::Tab.new(@template, params)
|
112
|
+
t.highlights_on "key1" => "a_value", "key2" => "a different value"
|
113
|
+
t.highlights_on "key1" => "a_value"
|
114
|
+
t.highlights_on "key2" => "wibble"
|
115
|
+
t.should be_active
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should treat strings ans symobls at matching" do
|
119
|
+
params = {"key1" => "a_value", "key2" => "another_value", "key3" => "something else"}
|
120
|
+
t = Tabnav::Tab.new(@template, params)
|
121
|
+
t.highlights_on :key1 => "a_value", :key2 => :another_value
|
122
|
+
t.should be_active
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "proc based rules" do
|
127
|
+
it "should be active if the proc returns true" do
|
128
|
+
t = Tabnav::Tab.new(@template, {})
|
129
|
+
t.highlights_on Proc.new { true }
|
130
|
+
t.should be_active
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should not be active if the proc returns false" do
|
134
|
+
t = Tabnav::Tab.new(@template, {})
|
135
|
+
t.highlights_on Proc.new { false }
|
136
|
+
t.should_not be_active
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should co-erce the result of the proc to a boolean" do
|
140
|
+
t = Tabnav::Tab.new(@template, {})
|
141
|
+
t.highlights_on Proc.new { "wibble" }
|
142
|
+
t.active?.should == true
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe "output" do
|
148
|
+
before :each do
|
149
|
+
@template = ActionView::Base.new()
|
150
|
+
end
|
151
|
+
it "should set the class of the li to active if the tab is highlighted" do
|
152
|
+
t = Tabnav::Tab.new(@template, {})
|
153
|
+
t.named "A Tab"
|
154
|
+
t.stub!(:active?).and_return(true)
|
155
|
+
t.render.should == '<li class="active"><span>A Tab</span></li>'
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should merge active with the other classes if highlighted" do
|
159
|
+
t = Tabnav::Tab.new(@template, {}, {:class => "my_class"})
|
160
|
+
t.named "A Tab"
|
161
|
+
t.stub!(:active?).and_return(true)
|
162
|
+
t.render.should == '<li class="my_class active"><span>A Tab</span></li>'
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tabnav
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Unboxed
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-07-28 00:00:00 +01:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: actionpack
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 7
|
30
|
+
segments:
|
31
|
+
- 2
|
32
|
+
- 3
|
33
|
+
- 2
|
34
|
+
version: 2.3.2
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: rspec
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 13
|
46
|
+
segments:
|
47
|
+
- 1
|
48
|
+
- 2
|
49
|
+
- 9
|
50
|
+
version: 1.2.9
|
51
|
+
type: :development
|
52
|
+
version_requirements: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: rspec-rails
|
55
|
+
prerelease: false
|
56
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 13
|
62
|
+
segments:
|
63
|
+
- 1
|
64
|
+
- 2
|
65
|
+
- 9
|
66
|
+
version: 1.2.9
|
67
|
+
type: :development
|
68
|
+
version_requirements: *id003
|
69
|
+
description: Rails helper for generating navbars in a declarative manner
|
70
|
+
email: github@unboxedconsulting.com
|
71
|
+
executables: []
|
72
|
+
|
73
|
+
extensions: []
|
74
|
+
|
75
|
+
extra_rdoc_files:
|
76
|
+
- LICENSE
|
77
|
+
- README.rdoc
|
78
|
+
files:
|
79
|
+
- .document
|
80
|
+
- LICENSE
|
81
|
+
- README.rdoc
|
82
|
+
- Rakefile
|
83
|
+
- VERSION
|
84
|
+
- lib/tabnav.rb
|
85
|
+
- lib/tabnav/helper.rb
|
86
|
+
- lib/tabnav/navbar.rb
|
87
|
+
- lib/tabnav/tab.rb
|
88
|
+
- spec/spec.opts
|
89
|
+
- spec/spec_helper.rb
|
90
|
+
- spec/tabnav/helper_spec.rb
|
91
|
+
- spec/tabnav/integration_spec.rb
|
92
|
+
- spec/tabnav/navbar_spec.rb
|
93
|
+
- spec/tabnav/tab_spec.rb
|
94
|
+
has_rdoc: true
|
95
|
+
homepage: http://github.com/unboxed/tabnav
|
96
|
+
licenses: []
|
97
|
+
|
98
|
+
post_install_message:
|
99
|
+
rdoc_options:
|
100
|
+
- --charset=UTF-8
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
none: false
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
hash: 3
|
109
|
+
segments:
|
110
|
+
- 0
|
111
|
+
version: "0"
|
112
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
hash: 3
|
118
|
+
segments:
|
119
|
+
- 0
|
120
|
+
version: "0"
|
121
|
+
requirements: []
|
122
|
+
|
123
|
+
rubyforge_project:
|
124
|
+
rubygems_version: 1.3.7
|
125
|
+
signing_key:
|
126
|
+
specification_version: 3
|
127
|
+
summary: Rails helper for generating navbars
|
128
|
+
test_files:
|
129
|
+
- spec/spec_helper.rb
|
130
|
+
- spec/tabnav/helper_spec.rb
|
131
|
+
- spec/tabnav/integration_spec.rb
|
132
|
+
- spec/tabnav/navbar_spec.rb
|
133
|
+
- spec/tabnav/tab_spec.rb
|