Nav Tag spec round 1

arnaud sellenet committed Jun 17, 2014
commit 4161b6649952e160941c794095b6e550548893a3
Showing 2 changed files with 175 additions and 22 deletions
locomotive/steam/liquid/tags/nav.rb b/lib/locomotive/steam/liquid/tags/nav.rb +24 -22
@@ @@ -16,7 +16,7 @@ module Locomotive
Syntax = /(#{::Liquid::Expression}+)?/
- attr_accessor :current_page, :mounting_point
+ attr_accessor :current_page, :site
def initialize(tag_name, markup, tokens, options)
if markup =~ Syntax
@@ @@ -32,7 +32,6 @@ module Locomotive
def render(context)
self.set_accessors_from_context(context)
-
entries = self.fetch_entries
output = self.build_entries_output(entries)
@@ @@ -72,17 +71,19 @@ module Locomotive
# @return [ Array ] List of pages
#
def fetch_entries
- children = (case @source
- when 'site' then self.mounting_point.pages['index']
+ children = root.children.try(:clone) || []
+ children.delete_if { |p| !include_page?(p) }
+ end
+
+ def root
+ case @source
+ when 'site' then Locomotive::Models['pages']['index']
when 'parent' then self.current_page.parent || self.current_page
when 'page' then self.current_page
else
- self.mounting_point.pages[@source]
- end).children.try(:clone) || []
-
- children.delete_if { |p| !include_page?(p) }
+ Locomotive::Models['pages'][@source]
+ end
end
-
# Determine whether or not a page should be a part of the menu.
#
# @param [ Object ] page The page
@@ @@ -93,7 +94,7 @@ module Locomotive
if !page.listed? || page.templatized? || !page.published?
false
elsif @_options[:exclude]
- (page.fullpath =~ @_options[:exclude]).nil?
+ (page.fullpath[:en] =~ @_options[:exclude]).nil?
else
true
end
@@ @@ -106,7 +107,7 @@ module Locomotive
# @return [ Boolean ]
#
def page_selected?(page)
- self.current_page.fullpath =~ /^#{page.fullpath}(\/.*)?$/
+ self.current_page.fullpath[:en] =~ /^#{page.fullpath[:en]}(\/.*)?$/
end
# Determine if the children of a page have to be rendered or not.
@@ @@ -131,7 +132,7 @@ module Locomotive
#
def entry_label(page)
icon = @_options[:icon] ? '<span></span>' : ''
- title = @_options[:liquid_render] ? @_options[:liquid_render].render('page' => page) : page.title
+ title = @_options[:liquid_render] ? @_options[:liquid_render].render('page' => page) : page.title[::I18n.locale]
if icon.blank?
title
@@ @@ -149,10 +150,10 @@ module Locomotive
# @return [ String ] The localized url
#
def entry_url(page)
- if ::I18n.locale.to_s == self.mounting_point.default_locale.to_s
- "/#{page.fullpath}"
+ if ::I18n.locale.to_s == self.site.default_locale.to_s
+ "/#{page.fullpath[::I18n.locale]}"
else
- "/#{::I18n.locale}/#{page.fullpath}"
+ "/#{::I18n.locale}/#{page.fullpath[::I18n.locale]}"
end
end
@@ @@ -165,7 +166,8 @@ module Locomotive
#
def entry_css(page, css = '')
_css = 'link'
- _css += " #{page} #{@_options[:active_class]}" if self.page_selected?(page)
+ #_css += " #{page} #{@_options[:active_class]}" if self.page_selected?(page)
+ _css += " #{@_options[:active_class]}" if self.page_selected?(page)
(_css + " #{css}").strip
end
@@ @@ -191,7 +193,7 @@ module Locomotive
options = %{ class="dropdown-toggle" data-toggle="dropdown"}
end
- self.render_tag(:li, id: "#{page.slug.to_s.dasherize}-link", css: css) do
+ self.render_tag(:li, id: "#{page.slug[::I18n.locale].to_s.dasherize}-link", css: css) do
children_output = depth.succ <= @_options[:depth].to_i ? self.render_entry_children(page, depth.succ) : ''
%{<a href="#{url}"#{options}>#{label}</a>} + children_output
end
@@ @@ -209,7 +211,7 @@ module Locomotive
css = self.bootstrap? ? 'dropdown-menu' : ''
unless entries.empty?
- self.render_tag(:ul, id: "#{@_options[:id]}-#{page.slug.to_s.dasherize}", css: css) do
+ self.render_tag(:ul, id: "#{@_options[:id]}-#{page.slug[::I18n.locale].dasherize}", css: css) do
self.build_entries_output(entries, depth)
end
else
@@ @@ -234,11 +236,11 @@ module Locomotive
end
# Avoid to call context.registers to get the current page
- # and the mounting point.
+ # and the site.
#
def set_accessors_from_context(context)
self.current_page = context.registers[:page]
- self.mounting_point = context.registers[:mounting_point]
+ self.site = context.registers[:site]
end
# Parse the template of the snippet give in option of the tag.
@@ @@ -249,7 +251,7 @@ module Locomotive
source = if template_name.include?('{')
template_name
else
- context[:mounting_point].snippets[template_name].try(:source)
+ context[:site].snippets[template_name].try(:source)
end
source ? ::Liquid::Template.parse(source) : nil
@@ @@ -284,4 +286,4 @@ module Locomotive
end
end
end
- end
\ No newline at end of file
+ end
spec/unit/liquid/tags/nav_spec.rb +151 -0
@@ @@ -0,0 +1,151 @@
+ require 'spec_helper'
+
+ describe Locomotive::Steam::Liquid::Tags::Nav do
+
+ subject { Locomotive::Steam::Liquid::Tags::Nav }
+ let(:entity_class) { Locomotive::Steam::Entities::Page }
+ let(:site_class) { Locomotive::Steam::Entities::Site }
+ let(:home) { entity_class.new fullpath: { en: 'index' }}
+ let(:site) { site_class.new locales: %w(en fr) }
+
+ before do
+ home_children = [
+ entity_class.new(title: { en: 'Child #1' }, fullpath: { en: 'child_1' }, slug: { en: 'child_1' }, published: true, listed: true),
+ entity_class.new(title: { en: 'Child #2' }, fullpath: { en: 'child_2' }, slug: { en: 'child_2' }, published: true, listed: true)
+ ]
+ home.stub(children: home_children)
+
+ other_children = [
+ entity_class.new(title: { en: 'Child #2.1' }, fullpath: { en: 'child_2/sub_child_1' }, slug: { en: 'sub_child_1' }, published: true, listed: true),
+ entity_class.new(title: { en: 'Child #2.2' }, fullpath: { en: 'child_2/sub_child_2' }, slug: { en: 'sub_child_2' }, published: true, listed: true),
+ entity_class.new(title: { en: 'Unpublished #2.2' }, fullpath: { en: 'child_2/sub_child_unpublishd_2' }, slug: { en: 'sub_child_unpublished_2' }, published: false, listed: true),
+ entity_class.new(title: { en: 'Templatized #2.3' }, fullpath: { en: 'child_2/sub_child_template_3' }, slug: { en: 'sub_child_template_3' }, published: true, templatized: true, listed: true),
+ entity_class.new(title: { en: 'Unlisted #2.4' }, fullpath: { en: 'child_2/sub_child_unlisted_4' }, slug: { en: 'sub_child_unlisted_4' }, published: true, listed: false)
+ ]
+ home.children.last.stub(children: other_children)
+
+ pages = [home]
+ Locomotive::Models['pages'].stub(root: pages)
+ Locomotive::Models['pages'].stub(all: pages)
+ Locomotive::Models['pages'].stub(:[]).with('index').and_return home
+ end
+
+ context '#rendering' do
+
+ it 'renders from site' do
+ render_nav.should == '<nav id="nav"><ul><li id="child-1-link" class="link first"><a href="/child_1">Child #1</a></li><li id="child-2-link" class="link last"><a href="/child_2">Child #2</a></li></ul></nav>'
+ end
+
+ it 'renders from page' do
+ render_nav('page').should == '<nav id="nav"><ul><li id="child-1-link" class="link first"><a href="/child_1">Child #1</a></li><li id="child-2-link" class="link last"><a href="/child_2">Child #2</a></li></ul></nav>'
+ end
+
+ it 'renders from parent' do
+ (page = home.children.last.children.first).stub(parent: home.children.last)
+ output = render_nav 'parent', { page: page }
+ output.should == '<nav id="nav"><ul><li id="sub-child-1-link" class="link on first"><a href="/child_2/sub_child_1">Child #2.1</a></li><li id="sub-child-2-link" class="link last"><a href="/child_2/sub_child_2">Child #2.2</a></li></ul></nav>'
+ end
+
+ it 'renders children to depth' do
+ output = render_nav('site', {}, 'depth: 2')
+
+ output.should match(/<nav id="nav">/)
+ output.should match(/<ul>/)
+ output.should match(/<li id="child-1-link" class="link first">/)
+ output.should match(/<\/a><ul id="nav-child-2">/)
+ output.should match(/<li id="sub-child-1-link" class="link first">/)
+ output.should match(/<li id="sub-child-2-link" class="link last">/)
+ output.should match(/<\/a><\/li><\/ul><\/li><\/ul><\/nav>/)
+ end
+
+ it 'does not render templatized pages' do
+ output = render_nav('site', {}, 'depth: 2')
+
+ output.should_not match(/sub-child-template-3/)
+ end
+
+ it 'does not render unpublished pages' do
+ output = render_nav('site', {}, 'depth: 2')
+
+ output.should_not match(/sub-child-unpublished-3/)
+ end
+
+ it 'does not render unlisted pages' do
+ output = render_nav('site', {}, 'depth: 2')
+
+ output.should_not match(/sub-child-unlisted-3/)
+ end
+
+ it 'does not render nested excluded pages' do
+ output = render_nav('site', {}, 'depth: 2, exclude: "child_2/sub_child_2"')
+
+ output.should match(/<li id="child-2-link" class="link last">/)
+ output.should match(/<li id="sub-child-1-link" class="link first last">/)
+ output.should_not match(/sub-child-2/)
+
+ output = render_nav('site', {}, 'depth: 2, exclude: "child_2"')
+
+ output.should match(/<li id="child-1-link" class="link first last">/)
+ output.should_not match(/child-2/)
+ output.should_not match(/sub-child/)
+ end
+
+ it 'adds an icon before the link' do
+ render_nav('site', {}, 'icon: true')
+ .should match(/<li id="child-1-link" class="link first"><a href="\/child_1"><span><\/span> Child #1<\/a>/)
+ render_nav('site', {}, 'icon: before')
+ .should match(/<li id="child-1-link" class="link first"><a href="\/child_1"><span><\/span> Child #1<\/a>/)
+ end
+
+ it 'adds an icon after the link' do
+ render_nav('site', {}, 'icon: after')
+ .should match(/<li id="child-1-link" class="link first"><a href="\/child_1">Child #1 <span><\/span><\/a><\/li>/)
+ end
+
+ it 'renders a snippet for the title' do
+ render_nav('site', {}, 'snippet: "-{{page.title}} {{ foo.png | theme_image_tag }}-"')
+ .should match( /<li id="child-1-link" class="link first"><a href="\/child_1">-Child #1 <img src=\"\" >-<\/a><\/li>/)
+ end
+
+ it 'assigns a different dom id' do
+ render_nav('site', {}, 'id: "main-nav"')
+ .should match(/<nav id="main-nav">/)
+ end
+
+ it 'assigns a class' do
+ render_nav('site', {}, 'class: "nav"')
+ .should match(/<nav id="nav" class="nav">/)
+ end
+
+ it 'assigns a class other than "on" for a selected item' do
+ (page = @home.children.last.children.first).stubs(:parent).returns(@home.children.last)
+ output = render_nav 'parent', { page: page }, 'active_class: "active"'
+ output.should match(/<li id="sub-child-1-link" class="link active first">/)
+ end
+
+ it 'excludes entries based on a regexp' do
+ render_nav('page', {}, 'exclude: "child_1"').should == '<nav id="nav"><ul><li id="child-2-link" class="link first last"><a href="/child_2">Child #2</a></li></ul></nav>'
+ end
+
+ it 'does not render the parent ul' do
+ render_nav('site', {}, 'no_wrapper: true')
+ .should_not match(/<ul id="nav">/)
+ end
+
+ it 'localizes the links' do
+ I18n.with_locale('fr') do
+ render_nav.should == '<nav id="nav"><ul><li id="child-1-link" class="link first"><a href="/fr/child_1">Child #1</a></li><li id="child-2-link" class="link last"><a href="/fr/child_2">Child #2</a></li></ul></nav>'
+ end
+ end
+
+ end
+
+ def render_nav(source = 'site', registers = {}, template_option = '')
+ registers = { site: site, page: home }.merge(registers)
+ liquid_context = ::Liquid::Context.new({}, {}, registers)
+
+ output = Liquid::Template.parse("{% nav #{source} #{template_option} %}").render(liquid_context)
+ output.gsub(/\n\s{0,}/, '')
+ end
+
+ end