simple-navigation-4.0.3/0000755000004100000410000000000012513767261015206 5ustar www-datawww-datasimple-navigation-4.0.3/Rakefile0000644000004100000410000000047412513767261016660 0ustar www-datawww-datarequire 'bundler/gem_tasks' require 'rspec/core/rake_task' require 'rdoc/task' RSpec::Core::RakeTask.new(:spec) task default: :spec RDoc::Task.new do |rdoc| rdoc.rdoc_dir = 'rdoc' rdoc.title = 'SimpleNavigation' rdoc.options << '--inline-source' rdoc.rdoc_files.include('README.md', 'lib/**/*.rb') end simple-navigation-4.0.3/Gemfile0000644000004100000410000000004712513767261016502 0ustar www-datawww-datasource 'https://rubygems.org' gemspec simple-navigation-4.0.3/simple-navigation.gemspec0000644000004100000410000000404312513767261022202 0ustar www-datawww-data# coding: utf-8 lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'simple_navigation/version' Gem::Specification.new do |spec| spec.name = 'simple-navigation' spec.version = SimpleNavigation::VERSION spec.authors = ['Andi Schacke', 'Mark J. Titorenko', 'Simon Courtois'] spec.email = ['andi@codeplant.ch'] spec.description = "With the simple-navigation gem installed you can easily " \ "create multilevel navigations for your Rails, Sinatra or "\ "Padrino applications. The navigation is defined in a " \ "single configuration file. It supports automatic as well "\ "as explicit highlighting of the currently active " \ "navigation through regular expressions." spec.summary = "simple-navigation is a ruby library for creating navigations "\ "(with multiple levels) for your Rails2, Rails3, Rails4, Sinatra or " \ "Padrino application." spec.homepage = 'http://github.com/codeplant/simple-navigation' spec.license = 'MIT' spec.files = `git ls-files -z`.split("\x0") spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ['lib'] spec.rdoc_options = ['--inline-source', '--charset=UTF-8'] spec.add_runtime_dependency 'activesupport', '>= 2.3.2' spec.add_development_dependency 'bundler', '~> 1.5' spec.add_development_dependency 'capybara' spec.add_development_dependency 'coveralls', '~> 0.7' spec.add_development_dependency 'guard-rspec', '~> 4.2' spec.add_development_dependency 'memfs', '~> 0.4.1' spec.add_development_dependency 'rake' spec.add_development_dependency 'rdoc' spec.add_development_dependency 'rspec', '~> 3.0' spec.add_development_dependency 'tzinfo', '>= 0' end simple-navigation-4.0.3/.rspec0000644000004100000410000000006512513767261016324 0ustar www-datawww-data--color --format=documentation --require spec_helper simple-navigation-4.0.3/spec/0000755000004100000410000000000012513767261016140 5ustar www-datawww-datasimple-navigation-4.0.3/spec/simple_navigation_spec.rb0000644000004100000410000001363712513767261023221 0ustar www-datawww-datadescribe SimpleNavigation do before { subject.config_file_path = 'path_to_config' } describe 'config_file_path=' do before { subject.config_file_paths = ['existing_path'] } it 'overrides the config_file_paths' do subject.config_file_path = 'new_path' expect(subject.config_file_paths).to eq ['new_path'] end end describe '.default_config_file_path' do before { allow(subject).to receive_messages(root: 'root') } it 'returns the config file path according to :root setting' do expect(subject.default_config_file_path).to eq 'root/config' end end describe 'Regarding renderers' do it 'registers the builtin renderers by default' do expect(subject.registered_renderers).not_to be_empty end describe '.register_renderer' do let(:renderer) { double(:renderer) } it 'adds the specified renderer to the list of renderers' do subject.register_renderer(my_renderer: renderer) expect(subject.registered_renderers[:my_renderer]).to be renderer end end end describe '.set_env' do before do subject.config_file_paths = [] allow(subject).to receive_messages(default_config_file_path: 'default_path') subject.set_env('root', 'my_env') end it 'sets the root' do expect(subject.root).to eq 'root' end it 'sets the environment' do expect(subject.environment).to eq 'my_env' end it 'adds the default-config path to the list of config_file_paths' do expect(subject.config_file_paths).to eq ['default_path'] end end describe '.load_config', memfs: true do let(:paths) { ['/path/one', '/path/two'] } before do FileUtils.mkdir_p(paths) allow(subject).to receive_messages(config_file_paths: paths) end context 'when the config file for the context exists' do before do File.open('/path/two/navigation.rb', 'w') { |f| f.puts 'default content' } File.open('/path/one/other_navigation.rb', 'w') { |f| f.puts 'other content' } end context 'when no context is provided' do it 'stores the configuration in config_files for the default context' do subject.load_config expect(subject.config_files[:default]).to eq "default content\n" end end context 'when a context is provided' do it 'stores the configuration in config_files for the given context' do subject.load_config(:other) expect(subject.config_files[:other]).to eq "other content\n" end end context 'and environment is production' do before { allow(subject).to receive_messages(environment: 'production') } it 'loads the config file only for the first call' do subject.load_config File.open('/path/two/navigation.rb', 'w') { |f| f.puts 'new content' } subject.load_config expect(subject.config_files[:default]).to eq "default content\n" end end context "and environment isn't production" do it 'loads the config file for every call' do subject.load_config File.open('/path/two/navigation.rb', 'w') { |f| f.puts 'new content' } subject.load_config expect(subject.config_files[:default]).to eq "new content\n" end end end context "when the config file for the context doesn't exists" do it 'raises an exception' do expect{ subject.load_config }.to raise_error end end end describe '.config' do it 'returns the Configuration singleton instance' do expect(subject.config).to be SimpleNavigation::Configuration.instance end end describe '.active_item_container_for' do let(:primary) { double(:primary) } before { allow(subject.config).to receive_messages(primary_navigation: primary) } context 'when level is :all' do it 'returns the primary_navigation' do nav = subject.active_item_container_for(:all) expect(nav).to be primary end end context 'when level is :leaves' do it 'returns the currently active leaf-container' do expect(primary).to receive(:active_leaf_container) subject.active_item_container_for(:leaves) end end context 'when level is a Range' do it 'takes the min of the range to lookup the active container' do expect(primary).to receive(:active_item_container_for).with(2) subject.active_item_container_for(2..3) end end context 'when level is an Integer' do it 'considers the Integer to lookup the active container' do expect(primary).to receive(:active_item_container_for).with(1) subject.active_item_container_for(1) end end context 'when level is something else' do it 'raises an exception' do expect{ subject.active_item_container_for('something else') }.to raise_error end end end describe '.load_adapter' do shared_examples 'loading the right adapter' do |framework, adapter| context "when the context is #{framework}" do before do allow(subject).to receive_messages(framework: framework) subject.load_adapter end it "returns the #{framework} adapter" do adapter_class = SimpleNavigation::Adapters.const_get(adapter) expect(subject.adapter_class).to be adapter_class end end end it_behaves_like 'loading the right adapter', :rails, :Rails it_behaves_like 'loading the right adapter', :padrino, :Padrino it_behaves_like 'loading the right adapter', :sinatra, :Sinatra end describe '.init_adapter_from' do let(:adapter) { double(:adapter) } let(:adapter_class) { double(:adapter_class, new: adapter) } it 'sets the adapter to a new instance of adapter_class' do subject.adapter_class = adapter_class subject.init_adapter_from(:default) expect(subject.adapter).to be adapter end end end simple-navigation-4.0.3/spec/initializers/0000755000004100000410000000000012513767261020646 5ustar www-datawww-datasimple-navigation-4.0.3/spec/initializers/coveralls.rb0000644000004100000410000000004512513767261023164 0ustar www-datawww-datarequire 'coveralls' Coveralls.wear! simple-navigation-4.0.3/spec/initializers/memfs.rb0000644000004100000410000000020412513767261022276 0ustar www-datawww-datarequire 'memfs' RSpec.configure do |config| config.around(memfs: true) do |example| MemFs.activate { example.run } end end simple-navigation-4.0.3/spec/initializers/rspec.rb0000644000004100000410000000017312513767261022310 0ustar www-datawww-dataRSpec.configure do |config| config.expect_with(:rspec) do |c| c.syntax = :expect end config.order = :random end simple-navigation-4.0.3/spec/initializers/rails.rb0000644000004100000410000000005512513767261022305 0ustar www-datawww-databegin require 'rails' rescue LoadError end simple-navigation-4.0.3/spec/initializers/have_css_matcher.rb0000644000004100000410000000077712513767261024504 0ustar www-datawww-dataRSpec::Matchers.define :have_css do |expected, times| match do |actual| selector = HTML::Selector.new(expected).select(actual) if times expect(selector.size).to eq times else expect(selector.size).to be >= 1 end end failure_message do |actual| "expected #{actual.to_s} to have #{times || 1} elements matching '#{expected}'" end failure_message_when_negated do |actual| "expected #{actual.to_s} not to have #{times || 1} elements matching '#{expected}'" end end simple-navigation-4.0.3/spec/spec_helper.rb0000644000004100000410000000400712513767261020757 0ustar www-datawww-datarequire 'initializers/have_css_matcher' require 'initializers/memfs' require 'initializers/coveralls' require 'initializers/rails' require 'initializers/rspec' require 'capybara/rspec' require 'bundler/setup' Bundler.require if defined? Rails require 'fake_app/rails_app' require 'rspec/rails' Capybara.app = RailsApp::Application RSpec.configure do |config| config.before do SimpleNavigation.config_files.clear setup_adapter_for :rails end end end def setup_adapter_for(framework, context = double(:context)) if framework == :rails allow(context).to receive_messages(view_context: ActionView::Base.new) end allow(SimpleNavigation).to receive_messages(framework: framework) SimpleNavigation.load_adapter SimpleNavigation.init_adapter_from(context) end def select_an_item(item) allow(item).to receive_messages(selected?: true) end def setup_container(dom_id, dom_class) container = SimpleNavigation::ItemContainer.new(1) container.dom_id = dom_id container.dom_class = dom_class container end def setup_navigation(dom_id, dom_class) setup_adapter_for :rails container = setup_container(dom_id, dom_class) setup_items(container) container end # FIXME: adding the :link option for the list renderer messes up the other # renderers def setup_items(container) container.item :users, 'Users', '/users', html: { id: 'users_id' }, link_html: { id: 'users_link_id' } container.item :invoices, 'Invoices', '/invoices' do |invoices| invoices.item :paid, 'Paid', '/invoices/paid' invoices.item :unpaid, 'Unpaid', '/invoices/unpaid' end container.item :accounts, 'Accounts', '/accounts', html: { style: 'float:right' } container.item :miscellany, 'Miscellany' container.items.each do |item| allow(item).to receive_messages(selected?: false, selected_by_condition?: false) if item.sub_navigation item.sub_navigation.items.each do |item| allow(item).to receive_messages(selected?: false, selected_by_condition?: false) end end end end simple-navigation-4.0.3/spec/integration/0000755000004100000410000000000012513767261020463 5ustar www-datawww-datasimple-navigation-4.0.3/spec/integration/rendering_navigation_spec.rb0000644000004100000410000000046312513767261026221 0ustar www-datawww-dataRSpec.feature 'Rendering navigation' do background do SimpleNavigation.set_env(RailsApp::Application.root, 'test') end scenario 'Rendering basic navigation', type: :feature do visit '/base_spec' expect(page).to have_content('Item 1') expect(page).to have_content('Item 2') end end simple-navigation-4.0.3/spec/simple_navigation/0000755000004100000410000000000012513767261021650 5ustar www-datawww-datasimple-navigation-4.0.3/spec/simple_navigation/renderer/0000755000004100000410000000000012513767261023456 5ustar www-datawww-datasimple-navigation-4.0.3/spec/simple_navigation/renderer/text_spec.rb0000644000004100000410000000271412513767261026005 0ustar www-datawww-datamodule SimpleNavigation module Renderer describe Text do let!(:navigation) { setup_navigation('nav_id', 'nav_class') } let(:item) { nil } let(:options) {{ level: :all }} let(:output) { renderer.render(navigation) } let(:renderer) { Text.new(options) } before { select_an_item(navigation[item]) if item } describe '#render' do context 'when no item is selected' do it 'renders an empty string' do expect(output).to eq '' end end context 'when an item is selected' do let(:item) { :invoices } it "renders the selected item's name" do expect(output).to eq 'Invoices' end end context 'when a sub navigation item is selected' do before do allow(navigation[:invoices]).to receive_messages(selected?: true) allow(navigation[:invoices].sub_navigation[:unpaid]).to \ receive_messages(selected?: true, selected_by_condition?: true) end it 'separates the items with a space' do expect(output).to eq 'Invoices Unpaid' end context "and the :join_with option is set" do let(:options) {{ level: :all, join_with: ' | ' }} it 'separates the items with the specified separator' do expect(output).to eq 'Invoices | Unpaid' end end end end end end end simple-navigation-4.0.3/spec/simple_navigation/renderer/list_spec.rb0000644000004100000410000000611712513767261025775 0ustar www-datawww-datamodule SimpleNavigation module Renderer describe List do let!(:navigation) { setup_navigation('nav_id', 'nav_class') } let(:item) { nil } let(:options) {{ level: :all }} let(:output) { HTML::Document.new(raw_output).root } let(:raw_output) { renderer.render(navigation) } let(:renderer) { List.new(options) } before { select_an_item(navigation[item]) if item } describe '#render' do it "renders an 'ul' tag for the navigation" do expect(output).to have_css('ul') end it "sets the right html id on the rendered 'ul' tag" do expect(output).to have_css('ul#nav_id') end it "sets the right html classes on the rendered 'ul' tag" do expect(output).to have_css('ul.nav_class') end context 'when an item has no specified id' do it "renders the item's 'li' tag with the item's stingified key as id" do expect(output).to have_css('li#invoices') end end context 'when an item has a specified id' do it "renders the item's 'li' tag with the specified id" do expect(output).to have_css('li#users_id') end end context 'when no item is selected' do it "renders each item as 'li' tag without any selected class" do expect(output).not_to have_css('ul li.selected') end it "renders each item as 'a' tag without any selected class" do expect(output).not_to have_css('ul li a.selected') end end context 'when an item is selected' do let(:item) { :invoices } it "renders the item's 'li' tag with its id and selected classes" do expect(output).to have_css('li#invoices.selected') end it "renders the item's 'a' tag with the selected classes" do expect(output).to have_css('li#invoices a.selected') end end context 'when the :ordered option is true' do let(:options) {{ level: :all, ordered: true }} it "renders an 'ol' tag for the navigation" do expect(output).to have_css('ol') end it "sets the right html id on the rendered 'ol' tag" do expect(output).to have_css('ol#nav_id') end it "sets the right html classes on the rendered 'ol' tag" do expect(output).to have_css('ol.nav_class') end end context 'when a sub navigation item is selected' do before do allow(navigation[:invoices]).to receive_messages(selected?: true) allow(navigation[:invoices].sub_navigation[:unpaid]).to \ receive_messages(selected?: true, selected_by_condition?: true) end it 'renders the parent items as selected' do expect(output).to have_css('li#invoices.selected') end it "renders the selected nested item's link as selected" do expect(output).to have_css('li#unpaid.selected') end end end end end end simple-navigation-4.0.3/spec/simple_navigation/renderer/base_spec.rb0000644000004100000410000001631412513767261025734 0ustar www-datawww-datamodule SimpleNavigation module Renderer describe Base do subject(:base) { Base.new(options) } let(:adapter) { double(:adapter) } let(:options) { Hash.new } before { allow(SimpleNavigation).to receive_messages(adapter: adapter) } it 'delegates the :link_to method to adapter' do allow(adapter).to receive_messages(link_to: 'link_to') expect(base.link_to).to eq 'link_to' end it 'delegates the :content_tag method to adapter' do allow(adapter).to receive_messages(content_tag: 'content_tag') expect(base.content_tag).to eq 'content_tag' end describe '#initialize' do it "sets the renderer adapter to the SimpleNavigation one" do expect(base.adapter).to be adapter end end describe '#options' do it "returns the renderer's options" do expect(base.options).to be options end end describe '#render' do it "raise an exception to indicate it's a subclass responsibility" do expect{ base.render(:container) }.to raise_error end end describe '#expand_all?' do context 'when :options is set' do context 'and the :expand_all option is true' do let(:options) {{ expand_all: true }} it 'returns true' do expect(base.expand_all?).to be true end end context 'and the :expand_all option is false' do let(:options) {{ expand_all: false }} it 'returns false' do expect(base.expand_all?).to be false end end end context "when :options isn't set" do let(:options) { Hash.new } it 'returns false' do expect(base.expand_all?).to be false end end end describe '#skip_if_empty?' do context 'when :options is set' do context 'and the :skip_if_empty option is true' do let(:options) {{ skip_if_empty: true }} it 'returns true' do expect(base.skip_if_empty?).to be true end end context 'and the :skip_if_empty option is false' do let(:options) {{ skip_if_empty: false }} it 'returns true' do expect(base.skip_if_empty?).to be false end end end context "when :options isn't set" do let(:options) { Hash.new } it 'returns true' do expect(base.skip_if_empty?).to be false end end end describe '#level' do context 'and the :level option is set' do let(:options) {{ level: 1 }} it 'returns the specified level' do expect(base.level).to eq 1 end end context "and the :level option isn't set" do let(:options) { Hash.new } it 'returns :all' do expect(base.level).to eq :all end end end describe '#consider_sub_navigation?' do let(:item) { double(:item) } before { allow(item).to receive_messages(sub_navigation: sub_navigation) } context 'when the item has no sub navigation' do let(:sub_navigation) { nil } it 'returns false' do expect(base.send(:consider_sub_navigation?, item)).to be false end end context 'when the item has sub navigation' do let(:sub_navigation) { double(:sub_navigation) } context 'and the renderer has an unknown level' do before { allow(base).to receive_messages(level: 'unknown') } it 'returns false' do expect(base.send(:consider_sub_navigation?, item)).to be false end end context 'and the renderer has a level set to :all' do before { allow(base).to receive_messages(level: :all) } it 'returns false' do expect(base.send(:consider_sub_navigation?, item)).to be true end end context "when the renderer's level is a number" do before { allow(base).to receive_messages(level: 2) } it 'returns false' do expect(base.send(:consider_sub_navigation?, item)).to be false end end context "when the renderer's level is a Range" do before { allow(base).to receive_messages(level: 2..3) } context "and sub navigation's level is greater than range.max" do before { allow(sub_navigation).to receive_messages(level: 4) } it 'returns false' do expect(base.send(:consider_sub_navigation?, item)).to be false end end context "and sub navigation's level is equal to range.max" do before { allow(sub_navigation).to receive_messages(level: 3) } it 'returns true' do expect(base.send(:consider_sub_navigation?, item)).to be true end end context "and sub navigation's level is equal to range.min" do before { allow(sub_navigation).to receive_messages(level: 2) } it 'returns true' do expect(base.send(:consider_sub_navigation?, item)).to be true end end end end end describe '#include_sub_navigation?' do let(:item) { double(:item) } context 'when consider_sub_navigation? is true' do before { allow(base).to receive_messages(consider_sub_navigation?: true) } context 'and expand_sub_navigation? is true' do before { allow(base).to receive_messages(expand_sub_navigation?: true) } it 'returns true' do expect(base.include_sub_navigation?(item)).to be true end end context 'and expand_sub_navigation? is false' do before { allow(base).to receive_messages(expand_sub_navigation?: false) } it 'returns false' do expect(base.include_sub_navigation?(item)).to be false end end end context 'consider_sub_navigation? is false' do before { allow(base).to receive_messages(consider_sub_navigation?: false) } context 'and expand_sub_navigation? is true' do before { allow(base).to receive_messages(expand_sub_navigation?: true) } it 'returns false' do expect(base.include_sub_navigation?(item)).to be false end end context 'and expand_sub_navigation? is false' do before { allow(base).to receive_messages(expand_sub_navigation?: false) } it 'returns false' do expect(base.include_sub_navigation?(item)).to be false end end end end describe '#render_sub_navigation_for' do let(:item) { double(:item, sub_navigation: sub_navigation) } let(:sub_navigation) { double(:sub_navigation) } it 'renders the sub navigation passing it the options' do expect(sub_navigation).to receive(:render).with(options) base.render_sub_navigation_for(item) end end end end end simple-navigation-4.0.3/spec/simple_navigation/renderer/links_spec.rb0000644000004100000410000000536712513767261026150 0ustar www-datawww-datamodule SimpleNavigation module Renderer describe Links do describe '#render' do let!(:navigation) { setup_navigation('nav_id', 'nav_class') } let(:item) { nil } let(:options) {{ level: :all }} let(:output) { HTML::Document.new(raw_output).root } let(:raw_output) { renderer.render(navigation) } let(:renderer) { Links.new(options) } before { select_an_item(navigation[item]) if item } it "renders a 'div' tag for the navigation" do expect(output).to have_css('div') end it "sets the right html id on the rendered 'div' tag" do expect(output).to have_css('div#nav_id') end it "sets the right html classes on the rendered 'div' tag" do expect(output).to have_css('div.nav_class') end it "renders an 'a' tag for each item" do expect(output).to have_css('a', 3) end it "renders the 'a' tags with the corresponding item's :html_options" do expect(output).to have_css('a[style=float:right]') end context 'when an item has a specified id' do it "renders the 'a' tags with the specified id" do expect(output).to have_css('a#users_id') end end context 'when an item has no specified id' do it "uses a default id by stringifying the item's key" do expect(output).to have_css('a#invoices') end end context 'when no item is selected' do it "renders items without the 'selected' class" do expect(output).not_to have_css('a.selected') end end context 'when an item is selected' do let(:item) { :invoices } it "renders the selected item with the 'selected' class" do expect(output).to have_css('a#invoices.selected') end end context "when the :join_with option is set" do let(:options) {{ level: :all, join_with: ' | ' }} it 'separates the items with the specified separator' do expect(raw_output.scan(' | ').size).to eq 3 end end context 'when a sub navigation item is selected' do before do allow(navigation[:invoices]).to receive_messages(selected?: true) allow(navigation[:invoices].sub_navigation[:unpaid]).to \ receive_messages(selected?: true, selected_by_condition?: true) end it 'renders the main parent as selected' do expect(output).to have_css('a#invoices.selected') end it "doesn't render the nested item's link" do expect(output).not_to have_css('a#unpaid') end end end end end end simple-navigation-4.0.3/spec/simple_navigation/renderer/breadcrumbs_spec.rb0000644000004100000410000000726012513767261027313 0ustar www-datawww-datamodule SimpleNavigation module Renderer describe Breadcrumbs do let!(:navigation) { setup_navigation('nav_id', 'nav_class') } let(:item) { nil } let(:options) {{ level: :all }} let(:output) { HTML::Document.new(raw_output).root } let(:raw_output) { renderer.render(navigation) } let(:renderer) { Breadcrumbs.new(options) } before { select_an_item(navigation[item]) if item } describe '#render' do it "renders a 'div' tag for the navigation" do expect(output).to have_css('div') end it "sets the right html id on the rendered 'div' tag" do expect(output).to have_css('div#nav_id') end it "sets the right html classes on the rendered 'div' tag" do expect(output).to have_css('div.nav_class') end context 'when no item is selected' do it "doesn't render any 'a' tag in the 'div' tag" do expect(output).not_to have_css('div a') end end context 'when an item is selected' do let(:item) { :invoices } it "renders the selected 'a' tag" do expect(output).to have_css('div a') end it "remders the 'a' tag without any html id" do expect(output).not_to have_css('div a[id]') end it "renders the 'a' tag without any html class" do expect(output).not_to have_css('div a[class]') end context 'and the :allow_classes_and_ids option is true' do let(:options) {{ level: :all, allow_classes_and_ids: true }} it "renders the 'a' tag with the selected class" do expect(output).to have_css('div a.selected') end context "and the item hasn't any id explicitly set" do it "renders the 'a' tag without any html id" do expect(output).not_to have_css('div a[id]') end end context 'and the item has an explicitly set id' do let(:item) { :users } it "renders the 'a' tag with an html id" do expect(output).to have_css('div a#breadcrumb_users_link_id') end end end end context 'and the :prefix option is set' do let(:options) {{ prefix: 'You are here: ' }} context 'and there are no items to render' do let(:item) { nil } it "doesn't render the prefix before the breadcrumbs" do expect(raw_output).not_to match(/^You are here: /) end end context 'and there are items to render' do let(:item) { :invoices } it 'renders the prefix before the breadcrumbs' do expect(raw_output).to match(/^You are here: /) end end end context 'when a sub navigation item is selected' do before do allow(navigation[:invoices]).to receive_messages(selected?: true) allow(navigation[:invoices].sub_navigation[:unpaid]).to \ receive_messages(selected?: true, selected_by_condition?: true) end it 'renders all items as links' do expect(output).to have_css('div a', 2) end context 'when the :static_leaf option is true' do let(:options) {{ level: :all, static_leaf: true }} it 'renders the items as links' do expect(output).to have_css('div a') end it 'renders the last item as simple text' do expect(output).to have_css('div span') end end end end end end end simple-navigation-4.0.3/spec/simple_navigation/renderer/json_spec.rb0000644000004100000410000000401012513767261025761 0ustar www-datawww-datamodule SimpleNavigation module Renderer describe Json do describe '#render' do let!(:navigation) { setup_navigation('nav_id', 'nav_class') } let(:item) { :invoices } let(:options) {{ level: :all }} let(:output) { renderer.render(navigation) } let(:parsed_output) { JSON.parse(output) } let(:renderer) { Json.new(options) } before { select_an_item(navigation[item]) if item } context 'when an item is selected' do it 'renders the selected page' do invoices_item = parsed_output.find { |item| item['name'] == 'Invoices' } expect(invoices_item).to include('selected' => true) end end # FIXME: not sure if :as_hash returning an array makes sense... context 'when the :as_hash option is true' do let(:options) {{ level: :all, as_hash: true }} it 'returns a hash' do expect(output).to be_an Array end it 'renders the selected page' do invoices_item = output.find { |item| item[:name] == 'Invoices' } expect(invoices_item).to include(selected: true) end end context 'when a sub navigation item is selected' do let(:invoices_item) do parsed_output.find { |item| item['name'] == 'Invoices' } end let(:unpaid_item) do invoices_item['items'].find { |item| item['name'] == 'Unpaid' } end before do allow(navigation[:invoices]).to receive_messages(selected?: true) allow(navigation[:invoices].sub_navigation[:unpaid]).to \ receive_messages(selected?: true, selected_by_condition?: true) end it 'marks all the parent items as selected' do expect(invoices_item).to include('selected' => true) end it 'marks the item as selected' do expect(unpaid_item).to include('selected' => true) end end end end end end simple-navigation-4.0.3/spec/simple_navigation/adapters/0000755000004100000410000000000012513767261023453 5ustar www-datawww-datasimple-navigation-4.0.3/spec/simple_navigation/adapters/rails_spec.rb0000644000004100000410000002351312513767261026130 0ustar www-datawww-datamodule SimpleNavigation module Adapters describe Rails do let(:action_controller) { ActionController::Base } let(:adapter) { Rails.new(context) } let(:context) { double(:context, controller: controller) } let(:controller) { double(:controller) } let(:request) { double(:request) } let(:simple_navigation) { SimpleNavigation } let(:template) { double(:template, request: request) } describe '.register' do before { allow(action_controller).to receive(:include) } it 'calls set_env' do app_path = RailsApp::Application.root expect(simple_navigation).to receive(:set_env).with(app_path, 'test') simple_navigation.register end it 'extends the ActionController::Base with the Helpers' do expect(action_controller).to receive(:include) .with(SimpleNavigation::Helpers) simple_navigation.register end shared_examples 'installing helper method' do |method| it "installs the #{method} method as helper method" do simple_navigation.register helper_methods = action_controller.send(:_helper_methods) expect(helper_methods).to include(method) end end it_behaves_like 'installing helper method', :render_navigation it_behaves_like 'installing helper method', :active_navigation_item_name it_behaves_like 'installing helper method', :active_navigation_item_key it_behaves_like 'installing helper method', :active_navigation_item it_behaves_like 'installing helper method', :active_navigation_item_container end describe '#initialize' do context "when the controller's template is set" do before { allow(controller).to receive_messages(instance_variable_get: template) } it "sets the adapter's request accordingly" do expect(adapter.request).to be request end end context "when the controller's template is not set" do before { allow(controller).to receive_messages(instance_variable_get: nil) } it "sets the adapter's request to nil" do expect(adapter.request).to be_nil end end it "sets the adapter's controller to the context's controller" do expect(adapter.controller).to be controller end context "when the controller's template is stored as instance var (Rails2)" do context "when the controller's template is set" do before { allow(controller).to receive_messages(instance_variable_get: template) } it "sets the adapter's template accordingly" do expect(adapter.template).to be template end end context "when the controller's template is not set" do before { allow(controller).to receive_messages(instance_variable_get: nil) } it "set the adapter's template to nil" do expect(adapter.template).to be_nil end end end context "when the controller's template is stored as view_context (Rails3)" do context 'and the template is set' do before { allow(controller).to receive_messages(view_context: template) } it "sets the adapter's template accordingly" do expect(adapter.template).to be template end end context 'and the template is not set' do before { allow(controller).to receive_messages(view_context: nil) } it "sets the adapter's template to nil" do expect(adapter.template).to be_nil end end end end describe '#request_uri' do context "when the adapter's request is set" do before { allow(adapter).to receive_messages(request: request) } context 'and request.fullpath is defined' do let(:request) { double(:request, fullpath: '/fullpath') } it "sets the adapter's request_uri to the request.fullpath" do expect(adapter.request_uri).to eq '/fullpath' end end context 'and request.fullpath is not defined' do let(:request) { double(:request, request_uri: '/request_uri') } before { allow(adapter).to receive_messages(request: request) } it "sets the adapter's request_uri to the request.request_uri" do expect(adapter.request_uri).to eq '/request_uri' end end end context "when the adapter's request is not set" do before { allow(adapter).to receive_messages(request: nil) } it "sets the adapter's request_uri to an empty string" do expect(adapter.request_uri).to eq '' end end end describe '#request_path' do context "when the adapter's request is set" do let(:request) { double(:request, path: '/request_path') } before { allow(adapter).to receive_messages(request: request) } it "sets the adapter's request_path to the request.path" do expect(adapter.request_path).to eq '/request_path' end end context "when the adapter's request is not set" do before { allow(adapter).to receive_messages(request: nil) } it "sets the adapter's request_path to an empty string" do expect(adapter.request_path).to eq '' end end end describe '#context_for_eval' do context "when the adapter's controller is set" do before { adapter.instance_variable_set(:@controller, controller) } context "and the adapter's template is set" do before { adapter.instance_variable_set(:@template, template) } it "sets the adapter's context_for_eval to the template" do expect(adapter.context_for_eval).to be template end end context "and the adapter's template is not set" do before { adapter.instance_variable_set(:@template, nil) } it "sets the adapter's context_for_eval to the controller" do expect(adapter.context_for_eval).to be controller end end end context "when the adapter's controller is not set" do before { adapter.instance_variable_set(:@controller, nil) } context "and the adapter's template is set" do before { adapter.instance_variable_set(:@template, template) } it "sets the adapter's context_for_eval to the template" do expect(adapter.context_for_eval).to be template end end context "and the adapter's template is not set" do before { adapter.instance_variable_set(:@template, nil) } it 'raises an exception' do expect{ adapter.context_for_eval }.to raise_error end end end end describe '#current_page?' do context "when the adapter's template is set" do before { allow(adapter).to receive_messages(template: template) } it 'delegates the call to the template' do expect(template).to receive(:current_page?).with(:page) adapter.current_page?(:page) end end context "when the adapter's template is not set" do before { allow(adapter).to receive_messages(template: nil) } it 'returns false' do expect(adapter.current_page?(:page)).to be_falsey end end context 'when the given url is nil' do it 'returns false' do expect(adapter.current_page?(nil)).to be_falsey end end end describe '#link_to' do let(:options) { double(:options) } context "when the adapter's template is set" do before { allow(adapter).to receive_messages(template: template, html_safe: 'safe_text') } context 'with considering item names as safe' do before { SimpleNavigation.config.consider_item_names_as_safe = true } after { SimpleNavigation.config.consider_item_names_as_safe = false } it 'delegates the call to the template (with html_safe text)' do expect(template).to receive(:link_to) .with('safe_text', 'url', options) adapter.link_to('text', 'url', options) end end context 'with considering item names as UNsafe (default)' do it 'delegates the call to the template (with html_safe text)' do expect(template).to receive(:link_to) .with('text', 'url', options) adapter.link_to('text', 'url', options) end end end context "when the adapter's template is not set" do before { allow(adapter).to receive_messages(template: nil) } it 'returns nil' do expect(adapter.link_to('text', 'url', options)).to be_nil end end end describe '#content_tag' do let(:options) { double(:options) } context "when the adapter's template is set" do before { allow(adapter).to receive_messages(template: template, html_safe: 'safe_text') } it 'delegates the call to the template (with html_safe text)' do expect(template).to receive(:content_tag) .with(:div, 'safe_text', options) adapter.content_tag(:div, 'text', options) end end context "when the adapter's template is not set" do before { allow(adapter).to receive_messages(template: nil) } it 'returns nil' do expect(adapter.content_tag(:div, 'text', options)).to be_nil end end end end end end simple-navigation-4.0.3/spec/simple_navigation/adapters/padrino_spec.rb0000644000004100000410000000162312513767261026450 0ustar www-datawww-datamodule SimpleNavigation module Adapters describe Padrino do let(:adapter) { SimpleNavigation::Adapters::Padrino.new(context) } let(:content) { double(:content) } let(:context) { double(:context, request: request) } let(:request) { double(:request) } describe '#link_to' do it 'delegates to context' do expect(context).to receive(:link_to) .with('name', 'url', :my_option => true) adapter.link_to('name', 'url', :my_option => true) end end describe '#content_tag' do it 'delegates to context' do expect(content).to receive(:html_safe).and_return('content') expect(context).to receive(:content_tag) .with('type', 'content', my_option: true) adapter.content_tag('type', content, my_option: true) end end end end end simple-navigation-4.0.3/spec/simple_navigation/adapters/sinatra_spec.rb0000644000004100000410000000717612513767261026466 0ustar www-datawww-datadescribe SimpleNavigation::Adapters::Sinatra do let(:adapter) { SimpleNavigation::Adapters::Sinatra.new(context) } let(:context) { double(:context) } let(:request) { double(:request, fullpath: '/full?param=true', path: '/full') } before { allow(context).to receive_messages(request: request) } describe '#context_for_eval' do context "when adapter's context is not set" do it 'raises an exception' do allow(adapter).to receive_messages(context: nil) expect{ adapter.context_for_eval }.to raise_error end end context "when adapter's context is set" do it 'returns the context' do expect(adapter.context_for_eval).to be context end end end describe '#request_uri' do it 'returns the request.fullpath' do expect(adapter.request_uri).to eq '/full?param=true' end end describe '#request_path' do it 'returns the request.path' do expect(adapter.request_path).to eq '/full' end end describe '#current_page?' do before { allow(request).to receive_messages(scheme: 'http', host_with_port: 'my_host:5000') } shared_examples 'detecting current page' do |url, expected| context "when url is #{url}" do it "returns #{expected}" do expect(adapter.current_page?(url)).to be expected end end end context 'when URL is not encoded' do it_behaves_like 'detecting current page', '/full?param=true', true it_behaves_like 'detecting current page', '/full?param3=true', false it_behaves_like 'detecting current page', '/full', true it_behaves_like 'detecting current page', 'http://my_host:5000/full?param=true', true it_behaves_like 'detecting current page', 'http://my_host:5000/full?param3=true', false it_behaves_like 'detecting current page', 'http://my_host:5000/full', true it_behaves_like 'detecting current page', 'https://my_host:5000/full', false it_behaves_like 'detecting current page', 'http://my_host:6000/full', false it_behaves_like 'detecting current page', 'http://my_other_host:5000/full', false end context 'when URL is encoded' do before do allow(request).to receive_messages(fullpath: '/full%20with%20spaces?param=true', path: '/full%20with%20spaces') end it_behaves_like 'detecting current page', '/full%20with%20spaces?param=true', true it_behaves_like 'detecting current page', '/full%20with%20spaces?param3=true', false it_behaves_like 'detecting current page', '/full%20with%20spaces', true it_behaves_like 'detecting current page', 'http://my_host:5000/full%20with%20spaces?param=true', true it_behaves_like 'detecting current page', 'http://my_host:5000/full%20with%20spaces?param3=true', false it_behaves_like 'detecting current page', 'http://my_host:5000/full%20with%20spaces', true it_behaves_like 'detecting current page', 'https://my_host:5000/full%20with%20spaces', false it_behaves_like 'detecting current page', 'http://my_host:6000/full%20with%20spaces', false it_behaves_like 'detecting current page', 'http://my_other_host:5000/full%20with%20spaces', false end end describe '#link_to' do it 'returns a link with the correct class and id' do link = adapter.link_to('link', 'url', class: 'clazz', id: 'id') expect(link).to eq "link" end end describe '#content_tag' do it 'returns a tag with the correct class and id' do tag = adapter.content_tag(:div, 'content', class: 'clazz', id: 'id') expect(tag).to eq "
content
" end end end simple-navigation-4.0.3/spec/simple_navigation/items_provider_spec.rb0000644000004100000410000000234112513767261026242 0ustar www-datawww-datamodule SimpleNavigation describe ItemsProvider do let(:items_provider) { ItemsProvider.new(provider) } describe '#items' do let(:items) { double(:items) } context 'when provider is a symbol' do let(:context) { double(:context, provider_method: items) } let(:provider) { :provider_method } before { allow(SimpleNavigation).to receive_messages(context_for_eval: context) } it 'retrieves the items from the evaluation context' do expect(items_provider.items).to eq items end end context 'when provider responds to :items' do let(:provider) { double(:provider, items: items) } it 'retrieves the items from the provider object' do expect(items_provider.items).to eq items end end context 'provider is a collection' do let(:provider) { [] } it 'retrieves the items by returning the provider' do expect(items_provider.items).to eq provider end end context 'when provider is something else' do let(:provider) { double(:provider) } it 'raises an exception' do expect{ items_provider.items }.to raise_error end end end end end simple-navigation-4.0.3/spec/simple_navigation/config_file_spec.rb0000644000004100000410000000117412513767261025456 0ustar www-datawww-datarequire 'simple_navigation/config_file' module SimpleNavigation describe ConfigFile do subject(:config_file) { ConfigFile.new(context) } let(:context) { :default } describe '#name' do context 'when the context is :default' do it 'returns navigation.rb' do expect(config_file.name).to eq 'navigation.rb' end end context 'when the context is different from :default' do let(:context) { :HelloWorld } it 'returns UNDERSCORED_CONTEXT_navigation.rb' do expect(config_file.name).to eq 'hello_world_navigation.rb' end end end end end simple-navigation-4.0.3/spec/simple_navigation/item_adapter_spec.rb0000644000004100000410000001242112513767261025645 0ustar www-datawww-datamodule SimpleNavigation describe ItemAdapter do let(:item_adapter) { ItemAdapter.new(item) } context 'when item is an object' do let(:item) { double(:item, key: 'key', name: 'name', url: 'url') } shared_examples 'delegating to item' do |meth| it "delegates #{meth} to item" do expect(item).to receive(meth) item_adapter.public_send(meth) end end it_behaves_like 'delegating to item', :key it_behaves_like 'delegating to item', :url it_behaves_like 'delegating to item', :name describe '#initialize' do it 'sets the item' do expect(item_adapter.item).to be item end end describe '#options' do context 'when item responds to options' do let(:options) { double(:options) } before { allow(item).to receive_messages(options: options) } it "returns the item's options" do expect(item_adapter.options).to be options end end context 'item does not respond to options' do it 'returns an empty hash' do expect(item_adapter.options).to eq({}) end end end describe '#items' do context 'when item responds to items' do context 'and items is nil' do before { allow(item).to receive_messages(items: nil) } it 'returns nil' do expect(item_adapter.items).to be_nil end end context 'when items is not nil' do context 'and items is empty' do before { allow(item).to receive_messages(items: []) } it 'returns nil' do expect(item_adapter.items).to be_nil end end context 'and items is not empty' do let(:items) { [true] } before { allow(item).to receive_messages(items: items) } it 'returns the items' do expect(item_adapter.items).to eq items end end end end context "when item doesn't respond to items" do it 'returns nil' do expect(item_adapter.items).to be_nil end end end describe '#to_simple_navigation_item' do let(:container) { double(:container) } before { allow(item).to receive_messages(items: [], options: {}) } it 'creates an Item' do expect(Item).to receive(:new) .with(container, 'key', 'name', 'url', {}) item_adapter.to_simple_navigation_item(container) end end end context 'when item is a kind of hash' do class ModifiedHash < Hash; end let(:item) { ModifiedHash[key: 'key', url: 'url', name: 'name'] } shared_examples 'delegating to item' do |meth| it "delegates #{meth} to item" do expect(item_adapter.item).to receive(meth) item_adapter.public_send(meth) end end it_behaves_like 'delegating to item', :key it_behaves_like 'delegating to item', :url it_behaves_like 'delegating to item', :name describe '#initialize' do it 'sets the item' do expect(item_adapter.item).not_to be_nil end it 'converts the item into an object' do expect(item_adapter.item).to respond_to(:url) end end describe '#options' do context 'when item responds to options' do before { item[:options] = { my: :options } } it "returns the item's options" do expect(item_adapter.options).to eq({ my: :options }) end end context 'when item does not respond to options' do it 'returns an empty hash' do expect(item_adapter.options).to eq({}) end end end describe '#items' do context 'when item responds to items' do context 'and items is nil' do before { item[:items] = nil } it 'returns nil' do expect(item_adapter.items).to be_nil end end context 'when items is not nil' do context 'and items is empty' do it 'returns nil' do expect(item_adapter.items).to be_nil end end context 'and items is not empty' do before { item[:items] = ['not', 'empty'] } it 'returns the items' do expect(item_adapter.items).to eq ['not', 'empty'] end end end end context 'when item does not respond to items' do it 'returns nil' do expect(item_adapter.items).to be_nil end end end describe '#to_simple_navigation_item' do let(:container) { double(:container) } before { item.merge(options: {}) } it 'passes the right arguments to Item' do expect(Item).to receive(:new) .with(container, 'key', 'name', 'url', {}) item_adapter.to_simple_navigation_item(container) end it 'creates an Item' do created_item = item_adapter.to_simple_navigation_item(container) expect(created_item).to be_an(Item) end end end end end simple-navigation-4.0.3/spec/simple_navigation/configuration_spec.rb0000644000004100000410000001240712513767261026062 0ustar www-datawww-datamodule SimpleNavigation describe Configuration do subject(:config) { Configuration.instance } describe '.run' do it "yields the singleton Configuration object" do expect{ |blk| Configuration.run(&blk) }.to yield_with_args(config) end end describe '.eval_config' do let(:config_files) {{ default: 'default', my_context: 'my_context' }} let(:eval_context) { double(:eval_context) } before do allow(eval_context).to receive(:instance_eval) allow(SimpleNavigation).to \ receive_messages(context_for_eval: eval_context, config_files: config_files) end context "with default navigation context" do it "calls instance_eval with the default config_file-string inside the context" do expect(eval_context).to receive(:instance_eval).with('default') Configuration.eval_config end end context 'with non default navigation context' do it "calls instance_eval with the specified config_file-string inside the context" do expect(eval_context).to receive(:instance_eval).with('my_context') Configuration.eval_config(:my_context) end end end describe '#initialize' do it 'sets the List-Renderer as default' do expect(config.renderer).to be Renderer::List end it 'sets the selected_class to "selected" as default' do expect(config.selected_class).to eq 'selected' end it 'sets the active_leaf_class to "simple-navigation-active-leaf" as default' do expect(config.active_leaf_class).to eq 'simple-navigation-active-leaf' end it 'sets autogenerate_item_ids to true as default' do expect(config.autogenerate_item_ids).to be true end it 'sets auto_highlight to true as default' do expect(config.auto_highlight).to be true end it 'sets the id_generator to a callable object' do expect(config.id_generator).to respond_to(:call) end it 'sets the name_generator to a callable object' do expect(config.name_generator).to respond_to(:call) end it 'sets the consider_item_names_as_safe to false' do expect(config.consider_item_names_as_safe).to be false end it 'sets highlights_on_subpath to false as default' do expect(config.highlight_on_subpath).to be false end it 'sets ignore_query_params_on_auto_highlight to true as default' do expect(config.ignore_query_params_on_auto_highlight).to be true end it 'sets ignore_anchors_on_auto_highlight to true as default' do expect(config.ignore_anchors_on_auto_highlight).to be true end end describe '#items' do let(:container) { double(:items_container) } before { allow(ItemContainer).to receive_messages(new: container) } context 'when a block is given' do context 'and items_provider is specified' do let(:provider) { double(:provider) } it 'raises an exception' do expect{ config.items(provider) {} }.to raise_error end end context 'when no items_provider is specified' do it 'yields an new ItemContainer' do expect{ |blk| config.items(&blk) }.to yield_with_args(container) end it 'assigns the ItemContainer to an instance-var' do config.items {} expect(config.primary_navigation).to be container end it "doesn't set the items on the container" do expect(container).not_to receive(:items=) config.items {} end end end context 'when no block is given' do context 'and items_provider is specified' do let(:external_provider) { double(:external_provider) } let(:items) { double(:items) } let(:items_provider) { double(:items_provider, items: items) } before do allow(SimpleNavigation::ItemsProvider).to receive_messages(new: items_provider) allow(container).to receive(:items=) end it 'creates a new Provider object for the specified provider' do expect(ItemsProvider).to receive(:new).with(external_provider) config.items(external_provider) end it 'calls items on the provider object' do expect(items_provider).to receive(:items) config.items(external_provider) end it 'sets the items on the container' do expect(container).to receive(:items=).with(items) config.items(external_provider) end end context 'when items_provider is not specified' do it "raises an exception" do expect{ config.items }.to raise_error end end end end describe '#loaded?' do context 'when primary_nav is set' do it 'returns true' do config.instance_variable_set(:@primary_navigation, :bla) expect(config).to be_loaded end end context 'when primary_nav is not set' do it 'returns false if no primary_nav is set' do config.instance_variable_set(:@primary_navigation, nil) expect(config).not_to be_loaded end end end end end simple-navigation-4.0.3/spec/simple_navigation/helpers_spec.rb0000644000004100000410000003421412513767261024655 0ustar www-datawww-datamodule SimpleNavigation describe Helpers do subject(:controller) { test_controller_class.new } let(:invoices_item) { navigation[:invoices] } let(:item) { nil } let(:navigation) { setup_navigation('nav_id', 'nav_class') } let(:test_controller_class) do Class.new { include SimpleNavigation::Helpers } end let(:unpaid_item) { invoices_item.sub_navigation[:unpaid] } before do allow(Configuration).to receive(:eval_config) allow(SimpleNavigation).to receive_messages(load_config: nil, primary_navigation: navigation, config_file?: true, context_for_eval: controller) select_an_item(navigation[item]) if item end describe '#active_navigation_item_name' do context 'when no item is selected' do it 'returns an empty string for no parameters' do expect(controller.active_navigation_item_name).to eq '' end it "returns an empty string for level: 1" do item_name = controller.active_navigation_item_name(level: 1) expect(item_name).to eq '' end it 'returns an empty string for level: 2' do item_name = controller.active_navigation_item_name(level: 2) expect(item_name).to eq '' end it 'returns an empty string for level: :all' do item_name = controller.active_navigation_item_name(level: :all) expect(item_name).to eq '' end end context 'when an item is selected' do context "and it's a primary item" do let(:item) { :invoices } it 'returns an empty string' do expect(controller.active_navigation_item_name).to eq '' end it "returns the selected item's name for level: 1" do item_name = controller.active_navigation_item_name(level: 1) expect(item_name).to eq 'Invoices' end it 'returns an empty string for level: 2' do item_name = controller.active_navigation_item_name(level: 2) expect(item_name).to eq '' end it 'returns an empty string for level: :all' do item_name = controller.active_navigation_item_name(level: :all) expect(item_name).to eq '' end end context "and it's a sub navigation item" do before do select_an_item(invoices_item) select_an_item(unpaid_item) end it "returns the selected item's name" do expect(controller.active_navigation_item_name).to eq 'Unpaid' end it "returns the selected item's parent name for level: 1" do item_name = controller.active_navigation_item_name(level: 1) expect(item_name).to eq 'Invoices' end it "returns the selected item's name for level: 2" do item_name = controller.active_navigation_item_name(level: 2) expect(item_name).to eq 'Unpaid' end it "returns the selected item's name for level: :all" do item_name = controller.active_navigation_item_name(level: :all) expect(item_name).to eq 'Unpaid' end end end end describe '#active_navigation_item_key' do context 'when no item is selected' do it 'returns nil' do expect(controller.active_navigation_item_key).to be_nil end it 'returns nil for no parameters' do expect(controller.active_navigation_item_key).to be_nil end it "returns nil for level: 1" do item_key = controller.active_navigation_item_key(level: 1) expect(item_key).to be_nil end it 'returns nil for level: 2' do item_key = controller.active_navigation_item_key(level: 2) expect(item_key).to be_nil end it 'returns nil for level: :all' do item_key = controller.active_navigation_item_key(level: :all) expect(item_key).to be_nil end end context 'when an item is selected' do context "and it's a primary item" do let(:item) { :invoices } it 'returns nil for no parameters' do expect(controller.active_navigation_item_key).to be_nil end it "returns the selected item's name for level: 1" do item_key = controller.active_navigation_item_key(level: 1) expect(item_key).to eq :invoices end it 'returns nil for level: 2' do item_key = controller.active_navigation_item_key(level: 2) expect(item_key).to be_nil end it 'returns nil for level: :all' do item_key = controller.active_navigation_item_key(level: :all) expect(item_key).to be_nil end end context "and it's a sub navigation item" do before do select_an_item(invoices_item) select_an_item(unpaid_item) end it "returns the selected item's name" do expect(controller.active_navigation_item_key).to eq :unpaid end it "returns the selected item's parent name for level: 1" do item_key = controller.active_navigation_item_key(level: 1) expect(item_key).to eq :invoices end it "returns the selected item's name for level: 2" do item_key = controller.active_navigation_item_key(level: 2) expect(item_key).to eq :unpaid end it "returns the selected item's name for level: :all" do item_key = controller.active_navigation_item_key(level: :all) expect(item_key).to eq :unpaid end end end end describe '#active_navigation_item' do context 'when no item is selected' do it 'returns nil for no parameters' do expect(controller.active_navigation_item).to be_nil end it "returns nil for level: 1" do item_key = controller.active_navigation_item(level: 1) expect(item_key).to be_nil end it 'returns nil for level: 2' do item_key = controller.active_navigation_item(level: 2) expect(item_key).to be_nil end it 'returns nil for level: :all' do item_key = controller.active_navigation_item(level: :all) expect(item_key).to be_nil end end context 'when an item is selected' do context "and it's a primary item" do let(:item) { :invoices } it 'returns nil for no parameters' do expect(controller.active_navigation_item).to be_nil end it "returns the selected item's name for level: 1" do item_key = controller.active_navigation_item(level: 1) expect(item_key).to be invoices_item end it 'returns nil for level: 2' do item_key = controller.active_navigation_item(level: 2) expect(item_key).to be_nil end it 'returns nil for level: :all' do item_key = controller.active_navigation_item(level: :all) expect(item_key).to be_nil end end context "and it's a sub navigation item" do before do select_an_item(invoices_item) select_an_item(unpaid_item) end it "returns the selected item's name for no parameters" do expect(controller.active_navigation_item).to be unpaid_item end it "returns the selected item's parent name for level: 1" do item_key = controller.active_navigation_item(level: 1) expect(item_key).to be invoices_item end it "returns the selected item's name for level: 2" do item_key = controller.active_navigation_item(level: 2) expect(item_key).to eq unpaid_item end it "returns the selected item's name for level: :all" do item_key = controller.active_navigation_item(level: :all) expect(item_key).to eq unpaid_item end end end end describe '#active_navigation_item_container' do shared_examples 'returning items container' do it 'returns the primary navigation for no parameters' do expect(controller.active_navigation_item_container).to be navigation end it "returns the primary navigation for level: 1" do item_container = controller.active_navigation_item_container(level: 1) expect(item_container).to be navigation end it 'returns the primary navigation level: :all' do item_container = controller.active_navigation_item_container(level: :all) expect(item_container).to be navigation end end context 'when no item is selected' do it_behaves_like 'returning items container' it 'returns nil for level: 2' do item_container = controller.active_navigation_item_container(level: 2) expect(item_container).to be_nil end end context 'when an item is selected' do context "and it's a primary item" do let(:item) { :invoices } it_behaves_like 'returning items container' it 'returns the invoices items container for level: 2' do item_container = controller.active_navigation_item_container(level: 2) expect(item_container).to be invoices_item.sub_navigation end end context "and it's a sub navigation item" do before do select_an_item(invoices_item) select_an_item(unpaid_item) end it_behaves_like 'returning items container' it 'returns the invoices items container for level: 2' do item_container = controller.active_navigation_item_container(level: 2) expect(item_container).to be invoices_item.sub_navigation end end end end describe '#render_navigation' do it 'evaluates the configuration on every request' do expect(SimpleNavigation).to receive(:load_config).twice 2.times { controller.render_navigation } end it 'loads the :default configuration' do expect(SimpleNavigation).to receive(:load_config).with(:default) controller.render_navigation end it "doesn't set the items directly" do expect(SimpleNavigation.config).not_to receive(:items) controller.render_navigation end it 'looks up the active_item_container based on the level' do expect(SimpleNavigation).to receive(:active_item_container_for) .with(:all) controller.render_navigation end context 'when the :context option is specified' do it 'loads the configuration for the specified context' do expect(SimpleNavigation).to receive(:load_config).with(:my_context) controller.render_navigation(context: :my_context) end end context 'when the :items option is specified' do let(:items) { double(:items) } it 'sets the items directly' do expect(SimpleNavigation.config).to receive(:items).with(items) controller.render_navigation(items: items) end end context 'when the :level option is set' do context 'and its value is 1' do it 'calls render on the primary navigation' do expect(navigation).to receive(:render).with(level: 1) controller.render_navigation(level: 1) end end context 'and its value is 2' do context 'and the active_item_container is set' do let(:item_container) { double(:container).as_null_object } before do allow(SimpleNavigation).to receive_messages(active_item_container_for: item_container) end it 'finds the selected sub navigation for the specified level' do expect(SimpleNavigation).to receive(:active_item_container_for) .with(2) controller.render_navigation(level: 2) end it 'calls render on the active item_container' do expect(item_container).to receive(:render).with(level: 2) controller.render_navigation(level: 2) end end context "and the active_item_container isn't set" do it "doesn't raise an exception" do expect{ controller.render_navigation(level: 2) }.not_to raise_error end end end context "and its value isn't a valid level" do it 'raises an exception' do expect{ controller.render_navigation(level: :invalid) }.to raise_error end end end context 'when the :levels option is set' do before { allow(SimpleNavigation).to receive_messages(active_item_container_for: navigation) } it 'treats it like the :level option' do expect(navigation).to receive(:render).with(level: 2) controller.render_navigation(levels: 2) end end context 'when a block is given' do it 'calls the block passing it an item container' do expect{ |blk| controller.render_navigation(&blk) }.to yield_with_args(ItemContainer) end end context 'when no primary configuration is defined' do before { allow(SimpleNavigation).to receive_messages(primary_navigation: nil) } it 'raises an exception' do expect{controller.render_navigation}.to raise_error end end context "when active_item_container is set" do let(:active_item_container) { double(:container).as_null_object } before do allow(SimpleNavigation).to receive_messages(active_item_container_for: active_item_container) end it 'calls render on the active_item_container' do expect(active_item_container).to receive(:render) controller.render_navigation end end end end end simple-navigation-4.0.3/spec/simple_navigation/config_file_finder_spec.rb0000644000004100000410000000270112513767261027002 0ustar www-datawww-datarequire 'fileutils' require 'simple_navigation/config_file_finder' module SimpleNavigation describe ConfigFileFinder do subject(:finder) { ConfigFileFinder.new(paths) } let(:paths) { ['/path/one', '/path/two'] } describe '#find', memfs: true do before { FileUtils.mkdir_p(paths) } context 'when the context is :default' do let(:context) { :default } context 'and a navigation.rb file is found in one of the paths' do before { FileUtils.touch('/path/one/navigation.rb') } it 'returns its full path' do expect(finder.find(context)).to eq '/path/one/navigation.rb' end end context 'and no navigation.rb file is found in the paths' do it 'raises an exception' do expect{ finder.find(context) }.to raise_error end end end context 'when the context is :other' do let(:context) { :other } context 'and a other_navigation.rb file is found in one of the paths' do before { FileUtils.touch('/path/two/other_navigation.rb') } it 'returns its full path' do expect(finder.find(context)).to eq '/path/two/other_navigation.rb' end end context 'and no other_navigation.rb file is found in the paths' do it 'raise an exception' do expect{ finder.find(context) }.to raise_error end end end end end end simple-navigation-4.0.3/spec/simple_navigation/item_spec.rb0000644000004100000410000003432712513767261024156 0ustar www-datawww-datamodule SimpleNavigation describe Item do let!(:item_container) { ItemContainer.new } let(:adapter) { double(:adapter) } let(:item_args) { [item_container, :my_key, 'name', url, options] } let(:item) { Item.new(*item_args) } let(:options) { Hash.new } let(:url) { 'url' } before { allow(SimpleNavigation).to receive_messages(adapter: adapter) } describe '#highlights_on' do let(:options) {{ highlights_on: :test }} it "returns the item's highlights_on option" do expect(item.highlights_on).to eq :test end end describe '#initialize' do context 'when there is a sub_navigation' do let(:subnav_container) { double(:subnav_container).as_null_object } shared_examples 'creating sub navigation container' do it 'creates a sub navigation container with a level+1' do expect(item.sub_navigation.level).to eq 2 end end context 'when a block is given' do it_behaves_like 'creating sub navigation container' do let(:item) { Item.new(*item_args) {} } end it 'calls the block' do allow(ItemContainer).to receive_messages(new: subnav_container) expect{ |blk| Item.new(*item_args, &blk) }.to yield_with_args(subnav_container) end end context 'when no block is given' do context 'and items are given' do let(:items) { [] } let(:options) {{ items: items }} it_behaves_like 'creating sub navigation container' it "sets the items on the subnav_container" do expect(item.sub_navigation.items).to eq items end end context 'and no items are given' do it "doesn't create a new ItemContainer" do item = Item.new(*item_args) expect(item.sub_navigation).to be_nil end end end end context 'when a :method option is given' do let(:options) {{ method: :delete }} it "sets the item's method" do expect(item.method).to eq :delete end end context 'when no :method option is given' do it "sets the item's method to nil" do expect(item.method).to be_nil end end context 'when an :highlights_on option is given' do let(:highlights_on) { double(:highlights_on) } let(:options) {{ highlights_on: highlights_on }} it "sets the item's highlights_on" do expect(item.highlights_on).to eq highlights_on end end context 'when no :highlights_on option is given' do it "sets the item's highlights_on to nil" do expect(item.highlights_on).to be_nil end end context 'when a url is given' do context 'and it is a string' do it "sets the item's url accordingly" do expect(item.url).to eq 'url' end end context 'and it is a proc' do let(:url) { proc{ "my_" + "url" } } it "sets the item's url accordingly" do expect(item.url).to eq 'my_url' end end context 'and it is nil' do let(:url) { nil } it "sets the item's url accordingly" do expect(item.url).to be_nil end end end context 'when no url nor options is specified' do let(:item_args) { [item_container, :my_key, 'name'] } it "sets the item's url to nil" do expect(item.url).to be_nil end end context 'when only a url is given' do let(:item_args) { [item_container, :my_key, 'name', 'url'] } it "set the item's url accordingly" do expect(item.url).to eq 'url' end end context 'when url and options are given' do let(:options) {{ html: { option: true } }} before { allow(adapter).to receive_messages(current_page?: false) } it "set the item's url accordingly" do expect(item.url).to eq 'url' end it "sets the item's html_options accordingly" do allow(item).to \ receive_messages(selected_by_subnav?: false, selected_by_condition?: false) expect(item.html_options).to include(option: true) end end end describe '#link_html_options' do let(:options) {{ link_html: :test }} it "returns the item's link_html option" do expect(item.link_html_options).to eq :test end end describe '#method' do let(:options) {{ method: :test }} it "returns the item's method option" do expect(item.method).to eq :test end end describe '#name' do before do allow(SimpleNavigation.config).to \ receive_messages(name_generator: proc{ |name| "#{name}" }) end context 'when no option is given' do context 'and the name_generator uses only the name' do it 'uses the default name_generator' do expect(item.name).to eq 'name' end end context 'and the name_generator uses only the item itself' do before do allow(SimpleNavigation.config).to \ receive_messages(name_generator: proc{ |name, item| "#{item.key}" }) end it 'uses the default name_generator' do expect(item.name).to eq 'my_key' end end end context 'when the :apply_generator is false' do it "returns the item's name" do expect(item.name(apply_generator: false)).to eq 'name' end end context 'when a block is given' do let(:item_args) { [item_container, :my_key, -> { 'Name in block' }, url, options] } it "returns the item's name that is defined in the block" do expect(item.name).to include 'Name in block' end end end describe '#selected?' do context 'when the item has no :highlights_on option' do before { allow(SimpleNavigation).to receive_messages(config: config) } context 'and auto highlighting is off' do let(:config) { double(:config, auto_highlight: false) } it 'returns false' do expect(item.selected?).to be false end end context 'and auto highlighting is on' do let(:config) { double(:config, ignore_query_params_on_auto_highlight: true, ignore_anchors_on_auto_highlight: true, auto_highlight: true) } context "and the current url matches the item's url" do before { allow(adapter).to receive_messages(current_page?: true) } it 'returns true' do expect(item.selected?).to be true end end context "and the current url does not match the item's url" do let(:config) do double(:config, auto_highlight: false, highlight_on_subpath: false) end before { allow(adapter).to receive_messages(current_page?: false) } it 'returns false' do expect(item.selected?).to be false end end context 'and highlights_on_subpath is on' do let(:config) do double(:config, auto_highlight: true, highlight_on_subpath: true, ignore_query_params_on_auto_highlight: true, ignore_anchors_on_auto_highlight: true) end context "and the current url is a sub path of the item's url" do before do allow(adapter).to \ receive_messages(current_page?: false, request_uri: 'url/test') end it 'returns true' do expect(item.selected?).to be true end end context "and the current url is not a sub path of the item's url" do before do allow(adapter).to \ receive_messages(current_page?: false, request_uri: 'other/test') end it 'returns false' do expect(item.selected?).to be false end end end end end context 'when the item has a :highlights_on option' do context 'and it is a regular expression' do before { allow(adapter).to receive_messages(request_uri: '/test') } context 'and the current url matches the expression' do let(:options) {{ highlights_on: /test/ }} it 'returns true' do expect(item.selected?).to be true end end context 'and the current url does not match the expression' do let(:options) {{ highlights_on: /other/ }} it 'returns false' do expect(item.selected?).to be false end end end context 'and it is a callable object' do context 'and the call returns true' do let(:options) {{ highlights_on: -> { true } }} it 'returns true' do expect(item.selected?).to be true end end context 'and the call returns false' do let(:options) {{ highlights_on: -> { false } }} it 'returns false' do expect(item.selected?).to be false end end end context 'and it is the :subpath symbol' do let(:options) {{ highlights_on: :subpath }} context "and the current url is a sub path of the item's url" do before do allow(adapter).to receive_messages(request_uri: 'url/test') end it 'returns true' do expect(item.selected?).to be true end end context "and the current url is not a sub path of the item's url" do before do allow(adapter).to receive_messages(request_uri: 'other/test') end it 'returns false' do expect(item.selected?).to be false end end end context 'and it is non usable' do let(:options) {{ highlights_on: :hello }} it 'raises an exception' do expect{ item.selected? }.to raise_error end end end end describe '#selected_class' do context 'when the item is selected' do before { allow(item).to receive_messages(selected?: true) } it 'returns the default selected_class' do expect(item.selected_class).to eq 'selected' end context 'and selected_class is defined in the context' do before { allow(item_container).to receive_messages(selected_class: 'defined') } it "returns the context's selected_class" do expect(item.selected_class).to eq 'defined' end end end context 'when the item is not selected' do before { allow(item).to receive_messages(selected?: false) } it 'returns nil' do expect(item.selected_class).to be_nil end end end describe ':html_options argument' do let(:selected_classes) { 'selected simple-navigation-active-leaf' } context 'when the :class option is given' do let(:options) {{ html: { class: 'my_class' } }} context 'and the item is selected' do before { allow(item).to receive_messages(selected?: true, selected_by_condition?: true) } it "adds the specified class to the item's html classes" do expect(item.html_options[:class]).to include('my_class') end it "doesn't replace the default html classes of a selected item" do expect(item.html_options[:class]).to include(selected_classes) end end context "and the item isn't selected" do before { allow(item).to receive_messages(selected?: false, selected_by_condition?: false) } it "sets the specified class as the item's html classes" do expect(item.html_options[:class]).to include('my_class') end end end context "when the :class option isn't given" do context 'and the item is selected' do before { allow(item).to receive_messages(selected?: true, selected_by_condition?: true) } it "sets the default html classes of a selected item" do expect(item.html_options[:class]).to include(selected_classes) end end context "and the item isn't selected" do before { allow(item).to receive_messages(selected?: false, selected_by_condition?: false) } it "doesn't set any html class on the item" do expect(item.html_options[:class]).to be_blank end end end shared_examples 'generating id' do |id| it "sets the item's html id to the specified id" do expect(item.html_options[:id]).to eq id end end describe 'when the :id option is given' do let(:options) {{ html: { id: 'my_id' } }} before do allow(SimpleNavigation.config).to receive_messages(autogenerate_item_ids: generate_ids) allow(item).to receive_messages(selected?: false, selected_by_condition?: false) end context 'and :autogenerate_item_ids is true' do let(:generate_ids) { true } it_behaves_like 'generating id', 'my_id' end context 'and :autogenerate_item_ids is false' do let(:generate_ids) { false } it_behaves_like 'generating id', 'my_id' end end context "when the :id option isn't given" do before do allow(SimpleNavigation.config).to receive_messages(autogenerate_item_ids: generate_ids) allow(item).to receive_messages(selected?: false, selected_by_condition?: false) end context 'and :autogenerate_item_ids is true' do let(:generate_ids) { true } it_behaves_like 'generating id', 'my_key' end context 'and :autogenerate_item_ids is false' do let(:generate_ids) { false } it "doesn't set any html id on the item" do expect(item.html_options[:id]).to be_blank end end end end end end simple-navigation-4.0.3/spec/simple_navigation/item_container_spec.rb0000644000004100000410000004744412513767261026224 0ustar www-datawww-datamodule SimpleNavigation describe ItemContainer do subject(:item_container) { ItemContainer.new } shared_examples 'adding the item to the list' do it 'adds the item to the list' do allow(Item).to receive_messages(new: item) item_container.item(*args) expect(item_container.items).to include(item) end end shared_examples 'not adding the item to the list' do it "doesn't add the item to the list" do allow(Item).to receive_messages(new: item) item_container.item(*args) expect(item_container.items).not_to include(item) end end describe '#initialize' do it 'sets an empty items array' do expect(item_container.items).to be_empty end end describe '#dom_attributes' do let(:dom_attributes) {{ id: 'test_id', class: 'test_class' }} before { item_container.dom_attributes = dom_attributes } it "returns the container's dom_attributes" do expect(item_container.dom_attributes).to eq dom_attributes end context 'when the dom_attributes do not contain any id or class' do let(:dom_attributes) {{ test: 'test' }} context "and the container hasn't any dom_id" do it "returns the contaier's dom_attributes without any id" do expect(item_container.dom_attributes).not_to include(:id) end end context 'and the container has a dom_id' do before { item_container.dom_id = 'test_id' } it "returns the contaier's dom_attributes including the #dom_id" do expect(item_container.dom_attributes).to include(id: 'test_id') end end context "and the container hasn't any dom_class" do it "returns the contaier's dom_attributes without any class" do expect(item_container.dom_attributes).not_to include(:class) end end context 'and the container has a dom_class' do before { item_container.dom_class = 'test_class' } it "returns the contaier's dom_attributes including the #dom_class" do expect(item_container.dom_attributes).to include(class: 'test_class') end end end end describe '#items=' do let(:item) {{ key: :my_key, name: 'test', url: '/' }} let(:items) { [item] } let(:item_adapter) { double(:item_adapter).as_null_object } let(:real_item) { double(:real_item) } before do allow(ItemAdapter).to receive_messages(new: item_adapter) allow(item_adapter).to receive(:to_simple_navigation_item) .with(item_container) .and_return(real_item) end context 'when the item should be added' do before { allow(item_container).to receive_messages(should_add_item?: true) } it 'converts it to an Item and adds it to the items collection' do item_container.items = items expect(item_container.items).to include(real_item) end end context 'when the item should not be added' do before { allow(item_container).to receive_messages(should_add_item?: false) } it "doesn't add it to the items collection" do item_container.items = items expect(item_container.items).not_to include(real_item) end end end describe '#selected?' do let(:item_1) { double(:item, selected?: false) } let(:item_2) { double(:item, selected?: false) } before do item_container.instance_variable_set(:@items, [item_1, item_2]) end context 'when no item is selected' do it 'returns nil' do expect(item_container).not_to be_selected end end context 'when an item is selected' do it 'returns true' do allow(item_1).to receive_messages(selected?: true) expect(item_container).to be_selected end end end describe '#selected_item' do let(:item_1) { double(:item, selected?: false) } let(:item_2) { double(:item, selected?: false) } before(:each) do allow(SimpleNavigation).to receive_messages(current_navigation_for: :nav) allow(item_container).to receive_messages(:[] => nil) item_container.instance_variable_set(:@items, [item_1, item_2]) end context "when navigation isn't explicitely set" do context 'and no item is selected' do it 'returns nil' do expect(item_container.selected_item).to be_nil end end context 'and an item selected' do before { allow(item_1).to receive_messages(selected?: true) } it 'returns the selected item' do expect(item_container.selected_item).to be item_1 end end end end describe '#active_item_container_for' do context "when the desired level is the same as the container's" do it 'returns the container itself' do expect(item_container.active_item_container_for(1)).to be item_container end end context "when the desired level is different than the container's" do context 'and no subnavigation is selected' do before { allow(item_container).to receive_messages(selected_sub_navigation?: false) } it 'returns nil' do expect(item_container.active_item_container_for(2)).to be_nil end end context 'and a subnavigation is selected' do let(:sub_navigation) { double(:sub_navigation) } let(:selected_item) { double(:selected_item) } before do allow(item_container).to \ receive_messages(selected_sub_navigation?: true, selected_item: selected_item) allow(selected_item).to receive_messages(sub_navigation: sub_navigation) end it 'calls recursively on the sub_navigation' do expect(sub_navigation).to receive(:active_item_container_for) .with(2) item_container.active_item_container_for(2) end end end end describe '#active_leaf_container' do context 'when the current container has a selected subnavigation' do let(:sub_navigation) { double(:sub_navigation) } let(:selected_item) { double(:selected_item) } before do allow(item_container).to receive_messages(selected_sub_navigation?: true, selected_item: selected_item) allow(selected_item).to receive_messages(sub_navigation: sub_navigation) end it 'calls recursively on the sub_navigation' do expect(sub_navigation).to receive(:active_leaf_container) item_container.active_leaf_container end end context 'when the current container is the leaf already' do before { allow(item_container).to receive_messages(selected_sub_navigation?: false) } it 'returns itsself' do expect(item_container.active_leaf_container).to be item_container end end end describe '#item' do let(:options) { Hash.new } let(:item) { double(:item) } context 'when a block is given' do let(:block) { proc{} } let(:sub_container) { double(:sub_container) } it 'yields a new ItemContainer' do allow_any_instance_of(Item).to \ receive_messages(sub_navigation: sub_container) expect{ |blk| item_container.item('key', 'name', 'url', options, &blk) }.to yield_with_args(sub_container) end it "creates a new Item with the given params and block" do allow(Item).to receive(:new) .with(item_container, 'key', 'name', 'url', options, &block) .and_return(item) item_container.item('key', 'name', 'url', options, &block) expect(item_container.items).to include(item) end it 'adds the created item to the list of items' do item_container.item('key', 'name', 'url', options) {} expect(item_container.items).not_to include(item) end end context 'when no block is given' do it 'creates a new Item with the given params and no sub navigation' do allow(Item).to receive(:new) .with(item_container, 'key', 'name', 'url', options) .and_return(item) item_container.item('key', 'name', 'url', options) expect(item_container.items).to include(item) end it 'adds the created item to the list of items' do allow(Item).to receive_messages(new: item) item_container.item('key', 'name', 'url', options) {} expect(item_container.items).to include(item) end end describe 'Optional url and optional options' do context 'when item specifed without url or options' do it_behaves_like 'adding the item to the list' do let(:args) { ['key', 'name'] } end end context 'when item is specified with only a url' do it_behaves_like 'adding the item to the list' do let(:args) { ['key', 'name', 'url'] } end end context 'when item is specified with only options' do context 'and options do not contain any condition' do it_behaves_like 'adding the item to the list' do let(:args) { ['key', 'name', { option: true }] } end end context 'and options contains a negative condition' do it_behaves_like 'not adding the item to the list' do let(:args) { ['key', 'name', nil, { if: ->{ false }, option: true }] } end end context 'and options contains a positive condition' do it_behaves_like 'adding the item to the list' do let(:args) { ['key', 'name', nil, { if: ->{ true }, option: true }] } end end end context 'when item is specified with a url and options' do context 'and options do not contain any condition' do it_behaves_like 'adding the item to the list' do let(:args) { ['key', 'name', 'url', { option: true }] } end end context 'and options contains a negative condition' do it_behaves_like 'not adding the item to the list' do let(:args) { ['key', 'name', 'url', { if: ->{ false }, option: true }] } end end context 'and options contains a positive condition' do it_behaves_like 'adding the item to the list' do let(:args) { ['key', 'name', 'url', { if: ->{ true }, option: true }] } end end end context 'when a frozen options hash is given' do let(:options) do { html: { id: 'test' } }.freeze end it 'does not raise an exception' do expect{ item_container.item('key', 'name', 'url', options) }.not_to raise_error end end describe "container options" do before do allow(item_container).to receive_messages(should_add_item?: add_item) item_container.item :key, 'name', 'url', options end context 'when the container :id option is specified' do let(:options) {{ container: { id: 'c_id' } }} context 'and the item should be added' do let(:add_item) { true } it 'changes its dom_id' do expect(item_container.dom_id).to eq 'c_id' end end context "and the item shouldn't be added" do let(:add_item) { false } it "doesn't change its dom_id" do expect(item_container.dom_id).to be_nil end end end context 'when the container :class option is specified' do let(:options) {{ container: { class: 'c_class' } }} context 'and the item should be added' do let(:add_item) { true } it 'changes its dom_class' do expect(item_container.dom_class).to eq 'c_class' end end context "and the item shouldn't be added" do let(:add_item) { false } it "doesn't change its dom_class" do expect(item_container.dom_class).to be_nil end end end context 'when the container :attributes option is specified' do let(:options) {{ container: { attributes: { option: true } } }} context 'and the item should be added' do let(:add_item) { true } it 'changes its dom_attributes' do expect(item_container.dom_attributes).to eq(option: true) end end context "and the item shouldn't be added" do let(:add_item) { false } it "doesn't change its dom_attributes" do expect(item_container.dom_attributes).to eq({}) end end end context 'when the container :selected_class option is specified' do let(:options) {{ container: { selected_class: 'sel_class' } }} context 'and the item should be added' do let(:add_item) { true } it 'changes its selected_class' do expect(item_container.selected_class).to eq 'sel_class' end end context "and the item shouldn't be added" do let(:add_item) { false } it "doesn't change its selected_class" do expect(item_container.selected_class).to be_nil end end end end end describe 'Conditions' do context 'when an :if option is given' do let(:options) {{ if: proc{condition} }} let(:condition) { nil } context 'and it evals to true' do let(:condition) { true } it 'creates a new Item' do expect(Item).to receive(:new) item_container.item('key', 'name', 'url', options) end end context 'and it evals to false' do let(:condition) { false } it "doesn't create a new Item" do expect(Item).not_to receive(:new) item_container.item('key', 'name', 'url', options) end end context 'and it is not a proc or a method' do it 'raises an error' do expect{ item_container.item('key', 'name', 'url', { if: 'text' }) }.to raise_error end end end context 'when an :unless option is given' do let(:options) {{ unless: proc{condition} }} let(:condition) { nil } context 'and it evals to false' do let(:condition) { false } it 'creates a new Navigation-Item' do expect(Item).to receive(:new) item_container.item('key', 'name', 'url', options) end end context 'and it evals to true' do let(:condition) { true } it "doesn't create a new Navigation-Item" do expect(Item).not_to receive(:new) item_container.item('key', 'name', 'url', options) end end end end end describe '#[]' do before do item_container.item(:first, 'first', 'bla') item_container.item(:second, 'second', 'bla') item_container.item(:third, 'third', 'bla') end it 'returns the item with the specified navi_key' do expect(item_container[:second].name).to eq 'second' end context 'when no item exists for the specified navi_key' do it 'returns nil' do expect(item_container[:invalid]).to be_nil end end end describe '#render' do # TODO let(:renderer_instance) { double(:renderer).as_null_object } let(:renderer_class) { double(:renderer_class, new: renderer_instance) } context 'when renderer is specified as an option' do context 'and is specified as a class' do it 'instantiates the passed renderer_class with the options' do expect(renderer_class).to receive(:new) .with(renderer: renderer_class) item_container.render(renderer: renderer_class) end it 'calls render on the renderer and passes self' do expect(renderer_instance).to receive(:render).with(item_container) item_container.render(renderer: renderer_class) end end context 'and is specified as a symbol' do before do SimpleNavigation.registered_renderers = { my_renderer: renderer_class } end it "instantiates the passed renderer_class with the options" do expect(renderer_class).to receive(:new).with(renderer: :my_renderer) item_container.render(renderer: :my_renderer) end it 'calls render on the renderer and passes self' do expect(renderer_instance).to receive(:render).with(item_container) item_container.render(renderer: :my_renderer) end end end context 'when no renderer is specified' do let(:options) { Hash.new } before { allow(item_container).to receive_messages(renderer: renderer_class) } it "instantiates the container's renderer with the options" do expect(renderer_class).to receive(:new).with(options) item_container.render(options) end it 'calls render on the renderer and passes self' do expect(renderer_instance).to receive(:render).with(item_container) item_container.render(options) end end end describe '#renderer' do context 'when no renderer is set explicitly' do it 'returns globally-configured renderer' do expect(item_container.renderer).to be Configuration.instance.renderer end end context 'when a renderer is set explicitly' do let(:renderer) { double(:renderer) } before { item_container.renderer = renderer } it 'returns the specified renderer' do expect(item_container.renderer).to be renderer end end end describe '#level_for_item' do before(:each) do item_container.item(:p1, 'p1', 'p1') item_container.item(:p2, 'p2', 'p2') do |p2| p2.item(:s1, 's1', 's1') p2.item(:s2, 's2', 's2') do |s2| s2.item(:ss1, 'ss1', 'ss1') s2.item(:ss2, 'ss2', 'ss2') end p2.item(:s3, 's3', 's3') end item_container.item(:p3, 'p3', 'p3') end shared_examples 'returning the level of an item' do |item, level| specify{ expect(item_container.level_for_item(item)).to eq level } end it_behaves_like 'returning the level of an item', :p1, 1 it_behaves_like 'returning the level of an item', :p3, 1 it_behaves_like 'returning the level of an item', :s1, 2 it_behaves_like 'returning the level of an item', :ss1, 3 it_behaves_like 'returning the level of an item', :x, nil end describe '#empty?' do context 'when there are no items' do it 'returns true' do item_container.instance_variable_set(:@items, []) expect(item_container).to be_empty end end context 'when there are some items' do it 'returns false' do item_container.instance_variable_set(:@items, [double(:item)]) expect(item_container).not_to be_empty end end end end end simple-navigation-4.0.3/spec/fake_app/0000755000004100000410000000000012513767261017706 5ustar www-datawww-datasimple-navigation-4.0.3/spec/fake_app/config/0000755000004100000410000000000012513767261021153 5ustar www-datawww-datasimple-navigation-4.0.3/spec/fake_app/config/navigation.rb0000644000004100000410000000025612513767261023642 0ustar www-datawww-dataSimpleNavigation::Configuration.run do |navigation| navigation.items do |nav| nav.item :item_1, 'Item 1', '/item_1' nav.item :item_2, 'Item 2', '/item_2' end end simple-navigation-4.0.3/spec/fake_app/rails_app.rb0000644000004100000410000000143412513767261022207 0ustar www-datawww-dataENV['RAILS_ENV'] ||= 'test' require 'action_controller/railtie' require 'simple_navigation' module RailsApp class Application < Rails::Application config.active_support.deprecation = :log config.cache_classes = true config.eager_load = false config.root = __dir__ config.secret_token = 'x'*100 config.session_store :cookie_store, key: '_myapp_session' end class TestsController < ActionController::Base def base render inline: <<-END <%= render_navigation %> END end end end Rails.backtrace_cleaner.remove_silencers! RailsApp::Application.initialize! RailsApp::Application.routes.draw do get '/base_spec' => 'rails_app/tests#base' end simple-navigation-4.0.3/.travis.yml0000644000004100000410000000031012513767261017311 0ustar www-datawww-databefore_install: - gem install bundler rvm: - 2.0.0 - 2.1.5 - 2.2.1 gemfile: - gemfiles/rails-4-2-stable.gemfile - gemfiles/rails-4-1-stable.gemfile - gemfiles/rails-3-2-stable.gemfile simple-navigation-4.0.3/lib/0000755000004100000410000000000012513767261015754 5ustar www-datawww-datasimple-navigation-4.0.3/lib/simple_navigation.rb0000644000004100000410000001325512513767261022017 0ustar www-datawww-data# cherry picking active_support stuff require 'active_support/core_ext/array' require 'active_support/core_ext/hash' require 'active_support/core_ext/module/attribute_accessors' require 'simple_navigation/version' require 'simple_navigation/configuration' require 'simple_navigation/item_adapter' require 'simple_navigation/item' require 'simple_navigation/item_container' require 'simple_navigation/items_provider' require 'simple_navigation/renderer' require 'simple_navigation/adapters' require 'simple_navigation/config_file_finder' require 'simple_navigation/railtie' if defined?(::Rails) require 'forwardable' # A plugin for generating a simple navigation. See README for resources on # usage instructions. module SimpleNavigation mattr_accessor :adapter, :adapter_class, :config_files, :config_file_paths, :default_renderer, :environment, :registered_renderers, :root # Cache for loaded config files self.config_files = {} # Allows for multiple config_file_paths. Needed if a plugin itself uses # simple-navigation and therefore has its own config file self.config_file_paths = [] # Maps renderer keys to classes. The keys serve as shortcut in the # render_navigation calls (renderer: :list) self.registered_renderers = { list: SimpleNavigation::Renderer::List, links: SimpleNavigation::Renderer::Links, breadcrumbs: SimpleNavigation::Renderer::Breadcrumbs, text: SimpleNavigation::Renderer::Text, json: SimpleNavigation::Renderer::Json } class << self extend Forwardable def_delegators :adapter, :context_for_eval, :current_page?, :request, :request_path, :request_uri def_delegators :adapter_class, :register # Sets the root path and current environment as specified. Also sets the # default config_file_path. def set_env(root, environment) self.root = root self.environment = environment config_file_paths << default_config_file_path end # Returns the current framework in which the plugin is running. def framework return :rails if defined?(Rails) return :padrino if defined?(Padrino) return :sinatra if defined?(Sinatra) return :nanoc if defined?(Nanoc3) fail 'simple_navigation currently only works for Rails, Sinatra and ' \ 'Padrino apps' end # Loads the adapter for the current framework def load_adapter self.adapter_class = case framework when :rails then SimpleNavigation::Adapters::Rails when :sinatra then SimpleNavigation::Adapters::Sinatra when :padrino then SimpleNavigation::Adapters::Padrino when :nanoc then SimpleNavigation::Adapters::Nanoc end end # Creates a new adapter instance based on the context in which # render_navigation has been called. def init_adapter_from(context) self.adapter = adapter_class.new(context) end def default_config_file_path File.join(root, 'config') end # Resets the list of config_file_paths to the specified path def config_file_path=(path) self.config_file_paths = [path] end # Reads the config_file for the specified navigation_context and stores it # for later evaluation. def load_config(navigation_context = :default) if environment == 'production' update_config(navigation_context) else update_config!(navigation_context) end end # Returns the singleton instance of the SimpleNavigation::Configuration def config SimpleNavigation::Configuration.instance end # Returns the ItemContainer that contains the items for the # primary navigation def primary_navigation config.primary_navigation end # Returns the active item container for the specified level. # Valid levels are # * :all - in this case the primary_navigation is returned. # * :leaves - the 'deepest' active item_container will be returned # * a specific level - the active item_container for the specified level # will be returned # * a range of levels - the active item_container for the range's minimum # will be returned # # Returns nil if there is no active item_container for the specified level. def active_item_container_for(level) case level when :all then primary_navigation when :leaves then primary_navigation.active_leaf_container when Integer then primary_navigation.active_item_container_for(level) when Range then primary_navigation.active_item_container_for(level.min) else fail ArgumentError, "Invalid navigation level: #{level}" end end # Registers a renderer. # # === Example # To register your own renderer: # # SimpleNavigation.register_renderer my_renderer: My::RendererClass # # Then in the view you can call: # # render_navigation(renderer: :my_renderer) def register_renderer(renderer_hash) registered_renderers.merge!(renderer_hash) end private def config_file(navigation_context) ConfigFileFinder.new(config_file_paths).find(navigation_context) end def read_config(navigation_context) File.read config_file(navigation_context) end def update_config(navigation_context) config_files[navigation_context] ||= read_config(navigation_context) end def update_config!(navigation_context) config_files[navigation_context] = read_config(navigation_context) end end end SimpleNavigation.load_adapter simple-navigation-4.0.3/lib/simple-navigation.rb0000644000004100000410000000003412513767261021724 0ustar www-datawww-datarequire 'simple_navigation' simple-navigation-4.0.3/lib/generators/0000755000004100000410000000000012513767261020125 5ustar www-datawww-datasimple-navigation-4.0.3/lib/generators/navigation_config/0000755000004100000410000000000012513767261023611 5ustar www-datawww-datasimple-navigation-4.0.3/lib/generators/navigation_config/navigation_config_generator.rb0000644000004100000410000000117312513767261031672 0ustar www-datawww-dataclass NavigationConfigGenerator < Rails::Generators::Base def self.source_root @source_root ||= begin tpl_dir = %w[.. .. .. .. generators navigation_config templates] tpl_dir_path = File.join(tpl_dir) File.expand_path(tpl_dir_path, __FILE__) end end desc 'Creates a template config file for the simple-navigation plugin. ' \ 'You will find the generated file in config/navigation.rb.' def navigation_config copy_file('config/navigation.rb', 'config/navigation.rb') readme_path = File.join(%w[.. .. .. .. README.md]) say File.read(File.expand_path(readme_path, __FILE__)) end end simple-navigation-4.0.3/lib/simple_navigation/0000755000004100000410000000000012513767261021464 5ustar www-datawww-datasimple-navigation-4.0.3/lib/simple_navigation/configuration.rb0000644000004100000410000000647612513767261024675 0ustar www-datawww-datarequire 'singleton' module SimpleNavigation # Responsible for evaluating and handling the config/navigation.rb file. class Configuration include Singleton attr_accessor :autogenerate_item_ids, :auto_highlight, :consider_item_names_as_safe, :highlight_on_subpath, :ignore_query_params_on_auto_highlight, :ignore_anchors_on_auto_highlight attr_reader :primary_navigation attr_writer :active_leaf_class, :id_generator, :name_generator, :renderer, :selected_class # Evals the config_file for the given navigation_context def self.eval_config(navigation_context = :default) context = SimpleNavigation.config_files[navigation_context] SimpleNavigation.context_for_eval.instance_eval(context) end # Starts processing the configuration def self.run(&block) block.call Configuration.instance end # Sets the config's default-settings def initialize @autogenerate_item_ids = true @auto_highlight = true @consider_item_names_as_safe = false @highlight_on_subpath = false @ignore_anchors_on_auto_highlight = true @ignore_query_params_on_auto_highlight = true end def active_leaf_class @active_leaf_class ||= 'simple-navigation-active-leaf' end def id_generator @id_generator ||= :to_s.to_proc end # This is the main method for specifying the navigation items. # It can be used in two ways: # # 1. Declaratively specify your items in the config/navigation.rb file # using a block. It then yields an SimpleNavigation::ItemContainer # for adding navigation items. # 2. Directly provide your items to the method (e.g. when loading your # items from the database). # # ==== Example for block style (configuration file) # config.items do |primary| # primary.item :my_item, 'My item', my_item_path # ... # end # # ==== To consider when directly providing items # items_provider should be: # * a methodname (as symbol) that returns your items. The method needs to # be available in the view (i.e. a helper method) # * an object that responds to :items # * an enumerable containing your items # The items you specify have to fullfill certain requirements. # See SimpleNavigation::ItemAdapter for more details. # def items(items_provider = nil, &block) if (items_provider && block) || (items_provider.nil? && block.nil?) fail('please specify either items_provider or block, but not both') end self.primary_navigation = ItemContainer.new if block block.call primary_navigation else primary_navigation.items = ItemsProvider.new(items_provider).items end end # Returns true if the config_file has already been evaluated. def loaded? !primary_navigation.nil? end def name_generator @name_generator ||= proc { |name| name } end def renderer @renderer ||= SimpleNavigation.default_renderer || SimpleNavigation::Renderer::List end def selected_class @selected_class ||= 'selected' end private attr_writer :primary_navigation end end simple-navigation-4.0.3/lib/simple_navigation/renderer/0000755000004100000410000000000012513767261023272 5ustar www-datawww-datasimple-navigation-4.0.3/lib/simple_navigation/renderer/breadcrumbs.rb0000644000004100000410000000364712513767261026122 0ustar www-datawww-datamodule SimpleNavigation module Renderer # Renders an ItemContainer as a
element and its containing items as # elements. # It only renders 'selected' elements. # # By default, the renderer sets the item's key as dom_id for the rendered # element unless the config option autogenerate_item_ids is # set to false. # # The id can also be explicitely specified by setting the id in the # html-options of the 'item' method in the config/navigation.rb file. # The ItemContainer's dom_attributes are applied to the surrounding
# element. class Breadcrumbs < SimpleNavigation::Renderer::Base def render(item_container) content = a_tags(item_container).join(join_with) content_tag(:div, prefix_for(content) + content, item_container.dom_attributes) end protected def a_tags(item_container) item_container.items.each_with_object([]) do |item, list| next unless item.selected? list << tag_for(item) if include_sub_navigation?(item) list.concat a_tags(item.sub_navigation) end end end def join_with @join_with ||= options[:join_with] || ' ' end def suppress_link?(item) super || (options[:static_leaf] && item.active_leaf_class) end def prefix_for(content) if !content.empty? && options[:prefix] options[:prefix] else '' end end # Extracts the options relevant for the generated link # def link_options_for(item) if options[:allow_classes_and_ids] opts = super opts[:id] &&= "breadcrumb_#{opts[:id]}" opts else html_options = item.html_options.except(:class, :id) { method: item.method }.merge(html_options) end end end end end simple-navigation-4.0.3/lib/simple_navigation/renderer/text.rb0000644000004100000410000000121012513767261024575 0ustar www-datawww-datamodule SimpleNavigation module Renderer # Renders the 'chain' of selected navigation items as simple text items, # joined with an optional separator (similar to breadcrumbs, but without # markup). class Text < SimpleNavigation::Renderer::Base def render(item_container) list(item_container).compact.join(options[:join_with] || ' ') end private def list(item_container) item_container.items.keep_if(&:selected?).map do |item| [item.name(apply_generator: false)] + (include_sub_navigation?(item) ? list(item.sub_navigation) : []) end end end end end simple-navigation-4.0.3/lib/simple_navigation/renderer/json.rb0000644000004100000410000000131712513767261024572 0ustar www-datawww-datarequire 'json' module SimpleNavigation module Renderer # Renders the navigation items as a object tree serialized as a json string, # can also output raw ruby Hashes class Json < SimpleNavigation::Renderer::Base def render(item_container) results = hash_render(item_container) options[:as_hash] ? results : results.to_json end private def hash_render(item_container) return nil unless item_container item_container.items.map do |item| { items: hash_render(item.sub_navigation), name: item.name, selected: item.selected?, url: item.url } end end end end end simple-navigation-4.0.3/lib/simple_navigation/renderer/links.rb0000644000004100000410000000251712513767261024744 0ustar www-datawww-datamodule SimpleNavigation module Renderer # Renders an ItemContainer as a
element and its containing items as # elements. # It adds the 'selected' class to the element that is currently active. # # The Links renderer cannot be used to render nested navigations. If you # would like it to use with nested navigations, you have to render each # level separately. # # By default, the renderer sets the item's key as dom_id for the rendered # element unless the config option autogenerate_item_ids is set # to false. # The id can also be explicitely specified by setting the id in the # html-options of the 'item' method in the config/navigation.rb file. # The ItemContainer's dom_attributes are applied to the surrounding
# element. class Links < SimpleNavigation::Renderer::Base def render(item_container) div_content = item_container.items .map { |item| tag_for(item) } .join(join_with) content_tag :div, div_content, item_container.dom_attributes end protected def join_with @join_with ||= options[:join_with] || '' end def options_for(item) { method: item.method }.merge(item.html_options) end end end end simple-navigation-4.0.3/lib/simple_navigation/renderer/list.rb0000644000004100000410000000276212513767261024601 0ustar www-datawww-datamodule SimpleNavigation module Renderer # Renders an ItemContainer as a
    element and its containing items as #
  • elements. # It adds the 'selected' class to li element AND the link inside the li # element that is currently active. # # If the sub navigation should be included (based on the level and # expand_all options), it renders another
      containing the sub navigation # inside the active
    • element. # # By default, the renderer sets the item's key as dom_id for the rendered #
    • element unless the config option autogenerate_item_ids is # set to false. # The id can also be explicitely specified by setting the id in the # html-options of the 'item' method in the config/navigation.rb file. class List < SimpleNavigation::Renderer::Base def render(item_container) if skip_if_empty? && item_container.empty? '' else tag = options[:ordered] ? :ol : :ul content = list_content(item_container) content_tag(tag, content, item_container.dom_attributes) end end private def list_content(item_container) item_container.items.map { |item| li_options = item.html_options.except(:link) li_content = tag_for(item) if include_sub_navigation?(item) li_content << render_sub_navigation_for(item) end content_tag(:li, li_content, li_options) }.join end end end end simple-navigation-4.0.3/lib/simple_navigation/renderer/base.rb0000644000004100000410000000571412513767261024540 0ustar www-datawww-datarequire 'forwardable' module SimpleNavigation module Renderer # This is the base class for all renderers. # # A renderer is responsible for rendering an ItemContainer and its # containing items to HTML. class Base extend Forwardable attr_reader :adapter, :options def_delegators :adapter, :link_to, :content_tag def initialize(options) #:nodoc: @options = options @adapter = SimpleNavigation.adapter end def expand_all? !!options[:expand_all] end def level options[:level] || :all end def skip_if_empty? !!options[:skip_if_empty] end def include_sub_navigation?(item) consider_sub_navigation?(item) && expand_sub_navigation?(item) end def render_sub_navigation_for(item) item.sub_navigation.render(options) end # Renders the specified ItemContainer to HTML. # # When implementing a renderer, please consider to call # include_sub_navigation? to determine whether an item's sub_navigation # should be rendered or not. def render(item_container) fail NotImplementedError, 'subclass responsibility' end protected def consider_sub_navigation?(item) return false unless item.sub_navigation case level when :all then true when Range then item.sub_navigation.level <= level.max else false end end def expand_sub_navigation?(item) expand_all? || item.selected? end # to allow overriding when there is specific logic determining # when a link should not be rendered (eg. breadcrumbs renderer # does not render the final breadcrumb as a link when instructed # not to do so.) def suppress_link?(item) item.url.nil? end # determine and return link or static content depending on # item/renderer conditions. def tag_for(item) if suppress_link?(item) content_tag('span', item.name, link_options_for(item).except(:method)) else link_to(item.name, item.url, options_for(item)) end end # to allow overriding when link options should be special-cased # (eg. links renderer uses item options for the a-tag rather # than an li-tag). def options_for(item) link_options_for(item) end # Extracts the options relevant for the generated link def link_options_for(item) special_options = { method: item.method, class: item.selected_class }.reject { |_, v| v.nil? } link_options = item.link_html_options return special_options unless link_options opts = special_options.merge(link_options) classes = [link_options[:class], item.selected_class] classes = classes.flatten.compact.join(' ') opts[:class] = classes unless classes.empty? opts end end end end simple-navigation-4.0.3/lib/simple_navigation/adapters/0000755000004100000410000000000012513767261023267 5ustar www-datawww-datasimple-navigation-4.0.3/lib/simple_navigation/adapters/padrino.rb0000644000004100000410000000074612513767261025257 0ustar www-datawww-datamodule SimpleNavigation module Adapters class Padrino < Sinatra def self.register(app) SimpleNavigation.set_env(::Padrino.root, ::Padrino.env) ::Padrino::Application.send(:helpers, SimpleNavigation::Helpers) end def link_to(name, url, options = {}) context.link_to(name, url, options) end def content_tag(type, content, options = {}) context.content_tag(type, content.html_safe, options) end end end end simple-navigation-4.0.3/lib/simple_navigation/adapters/sinatra.rb0000644000004100000410000000240612513767261025257 0ustar www-datawww-datarequire 'cgi' module SimpleNavigation module Adapters class Sinatra < Base def self.register(app) SimpleNavigation.set_env(app.root, app.environment) end def initialize(context) @context = context @request = context.request end def context_for_eval context || fail('no context set for evaluation the config file') end def request_uri request.fullpath end def request_path request.path end def current_page?(url) url_string = CGI.unescape(url) uri = if url_string.index('?') request_uri else request_uri.split('?').first end if url_string =~ %r(^\w+://) uri = "#{request.scheme}://#{request.host_with_port}#{uri}" end url_string == CGI.unescape(uri) end def link_to(name, url, options = {}) "#{name}" end def content_tag(type, content, options = {}) "<#{type}#{to_attributes(options)}>#{content}" end protected def to_attributes(options) options.map { |k, v| v.nil? ? '' : " #{k}='#{v}'" }.join end end end end simple-navigation-4.0.3/lib/simple_navigation/adapters/nanoc.rb0000644000004100000410000000240012513767261024706 0ustar www-datawww-datamodule SimpleNavigation module Adapters class Nanoc < Base class << self def register(root) SimpleNavigation.set_env(root, 'development') Nanoc3::Context.send(:include, SimpleNavigation::Helpers) end end def initialize(ctx) @context = ctx end # Returns the context in which the config files will be evaluated def context_for_eval context end # Returns true if the current request's url matches the specified url. # Used to determine if an item should be autohighlighted. def current_page?(url) path = context.item.path path && path.chop == url end # Returns a link with the specified name, url and options. # Used for rendering. def link_to(name, url, options = {}) "#{name}" end # Returns a tag of the specified type, content and options. # Used for rendering. def content_tag(type, content, options = {}) "<#{type} #{to_attributes(options)}>#{content}" end private def to_attributes(options) options.map { |k, v| v.nil? ? nil : "#{k}='#{v}'" }.compact.join(' ') end end end end simple-navigation-4.0.3/lib/simple_navigation/adapters/base.rb0000644000004100000410000000231412513767261024526 0ustar www-datawww-datamodule SimpleNavigation module Adapters # This is the base class for all adapters. # This class mainly exists for documenting reasons. # It lists all the methods that an adapter should implement. # class Base attr_reader :context, :request # This method is usually called when the framework is initialized. # It should call SimpleNavigation.set_env and install # SimpleNavigation::Helpers where appropriate. def self.register; end # Returns the full path incl. query params def request_uri; end # Returns the path without query params def request_path; end # Returns the context in which the config files will be evaluated def context_for_eval; end # Returns true if the current request's url matches the specified url. # Used to determine if an item should be autohighlighted. def current_page?(url); end # Returns a link with the specified name, url and options. # Used for rendering. def link_to(name, url, options = {}); end # Returns a tag of the specified type, content and options. # Used for rendering. def content_tag(type, content, options = {}); end end end end simple-navigation-4.0.3/lib/simple_navigation/adapters/rails.rb0000644000004100000410000000426512513767261024735 0ustar www-datawww-datamodule SimpleNavigation module Adapters class Rails < Base attr_reader :controller, :template def self.register SimpleNavigation.set_env(::Rails.root, ::Rails.env) ActionController::Base.send(:include, SimpleNavigation::Helpers) SimpleNavigation::Helpers.instance_methods.each do |m| ActionController::Base.send(:helper_method, m.to_sym) end end def initialize(context) @controller = extract_controller_from context @template = template_from @controller @request = @template.request if @template end def request_uri return '' unless request if request.respond_to?(:fullpath) request.fullpath else request.request_uri end end def request_path request ? request.path : '' end def context_for_eval template || controller || fail('no context set for evaluation the config file') end def current_page?(url) template && template.current_page?(url) end def link_to(name, url, options = {}) template && template.link_to(link_title(name), url, options) end def content_tag(type, content, options = {}) template && template.content_tag(type, html_safe(content), options) end protected def template_from(controller) if controller.respond_to?(:view_context) controller.view_context else controller.instance_variable_get(:@template) end end # Marks the specified input as html_safe (for Rails3). # Does nothing if html_safe is not defined on input. # def html_safe(input) input.respond_to?(:html_safe) ? input.html_safe : input end # Extracts a controller from the context. def extract_controller_from(context) if context.respond_to?(:controller) context.controller || context else context end end def link_title(name) if SimpleNavigation.config.consider_item_names_as_safe html_safe(name) else name end end end end end simple-navigation-4.0.3/lib/simple_navigation/config_file_finder.rb0000644000004100000410000000232112513767261025602 0ustar www-datawww-datarequire 'simple_navigation/config_file' module SimpleNavigation # Internal: Encapsulates the configuration file finding logic. class ConfigFileFinder # Internal: Initializes a ConfigFileFinder. # # paths - an enumerable list of paths in which to look for configuration # files. def initialize(paths) @paths = paths end # Internal: Searches a configuration file for the given context in the # initialization paths. # # context - The navigation context for which to look the configuration file. # # Returns a String representing the full path of the configuation file. # Raises StandardError if no file is found. def find(context) config_file_name = config_file_name_for_context(context) find_config_file(config_file_name) || fail("Config file '#{config_file_name}' not found in " \ "path(s) #{paths.join(', ')}!") end private attr_reader :paths def config_file_name_for_context(context) ConfigFile.new(context).name end def find_config_file(config_file_name) paths.map { |path| File.join(path, config_file_name) } .find { |full_path| File.exist?(full_path) } end end end simple-navigation-4.0.3/lib/simple_navigation/adapters.rb0000644000004100000410000000050712513767261023616 0ustar www-datawww-datarequire 'simple_navigation/adapters/base' module SimpleNavigation module Adapters autoload :Rails, 'simple_navigation/adapters/rails' autoload :Padrino, 'simple_navigation/adapters/padrino' autoload :Sinatra, 'simple_navigation/adapters/sinatra' autoload :Nanoc, 'simple_navigation/adapters/nanoc' end end simple-navigation-4.0.3/lib/simple_navigation/item.rb0000644000004100000410000001302312513767261022746 0ustar www-datawww-datamodule SimpleNavigation # Represents an item in your navigation. # Gets generated by the item method in the config-file. class Item attr_reader :key, :name, :sub_navigation, :url # see ItemContainer#item # # The subnavigation (if any) is either provided by a block or # passed in directly as items def initialize(container, key, name, url = nil, opts = {}, &sub_nav_block) self.container = container self.key = key self.name = name.respond_to?(:call) ? name.call : name self.url = url.respond_to?(:call) ? url.call : url self.options = opts setup_sub_navigation(options[:items], &sub_nav_block) end # Returns the item's name. # If :apply_generator option is set to true (default), # the name will be passed to the name_generator specified # in the configuration. # def name(options = {}) options = { apply_generator: true }.merge(options) if options[:apply_generator] config.name_generator.call(@name, self) else @name end end # Returns true if this navigation item should be rendered as 'selected'. # An item is selected if # # * it has a subnavigation and one of its subnavigation items is selected or # * its url matches the url of the current request (auto highlighting) # def selected? @selected ||= selected_by_subnav? || selected_by_condition? end # Returns the html-options hash for the item, i.e. the options specified # for this item in the config-file. # It also adds the 'selected' class to the list of classes if necessary. def html_options html_opts = options.fetch(:html) { Hash.new } html_opts[:id] ||= autogenerated_item_id classes = [html_opts[:class], selected_class, active_leaf_class] classes = classes.flatten.compact.join(' ') html_opts[:class] = classes if classes && !classes.empty? html_opts end # Returns the configured active_leaf_class if the item is the selected leaf, # nil otherwise def active_leaf_class if !selected_by_subnav? && selected_by_condition? config.active_leaf_class end end # Returns the configured selected_class if the item is selected, # nil otherwise def selected_class if selected? container.selected_class || config.selected_class end end # Returns the :highlights_on option as set at initialization def highlights_on @highlights_on ||= options[:highlights_on] end # Returns the :method option as set at initialization def method @method ||= options[:method] end # Returns the html attributes for the link as set with the :link_html option # at initialization def link_html_options @link_html_options ||= options[:link_html] end protected # Returns true if item has a subnavigation and # the sub_navigation is selected def selected_by_subnav? sub_navigation && sub_navigation.selected? end # Returns true if the item's url matches the request's current url. def selected_by_condition? highlights_on ? selected_by_highlights_on? : selected_by_autohighlight? end # Returns true if both the item's url and the request's url are root_path def root_path_match? url == '/' && SimpleNavigation.request_path == '/' end # Returns the item's id which is added to the rendered output. def autogenerated_item_id config.id_generator.call(key) if config.autogenerate_item_ids end # Return true if auto_highlight is on for this item. def auto_highlight? config.auto_highlight && container.auto_highlight end private attr_accessor :container, :options attr_writer :key, :name, :sub_navigation, :url def config SimpleNavigation.config end def request_uri SimpleNavigation.request_uri end def remove_anchors(url_with_anchors) url_with_anchors && url_with_anchors.split('#').first end def remove_query_params(url_with_params) url_with_params && url_with_params.split('?').first end def url_for_autohighlight relevant_url = remove_anchors(self.url) if config.ignore_anchors_on_auto_highlight relevant_url = remove_query_params(relevant_url) if config.ignore_query_params_on_auto_highlight relevant_url end def selected_by_autohighlight? return false unless auto_highlight? root_path_match? || (url_for_autohighlight && SimpleNavigation.current_page?(url_for_autohighlight)) || autohighlight_by_subpath? end def autohighlight_by_subpath? config.highlight_on_subpath && selected_by_subpath? end def selected_by_highlights_on? case highlights_on when Regexp then !!(request_uri =~ highlights_on) when Proc then highlights_on.call when :subpath then selected_by_subpath? else fail ArgumentError, ':highlights_on must be a Regexp, Proc or :subpath' end end def selected_by_subpath? escaped_url = Regexp.escape(url_for_autohighlight) !!(request_uri =~ /^#{escaped_url}(\/|$||\?)/i) end def setup_sub_navigation(items = nil, &sub_nav_block) return unless sub_nav_block || items self.sub_navigation = ItemContainer.new(container.level + 1) if sub_nav_block sub_nav_block.call sub_navigation else sub_navigation.items = items end end end end simple-navigation-4.0.3/lib/simple_navigation/item_adapter.rb0000644000004100000410000000337612513767261024460 0ustar www-datawww-datarequire 'forwardable' require 'ostruct' module SimpleNavigation # This class acts as an adapter to items that are not defined using the DSL # in the config/navigation.rb, but directly provided inside the application. # When defining the items that way, every item you provide needs to define # the following methods: # # * key # * name # * url # # and optionally # # * options # * items - if one of your items has a subnavigation it must respond # to items providing the subnavigation. # # You can also specify your items as a list of hashes. # The hashes will be converted to objects automatically. # The hashes representing the items obviously must have the keys :key, :name # and :url and optionally the keys :options and :items. # # See SimpleNavigation::ItemContainer#item for the purpose of these methods. class ItemAdapter extend Forwardable def_delegators :item, :key, :name, :url attr_reader :item def initialize(item) @item = item.is_a?(Hash) ? OpenStruct.new(item) : item end # Returns the options for this item. If the wrapped item does not implement # an options method, an empty hash is returned. def options item.respond_to?(:options) ? item.options : {} end # Returns the items (subnavigation) for this item if it responds to :items # and the items-collection is not empty. Returns nil otherwise. def items item.items if item.respond_to?(:items) && item.items && item.items.any? end # Converts this Item into a SimpleNavigation::Item def to_simple_navigation_item(item_container) SimpleNavigation::Item.new(item_container, key, name, url, options) end end end simple-navigation-4.0.3/lib/simple_navigation/items_provider.rb0000644000004100000410000000235312513767261025047 0ustar www-datawww-datamodule SimpleNavigation # Acts as a proxy to navigation items that are passed into the # SimpleNavigation::Configuration#items method. # It hides the logic for finding items from the Configuration object. # class ItemsProvider attr_reader :provider # It accepts the following types of provider: # * methodname as symbol - the specified method should return the relevant # items and has to be available in the view (a helper method) # * object that responds to :items # * enumerable object that represents the items # # See SimpleNavigation::ItemAdapter for the requirements that need to be # fulfilled by the provided items. # def initialize(provider) @provider = provider end # Returns the navigation items def items if provider.is_a?(Symbol) SimpleNavigation.context_for_eval.send(provider) elsif provider.respond_to?(:items) provider.items elsif provider.respond_to?(:each) provider else fail('items_provider either must be a symbol specifying the ' \ 'helper-method to call, an object with an items-method defined ' \ 'or an enumerable representing the items') end end end end simple-navigation-4.0.3/lib/simple_navigation/helpers.rb0000644000004100000410000001753512513767261023466 0ustar www-datawww-datamodule SimpleNavigation # View helpers to render the navigation. # # Use render_navigation as following to render your navigation: # * call render_navigation without :level option to render your # complete navigation as nested tree. # * call render_navigation(level: x) to render a specific # navigation level (e.g. level: 1 to render your primary navigation, # level: 2 to render the sub navigation and so forth) # * call render_navigation(:level => 2..3) to render navigation # levels 2 and 3). # # For example, you could use render_navigation(level: 1) to render your # primary navigation as tabs and render_navigation(level: 2..3) to render # the rest of the navigation as a tree in a sidebar. # # ==== Examples (using Haml) # #primary_navigation= render_navigation(level: 1) # # #sub_navigation= render_navigation(level: 2) # # #nested_navigation= render_navigation # # #top_navigation= render_navigation(level: 1..2) # #sidebar_navigation= render_navigation(level: 3) module Helpers def self.load_config(options, includer, &block) context = options.delete(:context) SimpleNavigation.init_adapter_from includer SimpleNavigation.load_config context SimpleNavigation::Configuration.eval_config context if block_given? || options[:items] SimpleNavigation.config.items(options[:items], &block) end unless SimpleNavigation.primary_navigation fail 'no primary navigation defined, either use a navigation config ' \ 'file or pass items directly to render_navigation' end end def self.apply_defaults(options) options[:level] = options.delete(:levels) if options[:levels] { context: :default, level: :all }.merge(options) end # Renders the navigation according to the specified options-hash. # # The following options are supported: # * :level - defaults to :all which renders the the sub_navigation # for an active primary_navigation inside that active # primary_navigation item. # Specify a specific level to only render that level of navigation # (e.g. level: 1 for primary_navigation, etc). # Specifiy a Range of levels to render only those specific levels # (e.g. level: 1..2 to render both your first and second levels, maybe # you want to render your third level somewhere else on the page) # * :expand_all - defaults to false. If set to true the all # specified levels will be rendered as a fully expanded # tree (always open). This is useful for javascript menus like Superfish. # * :context - specifies the context for which you would render # the navigation. Defaults to :default which loads the default # navigation.rb (i.e. config/navigation.rb). # If you specify a context then the plugin tries to load the configuration # file for that context, e.g. if you call # render_navigation(context: :admin) the file # config/admin_navigation.rb will be loaded and used for rendering # the navigation. # * :items - you can specify the items directly (e.g. if items are # dynamically generated from database). # See SimpleNavigation::ItemsProvider for documentation on what to # provide as items. # * :renderer - specify the renderer to be used for rendering the # navigation. Either provide the Class or a symbol matching a registered # renderer. Defaults to :list (html list renderer). # # Instead of using the :items option, a block can be passed to # specify the items dynamically # # ==== Examples # render_navigation do |menu| # menu.item :posts, "Posts", posts_path # end # def render_navigation(options = {}, &block) container = active_navigation_item_container(options, &block) container && container.render(options) end # Returns the name of the currently active navigation item belonging to the # specified level. # # See Helpers#active_navigation_item for supported options. # # Returns an empty string if no active item can be found for the specified # options def active_navigation_item_name(options = {}) active_navigation_item(options, '') do |item| item.name(apply_generator: false) end end # Returns the key of the currently active navigation item belonging to the # specified level. # # See Helpers#active_navigation_item for supported options. # # Returns nil if no active item can be found for the specified # options def active_navigation_item_key(options = {}) active_navigation_item(options, &:key) end # Returns the currently active navigation item belonging to the specified # level. # # The following options are supported: # * :level - defaults to :all which returns the # most specific/deepest selected item (the leaf). # Specify a specific level to only look for the selected item in the # specified level of navigation # (e.g. level: 1 for primary_navigation, etc). # * :context - specifies the context for which you would like to # find the active navigation item. Defaults to :default which loads the # default navigation.rb (i.e. config/navigation.rb). # If you specify a context then the plugin tries to load the configuration # file for that context, e.g. if you call # active_navigation_item_name(context: :admin) the file # config/admin_navigation.rb will be loaded and used for searching the # active item. # * :items - you can specify the items directly (e.g. if items are # dynamically generated from database). # See SimpleNavigation::ItemsProvider for documentation on what to provide # as items. # # Returns the supplied value_for_nil object (nil # by default) if no active item can be found for the specified # options def active_navigation_item(options = {}, value_for_nil = nil) if options[:level].nil? || options[:level] == :all options[:level] = :leaves end container = active_navigation_item_container(options) if container && (item = container.selected_item) block_given? ? yield(item) : item else value_for_nil end end # Returns the currently active item container belonging to the specified # level. # # The following options are supported: # * :level - defaults to :all which returns the # least specific/shallowest selected item. # Specify a specific level to only look for the selected item in the # specified level of navigation # (e.g. level: 1 for primary_navigation, etc). # * :context - specifies the context for which you would like to # find the active navigation item. Defaults to :default which loads the # default navigation.rb (i.e. config/navigation.rb). # If you specify a context then the plugin tries to load the configuration # file for that context, e.g. if you call # active_navigation_item_name(context: :admin) the file # config/admin_navigation.rb will be loaded and used for searching the # active item. # * :items - you can specify the items directly (e.g. if items are # dynamically generated from database). # See SimpleNavigation::ItemsProvider for documentation on what to provide # as items. # # Returns nil if no active item container can be found def active_navigation_item_container(options = {}, &block) options = SimpleNavigation::Helpers.apply_defaults(options) SimpleNavigation::Helpers.load_config(options, self, &block) SimpleNavigation.active_item_container_for(options[:level]) end end end simple-navigation-4.0.3/lib/simple_navigation/version.rb0000644000004100000410000000006012513767261023472 0ustar www-datawww-datamodule SimpleNavigation VERSION = '4.0.3' end simple-navigation-4.0.3/lib/simple_navigation/config_file.rb0000644000004100000410000000174112513767261024260 0ustar www-datawww-datarequire 'active_support/core_ext/string' module SimpleNavigation # Internal: Encapsulates the config file naming knowledge. class ConfigFile # Internal: Initializes a ConfigFile. # # context - The navigation context for this ConfigFile. def initialize(context) @prefix = prefix_for_context(context) end # Internal: Returns the name of the configuration file on disk. # # Based on the the initialization context the outcome may differ. # # Examples # # ConfigFile.new.name # => "navigation.rb" # ConfigFile.new(:default).name # => "navigation.rb" # ConfigFile.new(:other).name # => "other_navigation.rb" # # Returns a String representing the name of the configuration file on disk. def name @name ||= "#{prefix}navigation.rb" end private attr_reader :prefix def prefix_for_context(context) context == :default ? '' : "#{context.to_s.underscore}_" end end end simple-navigation-4.0.3/lib/simple_navigation/renderer.rb0000644000004100000410000000064112513767261023620 0ustar www-datawww-datarequire 'simple_navigation/helpers' require 'simple_navigation/renderer/base' module SimpleNavigation module Renderer autoload :List, 'simple_navigation/renderer/list' autoload :Links, 'simple_navigation/renderer/links' autoload :Breadcrumbs, 'simple_navigation/renderer/breadcrumbs' autoload :Text, 'simple_navigation/renderer/text' autoload :Json, 'simple_navigation/renderer/json' end end simple-navigation-4.0.3/lib/simple_navigation/item_container.rb0000644000004100000410000001445012513767261025015 0ustar www-datawww-datamodule SimpleNavigation # Holds the Items for a navigation 'level'. class ItemContainer attr_accessor :auto_highlight, :dom_class, :dom_id, :renderer, :selected_class attr_reader :items, :level attr_writer :dom_attributes def initialize(level = 1) #:nodoc: @level = level @items ||= [] @renderer = SimpleNavigation.config.renderer @auto_highlight = true end def dom_attributes # backward compability for #dom_id and #dom_class dom_id_and_class = { id: dom_id, class: dom_class }.reject { |_, v| v.nil? } (@dom_attributes || {}).merge(dom_id_and_class) end # Creates a new navigation item. # # The key is a symbol which uniquely defines your navigation item # in the scope of the primary_navigation or the sub_navigation. # # The name will be displayed in the rendered navigation. # This can also be a call to your I18n-framework. # # The url is the address that the generated item points to. # You can also use url_helpers (named routes, restful routes helper, # url_for, etc). url is optional - items without URLs should not # be rendered as links. # # The options can be used to specify the following things: # * any html_attributes - will be included in the rendered # navigation item (e.g. id, class etc.) # * :if - Specifies a proc to call to determine if the item should # be rendered (e.g. if: Proc.new { current_user.admin? }). The # proc should evaluate to a true or false value and is evaluated # in the context of the view. # * :unless - Specifies a proc to call to determine if the item # should not be rendered # (e.g. unless: Proc.new { current_user.admin? }). # The proc should evaluate to a true or false value and is evaluated in # the context of the view. # * :method - Specifies the http-method for the generated link - # default is :get. # * :highlights_on - if autohighlighting is turned off and/or you # want to explicitly specify when the item should be highlighted, you can # set a regexp which is matched againstthe current URI. # # The block - if specified - will hold the item's sub_navigation. def item(key, name, url = nil, options = {}, &block) return unless should_add_item?(options) item = Item.new(self, key, name, url, options, &block) add_item item, options end def items=(new_items) new_items.each do |item| item_adapter = ItemAdapter.new(item) next unless should_add_item?(item_adapter.options) add_item item_adapter.to_simple_navigation_item(self), item_adapter.options end end # Returns the Item with the specified key, nil otherwise. # def [](navi_key) items.find { |item| item.key == navi_key } end # Returns the level of the item specified by navi_key. # Recursively works its way down the item's sub_navigations if the desired # item is not found directly in this container's items. # Returns nil if item cannot be found. # def level_for_item(navi_key) return level if self[navi_key] items.each do |item| next unless item.sub_navigation level = item.sub_navigation.level_for_item(navi_key) return level if level end return nil end # Renders the items in this ItemContainer using the configured renderer. # # The options are the same as in the view's render_navigation call # (they get passed on) def render(options = {}) renderer_instance(options).render(self) end # Returns true if any of this container's items is selected. # def selected? items.any?(&:selected?) end # Returns the currently selected item, nil if no item is selected. # def selected_item items.find(&:selected?) end # Returns the active item_container for the specified level # (recursively looks up items in selected sub_navigation if level is deeper # than this container's level). def active_item_container_for(desired_level) if level == desired_level self elsif selected_sub_navigation? selected_item.sub_navigation.active_item_container_for(desired_level) end end # Returns the deepest possible active item_container. # (recursively searches in the sub_navigation if this container has a # selected sub_navigation). def active_leaf_container if selected_sub_navigation? selected_item.sub_navigation.active_leaf_container else self end end # Returns true if there are no items defined for this container. def empty? items.empty? end private def add_item(item, options) items << item modify_dom_attributes(options) end def modify_dom_attributes(options) return unless container_options = options[:container] self.dom_attributes = container_options.fetch(:attributes) { dom_attributes } self.dom_class = container_options.fetch(:class) { dom_class } self.dom_id = container_options.fetch(:id) { dom_id } self.selected_class = container_options.fetch(:selected_class) { selected_class } end # FIXME: raise an exception if :rederer is a symbol and it is not registred # in SimpleNavigation.registered_renderers def renderer_instance(options) return renderer.new(options) unless options[:renderer] if options[:renderer].is_a?(Symbol) registered_renderer = SimpleNavigation.registered_renderers[options[:renderer]] registered_renderer.new(options) else options[:renderer].new(options) end end def selected_sub_navigation? !!(selected_item && selected_item.sub_navigation) end def should_add_item?(options) [options[:if]].flatten.compact.all? { |m| evaluate_method(m) } && [options[:unless]].flatten.compact.none? { |m| evaluate_method(m) } end def evaluate_method(method) case method when Proc, Method then method.call else fail(ArgumentError, ':if or :unless must be procs or lambdas') end end end end simple-navigation-4.0.3/lib/simple_navigation/railtie.rb0000644000004100000410000000024312513767261023441 0ustar www-datawww-datamodule SimpleNavigation class Railtie < ::Rails::Railtie initializer 'simple_navigation.register' do |app| SimpleNavigation.register end end end simple-navigation-4.0.3/gemfiles/0000755000004100000410000000000012513767261017001 5ustar www-datawww-datasimple-navigation-4.0.3/gemfiles/rails-4-2-stable.gemfile0000644000004100000410000000017312513767261023216 0ustar www-datawww-datasource 'https://rubygems.org' gem 'launchy' gem 'railties', '~> 4.2.0' gem 'rspec-rails', '~> 3.2.1' gemspec path: '../' simple-navigation-4.0.3/gemfiles/rails-3-2-stable.gemfile0000644000004100000410000000025112513767261023212 0ustar www-datawww-datasource 'https://rubygems.org' gem 'railties', '~> 3.2.0' gem 'rspec-rails', '~> 3.2.1' if RUBY_VERSION >= '2.2.0' gem 'test-unit', '~> 3.0' end gemspec path: '../' simple-navigation-4.0.3/gemfiles/rails-4-1-stable.gemfile0000644000004100000410000000015512513767261023215 0ustar www-datawww-datasource 'https://rubygems.org' gem 'railties', '~> 4.1.0' gem 'rspec-rails', '~> 3.2.1' gemspec path: '../' simple-navigation-4.0.3/gemfiles/.bundle/0000755000004100000410000000000012513767261020330 5ustar www-datawww-datasimple-navigation-4.0.3/gemfiles/.bundle/config0000644000004100000410000000002312513767261021513 0ustar www-datawww-data--- BUNDLE_JOBS: 4 simple-navigation-4.0.3/metadata.yml0000644000004100000410000002115612513767261017516 0ustar www-datawww-data--- !ruby/object:Gem::Specification name: simple-navigation version: !ruby/object:Gem::Version version: 4.0.3 platform: ruby authors: - Andi Schacke - Mark J. Titorenko - Simon Courtois autorequire: bindir: bin cert_chain: [] date: 2015-04-09 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: activesupport requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: 2.3.2 type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: 2.3.2 - !ruby/object:Gem::Dependency name: bundler requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '1.5' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '1.5' - !ruby/object:Gem::Dependency name: capybara requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: coveralls requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '0.7' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '0.7' - !ruby/object:Gem::Dependency name: guard-rspec requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '4.2' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '4.2' - !ruby/object:Gem::Dependency name: memfs requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: 0.4.1 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: 0.4.1 - !ruby/object:Gem::Dependency name: rake requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: rdoc requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: rspec requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '3.0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '3.0' - !ruby/object:Gem::Dependency name: tzinfo requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' description: With the simple-navigation gem installed you can easily create multilevel navigations for your Rails, Sinatra or Padrino applications. The navigation is defined in a single configuration file. It supports automatic as well as explicit highlighting of the currently active navigation through regular expressions. email: - andi@codeplant.ch executables: [] extensions: [] extra_rdoc_files: [] files: - ".gitignore" - ".rspec" - ".travis.yml" - CHANGELOG.md - Gemfile - Guardfile - LICENSE - README.md - Rakefile - gemfiles/.bundle/config - gemfiles/rails-3-2-stable.gemfile - gemfiles/rails-4-1-stable.gemfile - gemfiles/rails-4-2-stable.gemfile - generators/navigation_config/USAGE - generators/navigation_config/navigation_config_generator.rb - generators/navigation_config/templates/config/navigation.rb - init.rb - install.rb - lib/generators/navigation_config/navigation_config_generator.rb - lib/simple-navigation.rb - lib/simple_navigation.rb - lib/simple_navigation/adapters.rb - lib/simple_navigation/adapters/base.rb - lib/simple_navigation/adapters/nanoc.rb - lib/simple_navigation/adapters/padrino.rb - lib/simple_navigation/adapters/rails.rb - lib/simple_navigation/adapters/sinatra.rb - lib/simple_navigation/config_file.rb - lib/simple_navigation/config_file_finder.rb - lib/simple_navigation/configuration.rb - lib/simple_navigation/helpers.rb - lib/simple_navigation/item.rb - lib/simple_navigation/item_adapter.rb - lib/simple_navigation/item_container.rb - lib/simple_navigation/items_provider.rb - lib/simple_navigation/railtie.rb - lib/simple_navigation/renderer.rb - lib/simple_navigation/renderer/base.rb - lib/simple_navigation/renderer/breadcrumbs.rb - lib/simple_navigation/renderer/json.rb - lib/simple_navigation/renderer/links.rb - lib/simple_navigation/renderer/list.rb - lib/simple_navigation/renderer/text.rb - lib/simple_navigation/version.rb - simple-navigation.gemspec - spec/fake_app/config/navigation.rb - spec/fake_app/rails_app.rb - spec/initializers/coveralls.rb - spec/initializers/have_css_matcher.rb - spec/initializers/memfs.rb - spec/initializers/rails.rb - spec/initializers/rspec.rb - spec/integration/rendering_navigation_spec.rb - spec/simple_navigation/adapters/padrino_spec.rb - spec/simple_navigation/adapters/rails_spec.rb - spec/simple_navigation/adapters/sinatra_spec.rb - spec/simple_navigation/config_file_finder_spec.rb - spec/simple_navigation/config_file_spec.rb - spec/simple_navigation/configuration_spec.rb - spec/simple_navigation/helpers_spec.rb - spec/simple_navigation/item_adapter_spec.rb - spec/simple_navigation/item_container_spec.rb - spec/simple_navigation/item_spec.rb - spec/simple_navigation/items_provider_spec.rb - spec/simple_navigation/renderer/base_spec.rb - spec/simple_navigation/renderer/breadcrumbs_spec.rb - spec/simple_navigation/renderer/json_spec.rb - spec/simple_navigation/renderer/links_spec.rb - spec/simple_navigation/renderer/list_spec.rb - spec/simple_navigation/renderer/text_spec.rb - spec/simple_navigation_spec.rb - spec/spec_helper.rb - uninstall.rb homepage: http://github.com/codeplant/simple-navigation licenses: - MIT metadata: {} post_install_message: rdoc_options: - "--inline-source" - "--charset=UTF-8" require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: rubygems_version: 2.2.2 signing_key: specification_version: 4 summary: simple-navigation is a ruby library for creating navigations (with multiple levels) for your Rails2, Rails3, Rails4, Sinatra or Padrino application. test_files: - spec/fake_app/config/navigation.rb - spec/fake_app/rails_app.rb - spec/initializers/coveralls.rb - spec/initializers/have_css_matcher.rb - spec/initializers/memfs.rb - spec/initializers/rails.rb - spec/initializers/rspec.rb - spec/integration/rendering_navigation_spec.rb - spec/simple_navigation/adapters/padrino_spec.rb - spec/simple_navigation/adapters/rails_spec.rb - spec/simple_navigation/adapters/sinatra_spec.rb - spec/simple_navigation/config_file_finder_spec.rb - spec/simple_navigation/config_file_spec.rb - spec/simple_navigation/configuration_spec.rb - spec/simple_navigation/helpers_spec.rb - spec/simple_navigation/item_adapter_spec.rb - spec/simple_navigation/item_container_spec.rb - spec/simple_navigation/item_spec.rb - spec/simple_navigation/items_provider_spec.rb - spec/simple_navigation/renderer/base_spec.rb - spec/simple_navigation/renderer/breadcrumbs_spec.rb - spec/simple_navigation/renderer/json_spec.rb - spec/simple_navigation/renderer/links_spec.rb - spec/simple_navigation/renderer/list_spec.rb - spec/simple_navigation/renderer/text_spec.rb - spec/simple_navigation_spec.rb - spec/spec_helper.rb simple-navigation-4.0.3/init.rb0000644000004100000410000000005712513767261016500 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/rails/init' simple-navigation-4.0.3/uninstall.rb0000644000004100000410000000003312513767261017540 0ustar www-datawww-data# Uninstall hook code here simple-navigation-4.0.3/install.rb0000644000004100000410000000025312513767261017201 0ustar www-datawww-databegin puts IO.read(File.join(File.dirname(__FILE__), 'README')) rescue Exception => e puts "The following error ocurred while installing the plugin: #{e.message}" end simple-navigation-4.0.3/.gitignore0000644000004100000410000000011712513767261017175 0ustar www-datawww-data.DS_Store rdoc pkg coverage Gemfile.lock .rvmrc capybara-* gemfiles/*.lock log simple-navigation-4.0.3/generators/0000755000004100000410000000000012513767261017357 5ustar www-datawww-datasimple-navigation-4.0.3/generators/navigation_config/0000755000004100000410000000000012513767261023043 5ustar www-datawww-datasimple-navigation-4.0.3/generators/navigation_config/templates/0000755000004100000410000000000012513767261025041 5ustar www-datawww-datasimple-navigation-4.0.3/generators/navigation_config/templates/config/0000755000004100000410000000000012513767261026306 5ustar www-datawww-datasimple-navigation-4.0.3/generators/navigation_config/templates/config/navigation.rb0000644000004100000410000001111012513767261030764 0ustar www-datawww-data# -*- coding: utf-8 -*- # Configures your navigation SimpleNavigation::Configuration.run do |navigation| # Specify a custom renderer if needed. # The default renderer is SimpleNavigation::Renderer::List which renders HTML lists. # The renderer can also be specified as option in the render_navigation call. #navigation.renderer = Your::Custom::Renderer # Specify the class that will be applied to active navigation items. Defaults to 'selected' #navigation.selected_class = 'selected' # Specify the class that will be applied to the current leaf of # active navigation items. Defaults to 'simple-navigation-active-leaf' #navigation.active_leaf_class = 'simple-navigation-active-leaf' # Specify if item keys are added to navigation items as id. Defaults to true #navigation.autogenerate_item_ids = true # You can override the default logic that is used to autogenerate the item ids. # To do this, define a Proc which takes the key of the current item as argument. # The example below would add a prefix to each key. #navigation.id_generator = Proc.new {|key| "my-prefix-#{key}"} # If you need to add custom html around item names, you can define a proc that # will be called with the name you pass in to the navigation. # The example below shows how to wrap items spans. #navigation.name_generator = Proc.new {|name, item| "#{name}"} # Specify if the auto highlight feature is turned on (globally, for the whole navigation). Defaults to true #navigation.auto_highlight = true # Specifies whether auto highlight should ignore query params and/or anchors when # comparing the navigation items with the current URL. Defaults to true #navigation.ignore_query_params_on_auto_highlight = true #navigation.ignore_anchors_on_auto_highlight = true # If this option is set to true, all item names will be considered as safe (passed through html_safe). Defaults to false. #navigation.consider_item_names_as_safe = false # Define the primary navigation navigation.items do |primary| # Add an item to the primary navigation. The following params apply: # key - a symbol which uniquely defines your navigation item in the scope of the primary_navigation # name - will be displayed in the rendered navigation. This can also be a call to your I18n-framework. # url - the address that the generated item links to. You can also use url_helpers (named routes, restful routes helper, url_for etc.) # options - can be used to specify attributes that will be included in the rendered navigation item (e.g. id, class etc.) # some special options that can be set: # :if - Specifies a proc to call to determine if the item should # be rendered (e.g. if: -> { current_user.admin? }). The # proc should evaluate to a true or false value and is evaluated in the context of the view. # :unless - Specifies a proc to call to determine if the item should not # be rendered (e.g. unless: -> { current_user.admin? }). The # proc should evaluate to a true or false value and is evaluated in the context of the view. # :method - Specifies the http-method for the generated link - default is :get. # :highlights_on - if autohighlighting is turned off and/or you want to explicitly specify # when the item should be highlighted, you can set a regexp which is matched # against the current URI. You may also use a proc, or the symbol :subpath. # primary.item :key_1, 'name', url, options # Add an item which has a sub navigation (same params, but with block) primary.item :key_2, 'name', url, options do |sub_nav| # Add an item to the sub navigation (same params again) sub_nav.item :key_2_1, 'name', url, options end # You can also specify a condition-proc that needs to be fullfilled to display an item. # Conditions are part of the options. They are evaluated in the context of the views, # thus you can use all the methods and vars you have available in the views. primary.item :key_3, 'Admin', url, class: 'special', if: -> { current_user.admin? } primary.item :key_4, 'Account', url, unless: -> { logged_in? } # you can also specify html attributes to attach to this particular level # works for all levels of the menu #primary.dom_attributes = {id: 'menu-id', class: 'menu-class'} # You can turn off auto highlighting for a specific level #primary.auto_highlight = false end end simple-navigation-4.0.3/generators/navigation_config/USAGE0000644000004100000410000000017212513767261023632 0ustar www-datawww-dataCreates a template config file for the simple-navigation plugin. You will find the generated file in config/navigation.rb.simple-navigation-4.0.3/generators/navigation_config/navigation_config_generator.rb0000644000004100000410000000025012513767261031117 0ustar www-datawww-dataclass NavigationConfigGenerator < Rails::Generator::Base def manifest record do |m| m.file 'config/navigation.rb', 'config/navigation.rb' end end end simple-navigation-4.0.3/LICENSE0000644000004100000410000000205712513767261016217 0ustar www-datawww-dataCopyright (c) 2014 codeplant GmbH MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. simple-navigation-4.0.3/CHANGELOG.md0000644000004100000410000003313612513767261017025 0ustar www-datawww-data# Changelog ## 4.0.3 * Fix #180 Check URL before invoking current_page? ## 4.0.2 * fixing current_page? when url is nil ## 4.0.1 * fixed padrino adapter ## 4.0.0 * added two new configuration options ignore_query_params_on_auto_highlight and ignore_anchors_on_auto_highlight * Remove dependency on classic-style Sinatra applications and enable use with modular-style apps. Credits to Stefan Kolb. * Item can now receive a block as `name` * It's now possible to set a global `highlight_on_subpath` option instead of adding it to every item * Creating an Item doesn't remove options anymore * Creating an Item no longer changed its container, only adding it to a container does * `Item#autogenerate_item_ids?` has been removed * `SN.config_file_name`, `SN.config_file` and `SN.config_file?` have been removed * `ConfigFileFinder` and `ConfigFile` handle the configuration logic * File organization was been changed to reflect the Ruby namespacing ## 3.13.0 * consider_item_names_as_safe is now false by default. Removed deprecation warning ## 3.12.2 * Fixing issue #154. Thanks to Simon Curtois. ## 3.12.1 * bugfix (error in generator) ## 3.12.0 * Relax hash constraint on item_adapter. Thanks to Ramon Tayag. * Fixed hidden special character in navigation template. Credits to Stef Lewandowski * Added full MIT license text. Thanks to Ben Armstrong. * Added license to gemspec. Thanks to Troy Thompson. * Allow defining other html attributes than :id and :class on menu container. Credits to Jacek Tomaszewski. * Added new config option "consider_item_names_as_safe". Thanks to Alexey Naumov. * Big cleanup of specs, removed jeweler in favor of the "bundler" way. Huge thank you to Simon Courtois. * Added more powerful name generator which yields the item itself in addition to the item's name. Credits to Simon Curtois. ## 3.11.0 * Added Json renderer. Thanks to Alberto Avila. ## 3.10.1 * Padrino adapter now returns "html_safe"d content_tag ## 3.10.0 * Added ability to set selected_class on container level. Credits to Joost Hietbrink. * do not highlight items that are only partial matches. Thanks to Troy Thompson. * adding support for rails 4. Credits to Samer Masry. ## 3.9.0 * Added ability to pass a block to render_navigation for configuring dynamic navigation items (instead of passing :items). Credits to Ronald Chan. ## 3.8.0 * Changed the way the context is fetched. Fixes incompatibility with Gretel. Thanks to Ivan Kasatenko. * Added :join_with option to links renderer. Thanks to Stefan Melmuk. * Added :prefix option to breadcrumb renderer. Credits to Rodrigo Manhães. * Added :ordered option for allowing list renderer to render an `
        ` rather than a `
          `. * Sinatra adapter no longer renders attributes with nil values as attributes with empty strings in the output, instead electing not to render the attribute at all. Thanks to revdan for pointing this out. ## 3.7.0 * Added new adapater for working with the Nanoc static site generation framework. * Fix issue #22 - last link in a breadcrumb trail may now be rendered as static text insted by supplying :static_leaf => true as an option * Allow breadcrumbs to be provided with link id and classes by supplying `:allow_classes_and_ids => true` as an option ## 3.6.0 * Added linkless items functionality - the `url` parameter is now optional, items which aren't links will be rendered within a 'span' element rather than an 'a' element. `options` remain optional (defaults to an empty Hash). `options` may be provided without providing a `url` (detected by checking if the `url` parameter is a Hash or otherwise). ## 3.5.1 * Fixed specs related to testing name_generator functionality - stub the name_generator method rather than calling it to ensure subsequent tests aren't affected. ## 3.5.0 * Added (configurable) "simple-navigation-active-leaf" class to last selected element and elements that have :highlights_on return true. Thanks to Frank Schumacher (thenoseman). ## 3.4.2 * Improve Gemfile dependencies with :development and :rails groups. ## 3.4.1 * Rerelease using ruby-1.8.7 rather than ruby-1.9.2 in order that the rubygems.org gemspec is generated in a compatible fashion. ## 3.4.0 * Added Gemfile for easier development with Bundler. Thanks to Josep Jaume. * modified :highlights_on option to accept a :subpath option (as well as Proc and Regexp forms). This can be used to automatically highlight an item even for items within a subpath. Thanks to Josep Jaume. ## 3.3.4 * modified :highlights_on option to accept a Proc (as well as the existing Regexp form). This can be used to provide specific highlighting conditions inline. Thanks to superlou for sparking the idea for the concept. ## 3.3.3 * Bugfix in Adapters::Sinatra#current_url? (compares unencoded URIs). Thanks to Matthew Gast. ## 3.3.2 * The patch listed in 3.3.1 somehow did not make it into the gem... sorry. Re-releasing... ## 3.3.1 * bugfix in sinatra adapter. Use Rack::Request#scheme instead of `Rack::Request#protocol`. Credits to Matthew Gast. ## 3.3.0 * add a new method `active_navigation_item_key` which returns the symbol for the currently selected navigation item in a similar way to `active_navigation_item_name` does for the name (useful for CSS class styling for eg.) * open up the helper API to provide `active_navigation_item` and `active_navigation_item_container` methods to make it easy to access the items/containers should it be necessary (came for free with the above refactoring) * isolate the apply_defaults and load_config private methods from `ActionController` mixin leakage by refactoring to module class instance methods * addition of test coverage for the added helpers within helpers_spec.rb * inclusion of new helpers within the rails adapter and minor refactoring to DRY up the helper_method invocations * addition of test coverage for the newly included helpers * Credits to Mark J. Titorenko for all the changes in this release! Thanks. ## 3.2.0 * Added Renderer::Text for rendering selected navigation items without markup (useful for dynamic page titles). Credits to Tim Cowlishaw. * Added ability to add custom markup around item names specifying a `name_generator` in the config file. Thanks to Jack Dempsey. ## 3.1.1 * `Item#selected_by_url?` now strips anchors from the item's url before comparing it with the current request's url. Credits to opengovernment. ## 3.1.0 * added new helper method `active_navigation_item_name` to render the name of the currently active item ## 3.0.2 * `dom_id` and `dom_class` can now be set as option in the item's definition (useful for dynamic menu items). ## 3.0.1 * allow controller instance variables named @template for rails3 apps. Credits to cmartyn. * added possibility to specify and item's URL as a block which is evaulated after the :if and :unless conditions have been checked. Credits to Nicholas Firth-McCoy. * upgraded to rspec 2.0.0 * fixed cgi error in sinatra adapter. Credits to Jack Dempsey. ## 3.0.0 * added ability to specify dynamic items using an array of hashes. Credits to Anshul Khandelwal for input and discussion. * added ability to specify attributes for the generated link-tag in list renderer (up to now the attributes have been applied to the li-tag). Credits to Anthony Navarre for input and discussion. ## 3.0.0.beta2 * moving code for initializing plugin in sinatra to separate gem ## 3.0.0.beta1 * moving deprecated rails controller methods (navigation, current_navigation) to separate file 'rails_controller_methods'. Deprecations removed. File can be required explicitly if controller methods should be still available. * decoupling from Rails. Introducing the concept of adapters to work with several frameworks. * tested with Rails 3.0.0 * adding support for Sinatra and Padrino frameworks. * cherry picking active_support stuff instead of requiring the whole bunch (tested with active_support >= 2.3.2 and 3.0.0) * created public sample project which includes demo for Rails2, Rails3, Sinatra and Padrino (will be available on github soon) * better src file organization (adapters/core/rendering folders) ## 2.7.3 * initializing SimpleNavigation.config_file_path with empty array (was `nil` before). Allows for adding paths before gem has been initialized. ## 2.7.2 * added ability to have more than one config_file_path (useful if simple-navigation is used as a part of another gem/plugin). Credits to Luke Imhoff. ## 2.7.1 * added SimpleNavigation.request and SimpleNavigation.request_uri as abstraction for getting request_uri (rails2/rails3) * use request.fullpath instead of request.request_uri for Rails3. Credits to Ben Langfeld. ## 2.7.0 * added new option :highlights_on to item definition in config-file. Specify a regexp which is matched against the current_uri to determine if an item is active or not. Replaces explicit highlighting in controllers. * deprecated explicit highlighting in the controllers. ## 2.6.0 * added rendering option 'skip_if_empty' to Renderer::List to avoid rendering of empty ul-tags * added breadcrumbs renderer incl. specs. A big thanks to Markus Schirp. * added ability to register a renderer / specify your renderer as symbol in render_navigation * renderer can be specified in render_navigation. Credits to Andi Bade from Galaxy Cats. ## 2.5.4 * bugfix: SimpleNavigation.config_file? without params does not check for `_navigation.rb` file anymore. Credits to Markus Schirp. ## 2.5.3 * removed deprecated railtie_name from simple_navigation/railtie. Credits to Markus Schirp. ## 2.5.2 * added Rails3 generator for navigation_config.rb. Thanks to Josep Jaume Rey. ## 2.5.1 * set template correctly for Rails3 (brings auto highlighting to life again). Credits to Josep Jaume Rey. ## 2.5.0 * added new renderer Renderer::Links to simply render the navigation as links inside a div. * also make item.name html_safe (in order you have html_code in the item's name). Thanks again, Johan Svensson. ## 2.4.2 * Rails 3.0.0.beta2 compatibility * Renderer::List --> make content of ul-tag html_safe for rails 3.0.0.beta2 (due to rails3 XSS protection). Credits to Johan Svensson and Disha Albaqui. * updated copyright * reduced visibility of 'sn_set_navigation' to protected ## 2.4.1 * removing depencency to rails. It installs the newest rails, even if a matching version is present. why is that? ## 2.4.0 * added Rails3 compatibility * added Jeweler::Gemcutter Tasks to Rakefile ## 2.2.3 * changed error handling in config-file. Do not ignore errors in config-file anymore. * only load config-file if it is present. Needed when directly providing items in render_navigation. ## 2.2.2 * added lib/simple-navigation.rb to allow 'require simple-navigation' or 'config.gem "simple-navigation"' ## 2.2.1 * Corrected URL to API-Doc on rubyforge in README ## 2.2.0 * Allow Ranges for :level option. Credits to Ying Tsen Hong. * Changing the API of `Helpers#render_navigation`. Now supports Ranges for `:level` option and :expand_all to render all levels as expanded. Old Api is still supported, but deprecated. * Deprecated `render_all_levels` in config-file. ## 2.1.0 * included Ben Marini's commit which allows individual id-generators. Thanks Ben! * added ability to specify navigation items through items_provider. This is useful for generating the navigation dynamically (e.g. from database) * items can now even be passed directly into render_navigation method. ## 2.0.1 * fixed handling of a non-existent explicit navigation item for a navigation context ## 2.0.0 * added auto_highlight feature. Active navigation is determined by comparing urls, no need to explicitly set it in the controllers anymore. Thanks to Jack Dempsey and Florian Hanke for the support on this. * added ability to create multi-level navigations (not just limited to primary and secondary navigation). Thanks again to Jack Dempsey for the motivation ;-) * simplified the process to explicitly set the navigation in the controller (where needed) - only deepest level has to be specified * made auto_highlight feature configurable both on global and item_container's level * config file is now evaluated in template if ever possible (not in controller anymore) ## 1.4.2 * explicitly loading all source files when requiring 'simple_navigation'. ## 1.4.0 * added the capability to have several navigation-contexts * doc-fix ## 1.3.1 * now compliant with ruby 1.9.1 (thanks to Gernot Kogler for the feedback) ## 1.3.0 * `render_all_levels` option allows to render all subnavigation independent from the active primary navigation ('full open tree'). Userful for javascript menus. Thanks to Richard Hulse. * ability to turn off automatic generation of dom_ids for the list items (autogenerate_item_ids). Credits again to Richard Hulse. * ability to specify dom_class for primary and secondary lists. Thanks Richard! ## 1.2.2 * renderers now have access to request_forgery_protection stuff (this allows delete-links as navigation-items) ## 1.2.1 * changed way to include render_*-helper_methods into view (including them into Controller and declaring them as helper_methods instead of adding whole module as Helper). this seems to be more reliable under certain conditions. Credits to Gernot Kogler. ## 1.2.0 * added capability to add conditions to navigation-items (`primary.item key, name, url, :if => Proc.new {current_user.admin?}`) ## 1.1.2 * Bugfix: config now gets evaluated on every render_navigation call. Credits to Joël Azémar. * Config file gets reloaded on every render_navigation call in development mode. Only load config file on server start in production mode. ## 1.1.1 * Change plugin into a GemPlugin simple-navigation-4.0.3/README.md0000644000004100000410000000354512513767261016474 0ustar www-datawww-data# Simple Navigation [![Gem Version](https://badge.fury.io/rb/simple-navigation.png)](http://badge.fury.io/rb/simple-navigation) [![Build Status](https://secure.travis-ci.org/codeplant/simple-navigation.png?branch=master)](http://travis-ci.org/codeplant/simple-navigation) [![Code Climate](https://codeclimate.com/github/codeplant/simple-navigation.png)](https://codeclimate.com/github/codeplant/simple-navigation) [![Coverage Status](https://coveralls.io/repos/codeplant/simple-navigation/badge.png)](https://coveralls.io/r/codeplant/simple-navigation) Simple Navigation is a ruby library for creating navigations (with multiple levels) for your Rails 2, Rails 3, Rails 4, Sinatra or Padrino applications. It runs with all ruby versions (including ruby 2.x). ## Documentation For the complete documentation, take a look at the [project's wiki](http://wiki.github.com/codeplant/simple-navigation). ## RDoc You can consult the project's RDoc on [RubyDoc.info](http://rubydoc.info/github/codeplant/simple-navigation/frames). If you need to generate the RDoc files locally, check out the repository and simply call the `rake rdoc` in the project's folder. ## Online Demo You can try simple-navigation with the [online demo](http://simple-navigation-demo.codeplant.ch). The source code of this online demo is [available on Github](http://github.com/codeplant/simple-navigation-demo). ## Feedback and Questions Don't hesitate to come talk on the [project's group](http://groups.google.com/group/simple-navigation). ## Contributing 1. Fork it (https://github.com/codeplant/simple-navigation/fork) 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create new Pull Request ## License Copyright (c) 2014 codeplant GmbH, released under the MIT license simple-navigation-4.0.3/Guardfile0000644000004100000410000000040412513767261017031 0ustar www-datawww-dataguard :rspec, all_after_pass: true, failed_mode: :none do watch(%r{^spec/.+_spec\.rb$}) watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } watch(%r{^spec/fake_app/.+\.rb$}) { 'spec/integration' } watch('spec/spec_helper.rb') { 'spec' } end